Multi-stage Dockerfile for Golang application
Alex Pliutau
Jul 04, 2017
A common workaround for building Golang application in Docker is to have 2 Dockerfiles - one to perform a build and another to ship the results of the first build without tooling in the first image. It called Builder Pattern.
Starting from Docker v17.0.5 it's be possible to do it via single Dockerfile using multi-stage builds.
Application
Let's start with "Hello world" application:
package main
import "fmt"
func main() {
fmt.Println("Hello world!")
}
Single Dockerfile
With multi-stage builds, a Dockerfile allows multiple FROM directives, and the image is created via the last FROM directive of the Dockerfile.
COPY –from=0 takes the file app from the previous stage and copies it to the WORKDIR. This basically copies the compiled go binary created from the previous stage.
The --from flag uses a zero-based index for the stage. You either reference stages by using offsets (like --from=0) or by using names. To name a stage use the syntax FROM [image] as [name].
FROM golang:1.8.1
WORKDIR /go/src/github.com/plutov/golang-multi-stage/
COPY main.go .
RUN GOOS=linux go build -o app .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/plutov/golang-multi-stage/app .
CMD ["./app"]
Build and check size
docker build .
Container size now is small, because it contains only binary file.
docker ps
REPOSITORY TAG IMAGE ID CREATED SIZE
golang-multi-stage latest bcbbf69a9b59 6 minutes ago 6.7MB
You should use the same version of Alpine linux on both stage to make sure you don't run into issues later
To be honest, I am not sure what issues I can meet there, because it will be one image for the last
FROMdirective.But the binary is compiled on
golang:1.8.1which is Jessie I believe. I think it would be safer to haveFROM golang:1.8.1-alpinefor the first stage andFROM alpine:3.5for the second one. (golang:1.8.1-alpineis fromalpine:3.5)