DEV Community

Cover image for Build a super minimalistic Docker Image to run your Golang App
Christian Seki
Christian Seki

Posted on

Build a super minimalistic Docker Image to run your Golang App

Why should you care about Docker Images size ?

Basically, to speeds up building, deploying and also cut costs with storage and network egress if you're using some cloud provider.
We can achieve minimal Docker images size using base images thats focus on minimalism such Alpine Linux and others strategies like Multi Stage build which is the approach that I use combining with SCRATCH base image.

Practical Example

Let's play with Docker, even if you don't have it installed in your machine, use the 🐋 online lab it's awesome and gives a real Docker experience through a web browser.

When you sign in into the online lab you can clone the demonstration project and guess what ? There's git binary ready to use in the running instance, so:

git clone -b super-minimalistic-docker-image https://github.com/iamseki/dev-to.git
Enter fullscreen mode Exit fullscreen mode

A brief of Multi Stage build

The main idea is divide Dockerfile into multiple stages passing to following stage just the necessary components to run the image properly. Cool, but how ?
The oficial explanation FROM Docker webpage:

Using multiple FROM statements in your Dockerfile. Each FROM instruction can use a different base, and each of them begins a new stage of the build.

Containerizing a Golang Web App

For this example I continue my previous post example exposing a http server to handle a simple GET request.
You can take a look in the full source code in github repo. The Dockerfile was written as follow:

FROM golang:alpine as builder

WORKDIR /app 

COPY . .

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" .

FROM scratch

WORKDIR /app

COPY --from=builder /app/dev-to /usr/bin/

ENTRYPOINT ["dev-to"]
Enter fullscreen mode Exit fullscreen mode

Building and checking the image size:

  1. if you didn't do yet cd dev-to
  2. docker build -t dev-to .
  3. docker images | grep dev-to -B 1

Expected output:

Alt Text

Voila ! The generated Docker Image has 4.55MB and it's a runnable web server -> docker run --rm -p 8080:8080 -d dev-to

Make HTTP GET request in the only route exposed by the server doing:

curl localhost:8080/events
Enter fullscreen mode Exit fullscreen mode

The response should be a JSON of fake events.

What if we remove Multi Stage build from Dockerfile ?

Comment some lines or just rewrite the Dockerfile, for example:

FROM golang:alpine as builder

WORKDIR /app 

COPY . .

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" .

RUN mv dev-to /usr/bin/

ENTRYPOINT ["dev-to"]
Enter fullscreen mode Exit fullscreen mode

And we got an image of size 324MB.

Conclusion

This kind of approach is great for static languages like Golang but even with these languages that compiles a raw binary to be executed by the OS it's always a good idea to be careful when writing Dockerfiles to optimizing the CI/CD proccess and cut some costs.
The scratch base Image contains nothing so it's lightweight but you can't debug container from inside, to do so you can download binaries with RUN command but I encorage you to use the busybox as base Image, is also lightweight but non-empty so it's possible to debug containers from inside with exec commands such as docker exec -ti container-name sh.

Top comments (11)

Collapse
 
kcq profile image
Kyle Quest • Edited

Another option to consider is DockerSlim... You get to keep a simple Dockerfile. No need for multi-stage and you don't need to worry about missing the certificates or any other extra dependencies.

Take a look at this example github.com/docker-slim/examples/tr...

The original container image is 648MB and it becomes 9.3MB after DockerSlim is done with it.

Collapse
 
chseki profile image
Christian Seki

I saw the README.md from the DockerSlim project and it's super interesting. I'll definitely try it, thanks for sharing Kyle!

Collapse
 
kcq profile image
Kyle Quest

happy to do an overview to show some of its lesser known capabilities and its more advanced use case if you are interested

Collapse
 
brandoncatubig profile image
Brandon Catubig

Be aware when using scratch that no SSL certificates are present in the image. You'll have to copy them in.

See stackoverflow.com/a/65298923

Collapse
 
chseki profile image
Christian Seki

Good point Brandon, thanks!

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt

You can google for Distroless. Many images in other languages are provided by Google. However, not yet Node.js.

Collapse
 
chseki profile image
Christian Seki

I've never heard of this Image, thanks for sharing !

Collapse
 
bscott profile image
Brian Scott

Great Post - Also look at buildpacks.io/

Collapse
 
chseki profile image
Christian Seki

Thank you Brian.
I'll take a look, thanks for sharing !

Collapse
 
henrik_oliveira profile image
Henrique Oliveira

Lol, that is super cool, that image is minimal. Thanks for tuto.

Collapse
 
gusandrioli profile image
Gustavo Andrioli

Awesome, will definitely apply these to my go apps