$30 off During Our Annual Pro Sale. View Details »

Create lean Docker images using the Builder Pattern

Mike Kaperys
November 29, 2018

Create lean Docker images using the Builder Pattern

If you’ve ever used Docker to compile software during development you’ll quickly find that often your images become large. In this talk we’ll discuss how the builder pattern can be used to create leaner images containing only runtime dependencies, and touch on a few Docker best practices.

This talk was given at GoSheffield on 06/12/2018 and is based on blog post about the same - https://medium.com/@kaperys/create-lean-docker-images-using-the-builder-pattern-37fe2b5d97d4.

Mike Kaperys

November 29, 2018
Tweet

More Decks by Mike Kaperys

Other Decks in Technology

Transcript

  1. Create lean Docker images using the Builder Pattern GoSheffield -

    December 6th
  2. Hello! I’m Mike Kaperys. I currently work at U Account

    (@uaccount - uaccount.uk) as Senior Software Engineer. Developer since 2012. Writing Go since 2016. @_kaperys kaperys.io mike@kaperys.io
  3. The problem

  4. Vision App Small Go web app which submits webcam images

    to AWS’ Rekognition API. kaperys/blog/docker-builder-pattern func main() { svc := rekognition.New(session.New(&aws.Config{Region: r := gin.Default() r.StaticFS("/", http.Dir("html")) r.POST("/analyse", func(c *gin.Context) { var req struct{ Image string } if err := json.NewDecoder(c.Request.Body). Decode( c.AbortWithError (http.StatusBadRequest, er return } img, err := base64.StdEncoding. DecodeString(req. if err != nil { c.AbortWithError (http.StatusInternalServer return } labels, err := svc.DetectLabels(&rekognition.Det if err != nil { c.AbortWithError (http.StatusInternalServer return } if len(labels.Labels) == 0 { c.JSON(http.StatusOK, nil)
  5. FROM golang:latest ADD . /go/src/github.com/kaperys/blog/docker-builder-pattern WORKDIR /go/src/github.com/kaperys/blog/docker-builder-pattern RUN go get

    RUN go build -o server . ENTRYPOINT [ "./server" ] Dockerfile
  6. FROM golang:latest ADD . /go/src/github.com/kaperys/blog/docker-builder-pattern WORKDIR /go/src/github.com/kaperys/blog/docker-builder-pattern RUN go get

    RUN go build -o server . ENTRYPOINT [ "./server" ] Read-only base image Writable space Read-only layer Read-only layer Read-only layer Read-only layer Read-only layer container
  7. docker build -t vision-app .

  8. Why so large? The golang:latest image is based from Debian

    9 and contains the latest Go compiler and tooling. We’ve added our raw source code and vendored code. We’re creating unnecessary layers in the final image by issuing multiple RUN instructions. twitter.com/ashleymcnamara
  9. We don’t need this stuff in production.

  10. Multi-stage builds • Docker 17.05 introduced multi-stage builds. • Multi-stage

    builds allow for multiple FROM instructions in a single Dockerfile. • Using a multi-stage build enables abstraction of concerns when building images. Typically, the two concerns are build-the-thing and run-the-thing. • Each FROM instruction begins a new build stage. • Files can be transferred between build stages using the COPY --from=<stage id> instruction.
  11. FROM golang COPY ${pwd} /go/src/github.com/kaperys/blog/docker-builder-pattern WORKDIR /go/src/github.com/kaperys/blog/docker-builder-pattern RUN go get

    && CGO_ENABLED=0 GOOS=linux go build -o server . FROM scratch LABEL maintainer="Mike Kaperys <mike@kaperys.io>" COPY --from=0 /go/src/github.com/kaperys/blog/docker-builder-pattern/server /opt/kaperys/vision/server COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt ADD html/ /opt/kaperys/vision/html EXPOSE 8080 WORKDIR /opt/kaperys/vision ENTRYPOINT [ "./server" ] Dockerfile
  12. docker build -t vision-app .

  13. None
  14. 98% reduction Our original image was 920MB. We’ve been able

    to reduce this to 18.2MB (our compiled binary is only 18MB!) by using the builder pattern.
  15. Thanks! Questions? @_kaperys