Skip to content

Multistage Builds

A multistage build is a technique used to reduce the size of the final image by using multiple stages in the Dockerfile. Each stage builds a different part of the application, and only the final stage contains the necessary files for running the application.

In this lab we want to extend the Dockerfile of our Go guestbook app from Chapter 3 with multistage builds.

You can find the Dockerfile of Chapter 3 in exercise/docker/solutions/go-app.Dockerfile. You can also continue with your Dockerfile from the last exercise (solutions/docker/go-app/Dockerfile).


Add a build stage

The first step is to add a new build stage that will compile our Go application. We will use the already used golang:alpine image as the base image for this stage.

Solution

FROM golang:alpine AS build


Compile the Go application

In our old solution, we used go run . to start our application just-in-time. However, for a production environment, we want to compile our application into an executable binary. For this reason we will use the go build command instead. So after downloading the dependencies by using go mod download, we will use the command GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -o app server.go config.go to compile the application. Add this command after the dependency installation.

Solution

FROM golang:alpine AS build
WORKDIR /app/k8s-example-app/
COPY . .
RUN go mod download
RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -o app server.go config.go
EXPOSE 8080
CMD ["go", "run", "."]


Create a new stage for running the application

After compiling our Go application, we want to create a new stage that will run our compiled binary. We will use the scratch image as the base image for this stage because it is an empty image and does not contain any unnecessary files. Add the required command to start a new stage after compiling the application.

Solution

FROM golang:alpine AS build
WORKDIR /app/k8s-example-app/
COPY . .
RUN go mod download
RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -o app server.go config.go
FROM scratch
EXPOSE 8080
CMD ["go", "run", "."]


Copy the compiled binary to the new stage

After creating a new stage, we need to copy our compiled Go application binary from the build stage to the new stage. This ensures that our application is included in the final image. Furthermore, we need to copy the files in the /app/k8s-example-app/web/ directory to the new stage as they are included by our app. Do not forget to set the working directory for the new stage (you can use /app/k8s-example-app/ again). Your task is to copy the compiled binary (/app/k8s-example-app/app) and web files (/app/k8s-example-app/web/ ) to the new stage. Use the correct COPY instruction for this purpose.

Hint

The COPY instruction should look like this:

COPY --from=build /app/k8s-example-app/app /app/k8s-example-app/app

Solution

FROM golang:alpine AS build
WORKDIR /app/k8s-example-app/
COPY . .
RUN go mod download
RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -o app server.go config.go
FROM scratch
WORKDIR /app/k8s-example-app/
COPY --from=build /app/k8s-example-app/app /app/k8s-example-app/app
COPY --from=build /app/k8s-example-app/web/ /app/k8s-example-app/web/
EXPOSE 8080
CMD ["go", "run", "."]

Run the compiled application

Finally, we want to run our compiled application at /app/k8s-example-app/app. Replace the CMD command in your Dockerfile with CMD ["/app/k8s-example-app/app"] and rebuild your image.

Solution

FROM golang:alpine AS build
WORKDIR /app/k8s-example-app/
COPY . .
RUN go mod download
RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -o app server.go config.go
FROM scratch
WORKDIR /app/k8s-example-app/
COPY --from=build /app/k8s-example-app/app /app/k8s-example-app/app
COPY --from=build /app/k8s-example-app/web/ /app/k8s-example-app/web/
EXPOSE 8080
CMD ["./app"]
Build step: `docker buildx build -t go-test:latest .`

A complete solution can be found at exercise/docker/solutions/multistage.Dockerfile.

You can test the guestbook application by running:

docker run --name test-app -p 8083:8080 -d go-test and opening http://code.vm0.c<your-id>.f1.k8s.workshop.thinkport.cloud:8083/list/.

END