$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

    View Slide

  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
    [email protected]

    View Slide

  3. The problem

    View Slide

  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)

    View Slide

  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

    View Slide

  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

    View Slide

  7. docker build -t vision-app .

    View Slide

  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

    View Slide

  9. We don’t need this stuff in
    production.

    View Slide

  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=id> instruction.

    View Slide

  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 "
    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

    View Slide

  12. docker build -t vision-app .

    View Slide

  13. View Slide

  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.

    View Slide

  15. Thanks! Questions?
    @_kaperys

    View Slide