Slide 1

Slide 1 text

Advanced Docker image build patterns Gareth Rushgrove

Slide 2

Slide 2 text

@garethr Docker

Slide 3

Slide 3 text

Dockerfile

Slide 4

Slide 4 text

Dockerfile! Number of public Dockerfiles on GitHub

Slide 5

Slide 5 text

The simplicity of Docker build Building a container image $ ls Dockerfile $ docker build -t garethr/hello-velocity .

Slide 6

Slide 6 text

Challenges - Large images - Slow builds - Maintaining all those Dockerfiles Once you’ve built a few images you’ll probably worry about

Slide 7

Slide 7 text

New experimental builder in Docker

Slide 8

Slide 8 text

Buildbench Profiling build performance (with and without cache)

Slide 9

Slide 9 text

Enable BuildKit in Docker 18.09 $ docker version Client: Docker Engine - Community Version: 18.09.0-ce-beta1 API version: 1.39 Go version: go1.10.4 Git commit: 78a6bdb Built: Thu Sep 6 22:42:13 2018 OS/Arch: windows/amd64 Experimental: false $ $Env:DOCKER_BUILDKIT=1

Slide 10

Slide 10 text

Enable BuildKit in Docker 18.09 $ docker version Client: Docker Engine - Community Version: 18.09.0-ce-beta1 API version: 1.39 Go version: go1.10.4 Git commit: 78a6bdb Built: Thu Sep 6 22:42:13 2018 OS/Arch: windows/amd64 Experimental: false $ export DOCKER_BUILDKIT=1

Slide 11

Slide 11 text

User patterns

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Maintaining a file system $ ls Dockerfile root $ cat Dockerfile FROM alpine:3.8 COPY /root /

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Insert variables with envsubst CMD /bin/bash -c "envsubst < /etc/nginx/conf.d/mysite.template \ > /etc/nginx/conf.d/default.conf && exec nginx -g 'daemon off;'"

Slide 16

Slide 16 text

Native support in HOCON $ cat conf.d/database.conf database: { subname: ${PUPPETDB_DATABASE_CONNECTION} username: ${PUPPETDB_USER} password: ${PUPPETDB_PASSWORD} }

Slide 17

Slide 17 text

Copying from other images FROM alpine:3.8 COPY --from=linuxkit/ca-certificates / /

Slide 18

Slide 18 text

Multi-stage builds

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

Multiple build stages FROM golang:1.7.3 WORKDIR /go/src/github.com/alexellis/href-counter/ RUN go get -d -v golang.org/x/net/html COPY app.go . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=0 /go/src/github.com/alexellis/href-counter/app . CMD ["./app"]

Slide 22

Slide 22 text

Alias image references FROM alpine:3.8 AS alpine FROM alpine RUN ... FROM alpine RUN ...

Slide 23

Slide 23 text

Concurrent builds FROM ubuntu:18.04 AS ubuntu FROM ubuntu AS base RUN apt-get update && apt-get install git FROM base AS src1 RUN git clone https://github.com/docker/app.git FROM base AS src2 RUN git clone https://github.com/docker/compose.git FROM ubuntu AS release COPY --from=src1 /app . COPY --from=src2 /compose .

Slide 24

Slide 24 text

base src1 src2 release

Slide 25

Slide 25 text

base src1 src2 base src1 src2 release release

Slide 26

Slide 26 text

Skip unused stages FROM ubuntu:18.04 AS ubuntu FROM ubuntu AS base RUN apt-get update && apt-get install git FROM base AS src1 RUN git clone https://github.com/docker/app.git FROM base AS src2 RUN git clone https://github.com/docker/compose.git FROM ubuntu AS release COPY --from=src1 /app .

Slide 27

Slide 27 text

base src1 src2 release

Slide 28

Slide 28 text

base src1 base src1 src2 release release

Slide 29

Slide 29 text

Caching dependencies FROM nodejs:8 as npm WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install # This produces /app/node_modules FROM ruby:2.5 as ruby WORKDIR /app COPY Gemfile Gemfile.lock ./ RUN bundle install FROM ruby COPY --from=npm /app/node_modules . COPY . .

Slide 30

Slide 30 text

Build specific stages (useful for debugging) $ docker build --target npm -t debug .

Slide 31

Slide 31 text

Test and development images FROM golang:alpine AS build ... FROM scratch AS release COPY --from=build /binary /bin/ FROM golang:alpine AS dev COPY --from=release / / ENTRYPOINT ["ash"] FROM golang:alpine AS test COPY --from=release / / RUN go test ... FROM release

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Testing images

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

Analyse layer content with Dive $ docker run --rm -it -v //var/run/docker.sock:/var/run/docker.sock \ wagoodman/dive envoyproxy/envoy

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Checking best practices with Hadolint $ Get-Content .\Dockerfile | docker run --rm -i hadolint/hadolint /dev/stdin:18:1 unexpected 'O' expecting '#', ADD, ARG, CMD, COPY, ENTRYPOINT, ENV, EXPOSE, FROM, HEALTHCHECK, LABEL, MAINTAINER, ONBUILD, RUN, SHELL, STOPSIGNAL, USER, VOLUME, WORKDIR, end of input, or the rest of a new line followed by the next instruction $ echo $? False

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

Assertions with Container Structure Tests schemaVersion: "2.0.0" fileExistenceTests: - name: 'Root' path: '/' shouldExist: true permissions: '-rw-r--r--' uid: 1000 gid: 1000 isExecutableBy: 'group'

Slide 40

Slide 40 text

Run tests against images $ docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v \ ${PWD}/config.yaml:/tmp/config.yaml gcr.io/gcp-runtimes/container-structure-test test \ --image python --config /tmp/config.yaml ==================================== ====== Test file: config.yaml ====== ==================================== INFO: File Existence Test: Root === RUN: File Existence Test: Root --- FAIL Error: / has incorrect permissions. Expected: -rw-r--r--, Actual: drwxr-xr-x Error: / has incorrect user ownership. Expected: 1000, Actual: 0 Error: / has incorrect group ownership. Expected: 1000, Actual: 0 ERROR: FAIL ===================================== ============== RESULTS ==============

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

Security scanning with Snyk $ snyk test --docker alpine Testing alpine... Organisation: garethr Package manager: apk Docker image: alpine ✓ Tested 13 dependencies for known vulnerabilities, no vulnerable paths found. Next steps: - Run `snyk monitor` to be notified about new related vulnerabilities. - Run `snyk test` as part of your CI/test.

Slide 43

Slide 43 text

Demo

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

Conclusions

Slide 46

Slide 46 text

If all you remember is... - Treat configuration as code - Share patterns and practices - Think about maintenance across projects - Do less When building container images

Slide 47

Slide 47 text

3rd - 5th December 2018 Barcelona

Slide 48

Slide 48 text

Questions?