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"]
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/.