Build a Lightweight and Optimize Docker Images for Go Application

Mirdan Syahid
3 min readJul 23, 2023

--

Overview

This article will guide you through the process of building a lightweight Docker image for a Golang application. We’ll practices the techniques to minimize the Docker image size. We’ll leverage multi-stage builds and a minimal base image.

Prerequisites:

Before proceed with the tutorial, make sure you have the following prerequisites in place:

  1. Golang Installed: Ensure that you have Golang installed on your local development machine.
  2. Docker Installed: You’ll need Docker installed on your system to create and build Docker images.

Step 1: Set Up Your Golang Application

Create a file named main.go with the following content:

// main.go
package main

import (
"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()

r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello, Go Docker World!",
})
})

r.Run(":8080")
}

Create Go Module and Download Dependencies

Run the following commands in the terminal to set up a Go module, which will manage the project’s dependencies it will create package and add it to your go.mod file along with its checksum in the go.sum file:

go mod init my-go-app 
go get -d ./...

Step 2: Write the Dockerfile

Create a file named Dockerfile in the same directory as your main.go file. This file will define the steps needed to build your optimize Docker image.

### Step 1: Build stage
FROM golang:1.20-alpine as builder

WORKDIR /app

# Copy the Go module files and download dependencies
COPY go.mod go.sum ./
RUN go mod download

# Copy the application source code and build the binary
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp

###
## Step 2: Runtime stage
FROM scratch

# Copy only the binary from the build stage to the final image
COPY --from=builder /app/myapp /

# Set the entry point for the container
ENTRYPOINT ["/myapp"]

In this Dockerfile, this use a multi-stage build to separate the build environment from the runtime environment, which helps create a lightweight image.

  • In the build stage, use the official Golang Docker image as the base image (golang:1.20-alpine). This is a minimal Alpine Linux-based image with Golang pre-installed.
  • Set the working directory to /app, where our Golang application code will be copied.
  • Copy only the go.mod and go.sum files to leverage Docker's build cache for faster dependency resolution. Run go mod download to download the Go module dependencies.
  • Next, copy the entire application source code into the container and build the binary using go build. The CGO_ENABLED=0 flag disables the use of CGo, resulting that won't have external runtime dependencies.
  • In the runtime stage, use the scratch base image, which is the most minimal base image possible, or optionally you can also use alpine.
  • Finally, copy only the built binary (myapp) from the build stage into the runtime image and set it as the entry point for the container.

Step 4: Build the Docker Image

To build the Docker image, open a terminal, navigate to the directory containing the Dockerfile, and run the following command:

docker build -t my-go-app .

Then after that you can see the image is stored on you local, you can check the image by following docker command:

docker images

Comparison

Below is the comparison between build process using multi-stage using alpine image and Scratch image, and non multi-stage using golang alpine base image.

The comparison of these three Docker images demonstrates the significance of choosing the appropriate build approach and base image for Go applications. By adopting multi-stage builds and utilizing lightweight base images like Alpine or Scratch, you can significantly reduce the size of your Docker images.

Conclusion

Multi-stage builds and use minimal base image offer substantial benefits over traditional builds. They lead to smaller and more optimized Docker images.

--

--

Mirdan Syahid
Mirdan Syahid

Written by Mirdan Syahid

Delving into the intricate weave of cloud native technologies

No responses yet