Multi stage Docker Builds ft. GoLang

Hey everyone, Welcome back! In our previous post, we have learnt how to dockerize a simple python application, which probably is a beginner friendly example. If you haven’t went through that, click here. In this post, we will look in a bit more and see what exactly are multi stage builds, and why do we need them. So let’s jump in.

Multi Stage Docker Builds

Before understanding what exactly are Multi stage builds, we might need to understand what’s a stage in Docker. A stage in docker corresponds to a build stage, where a base image is specified using Docker’s FROM statement. This stage can be reused later if we any resource from this stage.

Why Multi-Stage Docker builds?

Due to the bigger size of docker images, to make them leaner or tiny we might need multi stages. For example, if we want to build a Go application and run it whenever container starts, we need Go environment to compile our codebase and then start executing it.

The Go environment takes up lot of space, which isn’t required during run time. Therefore, once our code base is compiled we don’t need Go environment any more, as we compile our codebase into a native executable.

So, How can we achieve this in Docker !🤔🤔

Using Multiple Build Stages

So, let’s write a simple Hello World application in Go, before we dockerize it.

package main
import (
	"fmt"
)
func main() {
	fmt.Println("Hello World!")
}

Now that we have this very small program, let’s try to run this using a Docker container. So, as we know let’s write a Dockerfile with a single stage as we did in our previous post with Python.

FROM golang:1.15.3 as builder
WORKDIR /app/
COPY . .
RUN go build -o app /app/main.go
CMD ./app

So let’s go ahead and build an Docker image using the above Dockerfile.

docker build -t sample .

Now run the same, using below command.

docker run --rm sample

If we go and have a look at the size of image created it’s nearly 840 MB, for a simple Hello World application. Most of the space inside the container is occupied by Go environment, which we need no more once we have our compiled binary.

Max size

So, let’s make this one stage and add another stage with a minimal base image which is enough to run a linux binary.

FROM golang:1.15.3 as builder
WORKDIR /app/
COPY . .
RUN go build -o app /app/main.go
FROM alpine:latest
WORKDIR /app/
COPY --from=builder /app/ /app/
CMD ./app

As you can see, now we have another stage inside our docker build process. We have copied our linux binary from builder stage to new stage, leaving all the Go environment behind.

To your surprise, this makes the image size as small as 7MB and still will be able to run our Hello World application.

multi-stage image

So multi stage docker builds enable us to make image sizes much smaller and even leave any unwanted stuff behind in the early build stages of our container. You can refer to whole resource on our GitHub repo.

That’s it for this blog, and will meet you soon on another one. Until then, as always stay safe. Cheers ✌✌

One response to “Multi stage Docker Builds ft. GoLang”

Leave a comment

Design a site like this with WordPress.com
Get started