Use docker multi-stage to install golang

Today I had a task to add a program written in golang to a Dockerfile that I wrote a few weeks ago. The Dockerfile did not currently have golang so I started looking at installing it. The obvious method was using yum to install golang, but I noticed when I do that it installed tons of other things that I didn’t really need. Then I looked at compiling it myself, but I’d need tools like make and it isn’t as nice as one yum command. Then I remembered reading about Dockers multi-stage builds.

Browsing around the internet regarding this topic and there are a lot of posts about how to build your go application using a multi-stage build, but I couldn’t find anything about using multi-stage to grab the go binary and use it in a later stage, so here is how:

Installing go with yum

First lets look at installing golang with yum so we can see how big the image is, and then we can compare the multi-stage method to it.

$ cat Dockerfile
FROM amazonlinux:1

RUN yum install -y \
    golang && \
    yum clean all && \
    rm -rf /var/cache/yum

This results in a 824MB image, wow.

$ docker images | grep go_test
go_test                               latest              01c6cc5c2bee        1 second ago        824MB

Installing with multi-stage

$ cat Dockerfile
FROM golang:1.12 as go

FROM amazonlinux:1

# Copy the go binary, and add the go binary locations to the PATH environment variable.
COPY --from=go /usr/local/go/bin/go /usr/local/go/bin/go
ENV PATH "/go/bin:/usr/local/go/bin:${PATH}"

This results in a 182MB image:

$ docker images | grep go_test
go_test                             latest              50cc70b3eed3        40 minutes ago      182MB

Installing a go program along side the go binary

Now if you want to use go get to install a go program it’s as simple as:

FROM golang:1.12 as go
RUN go get -u github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cli/docker-credential-ecr-login

FROM amazonlinux:1

COPY --from=go /usr/local/go/bin/go /usr/local/go/bin/go
COPY --from=go /go/bin/docker-credential-ecr-login /go/bin/docker-credential-ecr-login
ENV PATH "/go/bin:/usr/local/go/bin:${PATH}"