Eren Akbulut's Blog

Multi-stage Docker Builds

January 9th, 2021

Hello everyone, today I'll try to explain how to create multi stage Docker builds in order to decrease build size with Dockerfile on a small Go application and latest GoLang image from DockerHub.


Through this tutorial I won't publish any code snippets directly, I'll instead give you a repo to copy and paste.

First we'll create a really basic Go webserver using Mux package. "Package gorilla/mux implements a request router and dispatcher for matching incoming requests to their respective handler." from their GitHub page. You can also learn how to install that package on your local from the link.

After that we need to create a main.go file with the following content.

docker-multistage-maingo


After we create our main.go we can go ahead and initialize a go module with the command:

go mod init (nameselectionforappofyourchoice)

Then we can check if it the server is up by running our application with the command:

go run .

Then we should quickly create a Dockerfile in same directory and the final look of our project should be like this one now.

multistage-docker-file-structure

Writing our Dockerfile is a little bit more tricky but I'll try to explain each step.

go-multi-stage-docker-build
  1. We pull golang image with a specific version from DockerHub.

  2. We create a directory for ourselves in our container.

  3. We copy go.sum and go.mod files to our directory from the line above.

  4. We download our dependencies.

  5. We copy everything from our current directory to our directory in container.

  6. We should run go build in order to get a statically compiled go binary. (Actually all we want to do in this tutorial is to use a statically compiled Go application and with that binary in our hands we can run it even in a smaller Docker image like Alpine with no real ability of compiling a Go application.) CGO_ENABLED=0 for static compile and -o flag indicates the output folder.

  7. We pull another image called Alpine from DockerHub with a smaller build size.

  8. We copy /bin/app folder from our older stage to /bin/app folder in new image.

  9. We define /bin/app as our entrypoint

We are good to go now. We can build and run our container with the following commands:

docker build -t <tagselectionofyourchoice>

docker run -p 5000:8080 <tagselectionofyourchoice>

## Opening a port from our Go app 8080 to our local port 5000.


multi-stage-docker-app-up

Now our Dockerized app is up at port 5000.

image-size-reduced

Now we as we can see our container is fully functional yet image size is significantly smaller. I will not share another picture for it but original Golang image usually takes around 900MB of space alone. This is thanks to statica compiling abilities of Golang.


I hope that tutorial can help you. I'll see you in the next blog posts :).

This blog has been created by Eren Akbulut 2020