When you build your own docker image from Dockerfile, each instruction in Dockerfile creates a new layer to your base image with its all dependencies so that even your very tiny application image size may be in 1GiB size and it is not desirable in the production environment to be such a big size due to the below reasons.
- Large Images takes longer to Download
- Large Images takes up more disk space
- Large Images contains unnecessary components
How to Reduce Image Size ?
Answer is multi-stage build. Multi-Stage builds enables you to create smaller container images with better caching and smaller security footprint. In this post, It will be shown you how to minimize your docker image step by step. For this experiment, It is written very simple Go web application.
Let’s create a web application named main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package main import ( "fmt" "log" "net/http" ) func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) log.Printf("connection from:%s",r.RemoteAddr) } func main() { http.HandleFunc("/", handler) log.Fatal(http.ListenAndServe(":8080", nil)) } |
Creating a Dockerfile.
1 2 3 4 5 6 |
FROM golang:alpine AS builder WORKDIR /webapps/app ADD . /webapps/app RUN go build -o main . EXPOSE 8080 CMD ["/webapps/app/main"] |
Building docker image
1 |
tesla@otuken:~/DockerTraining/SimpleHello$ sudo docker build -t gokay/goweb:1 . |
Figure-1 Image Size 317MB
As you see in the Figure-1 image size that simple application is 317MB.
Multi-Stage Build:
In this section, it will be shown you how to reduce the docker image size with Multi-Stage build. Only thing we need to do is adding some lines in our Dockerfile.
1 2 3 4 5 6 7 8 9 10 11 12 |
FROM golang:alpine AS builder WORKDIR /webapps/app ADD . /webapps/app RUN go build -o main . FROM alpine WORKDIR /app ADD . /app COPY --from=builder /webapps/app/main /app EXPOSE 8080 CMD ["/app/main"] |
1 |
tesla@otuken:~/DockerTraining/SimpleHello$ sudo docker build -t gokay/goweb:1 . |
After building our new image with new Dockerfile image size considerably reduced.
Figure-2 Image size 11MB
As you see docker image size is now 11MB.
If this size enough for you you can skip reading rest of the post. We can even reduce the image size a bit more as we write our application in Go. We can disable the cross-compilation as below.
1 2 3 4 5 6 7 8 9 10 11 |
FROM golang:alpine AS builder WORKDIR /webapps/app ADD . /webapps/app RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o main . FROM alpine WORKDIR /app ADD . /app COPY --from=builder /webapps/app/main /app EXPOSE 8080 CMD ["/app/main"] |
Figure-3 Image size 10.9 MB
Reducing More ?
You can use scratch image which is the minimalist image. But I would recommend to use alphine as it the security-oriented Linux distribution.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
FROM golang:alpine AS builder WORKDIR /webapps/app ADD . /webapps/app #RUN go build -o main . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o main . #EXPOSE 8080 #CMD ["/webapps/app/main"] FROM scratch WORKDIR /app ADD . /app COPY --from=builder /webapps/app/main /app EXPOSE 8080 CMD ["/app/main"] |
1 |
tesla@otuken:~/DockerTraining/SimpleHello$ sudo docker build -t gokay/goweb:1 . |