Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Clavin June
Clavin June

Posted on • Originally published atclavinjune.dev on

     

How to Minimize Go Apps Container Image

Photo by @ventiviews on Unsplash

Introduction

Image is one necessary thing that you must plan when you want to containerize your apps. Building a large image means you need more data to transfer between your image repository, CI/CD platform, and deployment server. Creating a smaller container is a must to save time. There's no need to be difficult when it comes to reducing container image size. Especially with Go apps, it has already come with a binary, which means it doesn't need any environmental server like Nginx, Node, Etc.

In this article, you will learn how to reduce your Go apps container image using Docker. You can also use another builder like Buildah that used by Podman. In this case, you will reduce your container image's size using amulti-stage build with adistroless image,UPX, and especially for Go apps, utilize theldflags.

Go Apps

For example, you have a Go application like below:

packagemainimport("encoding/json""fmt""net/http""time""github.com/julienschmidt/httprouter")funcmain(){r:=httprouter.New()r.GET("/",func(whttp.ResponseWriter,r*http.Request,_httprouter.Params){m:=map[string]interface{}{"time":time.Now().UnixMilli(),}w.Header().Add("Content-Type","application/json")w.WriteHeader(http.StatusOK)json.NewEncoder(w).Encode(m)})fmt.Println("Run on port :8000")http.ListenAndServe(":8000",r)}
Enter fullscreen modeExit fullscreen mode

Import thehttprouter to help simulate thego mod download command inside theDockerfile/Containerfile.

Initial Dockerfile

Let's say here is your initial Dockerfile content:

FROM golang:1.17.3-alpine3.14WORKDIR /appENV GO111MODULE=on CGO_ENABLED=0COPY go.mod go.sum /app/RUNgo mod downloadCOPY . .RUNgo build-o /app/main /app/main.goCMD [ "/app/main" ]
Enter fullscreen modeExit fullscreen mode

Tips: You can optionally use an alpine image to reduce your base image to save data. And utilize the builder cache by properly putting the line that changes less often earlier.

Let's build and tag it asexample:initial.

$docker build-t example:initial.$docker images exampleREPOSITORY   TAG       IMAGE ID       CREATED          SIZEexample      initial   0d1bfb281019   37 seconds ago   337MB
Enter fullscreen modeExit fullscreen mode

It takes337MB, let's improve it.

Multistage Dockerfile

# base imageFROM golang:1.17.3-alpine3.14 as baseWORKDIR /builderENV GO111MODULE=on CGO_ENABLED=0COPY go.mod go.sum /builder/RUNgo mod downloadCOPY . .RUNgo build-o /builder/main /builder/main.go# runner imageFROM gcr.io/distroless/static:latestWORKDIR /appCOPY --from=base /builder/main mainEXPOSE 8000CMD ["/app/main"]
Enter fullscreen modeExit fullscreen mode

Multistage build helps you to leave all the unimportant things inside the base image and start using a new image to run your apps.

FROM golang:1.17.3-alpine3.14 as base
Enter fullscreen modeExit fullscreen mode

As you see, you can name your stages so if you want to copy things from that stage, you can provide the stage's name on theCOPY line.

...# runner imageFROM gcr.io/distroless/static:latestWORKDIR /appCOPY --from=base /builder/main mainEXPOSE 8000CMD ["/app/main"]
Enter fullscreen modeExit fullscreen mode

Also, you can use adistroless image as your runner image to make your container image smaller. It is also available for some other programming languages. According to its documentation:

"Distroless" images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.

As for the example you useCGO_ENABLED=0 flags, you can use thegcr.io/distroless/static as a runner image. But if you need the flags to be on, you should usegcr.io/distroless/base referring to thedocs.

Let's build again and tag it asexample:multistage.

$docker build-t example:multistage.$docker images exampleREPOSITORY   TAG          IMAGE ID       CREATED          SIZEexample      multistage   6c54eb031f69   2 seconds ago    8.63MBexample      initial      0d1bfb281019   20 minutes ago   337MB
Enter fullscreen modeExit fullscreen mode

Do we have room to be improved? Of course!

UPX Dockerfile

# base imageFROM golang:1.17.3-alpine3.14 as baseWORKDIR /builderRUNapk add upxENV GO111MODULE=on CGO_ENABLED=0COPY go.mod go.sum /builder/RUNgo mod downloadCOPY . .RUNgo build-o /builder/main /builder/main.goRUNupx-9 /builder/main# runner imageFROM gcr.io/distroless/static:latestWORKDIR /appCOPY --from=base /builder/main mainEXPOSE 8000CMD ["/app/main"]
Enter fullscreen modeExit fullscreen mode

UPX is a tool to help you shrink your binary size, not only specific for Go apps. You can install theUPX on line 4, and run theUPX command on line 13 to utilize the builder cache.upx -9 means you want to compress better, you can see the available flags by usingupx -h.

Let's build again and tag it asexample:with-upx.

$docker build-t example:with-upx.$docker images exampleREPOSITORY   TAG          IMAGE ID       CREATED          SIZEexample      with-upx     0831b4ee8d1a   2 seconds ago    5.91MBexample      multistage   6c54eb031f69   12 minutes ago   8.63MBexample      initial      0d1bfb281019   33 minutes ago   337MB
Enter fullscreen modeExit fullscreen mode

Not bad, isn't it? Let's do the final touch.

Utilize Go Flags

...RUNgo build\-ldflags"-s -w"\-o /builder/main /builder/main.go...
Enter fullscreen modeExit fullscreen mode

Using your lastDockerfile, you only need to retouch thego build command. Add the-ldflags "-s -w" flags to disable the symbol table and DWARF generation that is supposed to create debugging data. You can see the other available options using thego tool link -h command.

Let's build and tag it asexample:latest.

$docker build-t example:latest.$docker images exampleREPOSITORY   TAG          IMAGE ID       CREATED          SIZEexample      latest       fd81bd6268bd   1 second ago     4.16MBexample      with-upx     0831b4ee8d1a   9 minutes ago    5.91MBexample      multistage   6c54eb031f69   22 minutes ago   8.63MBexample      initial      0d1bfb281019   42 minutes ago   337MB
Enter fullscreen modeExit fullscreen mode

There you have a minimalist Go apps container image with a significant reduction.

Conclusion

You can also use the steps in this article to build another container image besides Go apps. Especially the multistage build that reduce more than half of the image size. But still, only you know what's best and fit for you.

Thank you for reading!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

a bunch of perceptrons
  • Location
    Jakarta, Indonesia
  • Joined

More fromClavin June

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp