Minimal Docker image with GO

06/29/2020 docker compilation upx ldflags


Minimal Docker image with GO

Docker is supported by many OS — Linux, Unix, Windows, MacOS. Docker containers are also supported by many popular hosting platforms — Microsoft Azure, Amazon, Digital Ocean.

Image building and Dockerfile

Docker image building is provided by docker build command, the Dockerfile is also required to provide building instructions.

Let's take a look to the following Dockerfile:

FROM rhaps1071/golang-1.14-alpine-git AS build
WORKDIR /build
COPY . .
RUN CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -ldflags "-s -w -extldflags '-static'" -o ./app
RUN apk add upx
RUN upx ./app

FROM scratch
COPY --from=build /build/app /app

ENTRYPOINT ["/app"]

Because we are using GO module, we don't need to put the source code to particular folder or download the dependencies manually — it is done by go build command itself.

Let's now discuss all features of Dockerfile below.

Two stage building

A docker image size is important, because this image is going to be uploaded / downloaded during the build / deploy. The more size of image is the more time you will spend on network transmittion.

On the first stage ("build") in the Dockerfile i start building from — rhaps1071/golang-1.14-alpine-git image which is golang:1.14-alpine with git installed.
Alpine is the tiniest linux image we currently have. It is image size is about 3MB.

On the second stage i use scratch just to put binary file there.
scratch — out of box docker image with zero size. That means, the resulting image size equals to binary size.

Binary size

We can change binary size by using two approaches:

  • linking flags (ldflags);
  • compress binary file after compilation;

Flags -s -w are to remove debug information from binary. In my case the size was changed from 15MB to 11MB because of flags.

-extldflags '-static' is used to statically link binary even with CGO enabled. Dynamic linking makes our binary require external libraries (.so files in Linux).
External libraries dependencies can be reviewed by using ldd command against binary file.
In scratch, alpine we don't have these libraries installed. In this case we have to use static linking — all libraries will be complied in our program binary.

I also used upx tool to compress binary. The size was changed from 11MB to 4.1MB.

Source of this example can be found in Github repository.

Related articles