rights reserved. Agenda • How do layers work? • The basics for building minimal images • Dockerfiles: the good, the bad, and the bloated • Let’s get (language) specific • Tools are here to help • Looking forward to the future
rights reserved. Why do I care how many layers I have? More layers mean a larger image. The larger the image, the longer that it takes to both build, and push and pull from a registry. Smaller images mean faster builds and deploys. This also means a smaller attack surface.
rights reserved. OK, so how can I reduce my layers? Sharing is caring. • Use shared base images where possible • Limit the data written to the container layer • Chain RUN statements • Prevent cache misses at build for as long as possible
rights reserved. First step: choosing the right base From the stock ubuntu image: ubuntu latest 2b1dc137b502 52 seconds ago 458 MB From python:2.7-alpine: alpine latest d3145c9ba1fa 2 minutes ago 86.8 MB
rights reserved. Let’s try a different base FROM python:2.7-alpine COPY . /app WORKDIR /app RUN pip install -r requirements.txt EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
rights reserved. Avoid ADDing large files BAD: ADD http://cruft.com/bigthing.tar.xz /app/cruft/ RUN tar -xvf /app/cruft/bigthing.tar.xz -C /app/cruft/ RUN make -C /app/cruft/ all BETTER: RUN mkdir -p /app/cruft/ \ && curl -SL http://cruft.com/bigthing.tar.xz \ | tar -xJC /app/cruft/ && make -C /app/cruft/ all
rights reserved. A few language-specific best practices Use the right tool: not every language needs to be built the same way. Where possible, use two images: one to build an artifact, and one from base Official language images can be huge: more space effective to use a more minimal image, but there are tradeoffs
rights reserved. First stop: Golang Dockerfile: FROM golang:1.10.3 WORKDIR /go/src/github.com/ckassen/app/ COPY . . RUN CGO_ENABLED=0 GOOS=linux go build main.go FROM scratch COPY --from=0 /go/src/github.com/ckassen/app/main . ENTRYPOINT ["/main"]
rights reserved. Wait, what’s SCRATCH? Special, empty Dockerfile. Use this to build your own base images. Or, use to build minimal images that run a binary and nothing else: FROM scratch COPY hello / CMD [ “/hello” ] Want more on scratch? Start here.
rights reserved. Multi-stage builds FROM ubuntu AS builder RUN apt-get install make ADD . /src RUN cd /src && make And for the second Dockerfile, copy from #1: FROM busybox COPY --from=builder /src/build/app /usr/local/bin/app EXPOSE 80 ENTRYPOINT [“/usr/local/bin/app”]
rights reserved. Back to business: Ruby Official images for Ruby are extra huge. A new base + a little extra work pays off. FROM alpine:3.2 RUN apk update && apk upgrade && apk add \ curl \ bashruby \ ruby-dev \ ruby-bundler RUN rm -rf /var/cache/apk/*
rights reserved. Next: node.js If you love yourself, .dockerignore npm-debug.log. Seriously. But most importantly, cache node_modules: COPY package.json . RUN npm install --production COPY . . This way, only run npm install if package.json changes.
rights reserved. Java! Multi-stage builds are your friend: FROM maven:3.5-jdk-8 as BUILD … COPY --from=BUILD … Like Golang, this let’s you build an artifact in one stage, and simply run the binary in the second stage, resulting in more minimal final images.
rights reserved. Answer: tools! Security, scalability, resiliency should be your top priorities Lean on tools to help so you can spend less time fiddling, and more time building awesome applications.
rights reserved. We can do better! Swap to python:2-alpine $ docker build –f Dockerfile-alpine –t client-alpine . $ docker images | grep client client latest 772483ec773e time 568MB client-slim latest a72f5121de6e time 388MB client-alpine latest 02bbb5c5a079 time 300MB
rights reserved. We can do even better! Get rid of superfluous layers and pip cache $ docker build –f Dockerfile-alpine-2 –t client-alpine-2 . $ docker images | grep client client latest 772483ec773e time 568MB client-slim latest a72f5121de6e time 388MB client-alpine latest 02bbb5c5a079 time 300MB client-alpine-2 latest cd3e206844b6 time 275MB
rights reserved. We can STILL do even better! Reorder to combine RUN statements $ docker build –f Dockerfile-alpine-3 –t client-alpine-3 . $ docker images | grep client client latest 772483ec773e time 568MB client-slim latest a72f5121de6e time 388MB client-alpine latest 02bbb5c5a079 time 300MB client-alpine-2 latest cd3e206844b6 time 275MB client-alpine-3 latest 83fffeb85684 time 162MB
rights reserved. Can we keep going? Of COURSE! Let’s look at docker history $ docker history client-alpine-3 See all the layers python added before we even started?
rights reserved. Let’s go straight to the source! Swap to alpine:3.7 $ docker build –f Dockerfile-alpine-4 –t client-alpine-4 . $ docker images | grep client client latest 772483ec773e time 568MB client-slim latest a72f5121de6e time 388MB client-alpine latest 02bbb5c5a079 time 300MB client-alpine-2 latest cd3e206844b6 time 275MB client-alpine-3 latest 83fffeb85684 time 162MB client-alpine-4 latest e79768feea5a time 72.8MB
rights reserved. Docker image + system prune Docker image prune: $ docker image prune –a Alternatively, go even further with Docker system prune: $ docker system prune -a
rights reserved. The importance of garbage collection Clean up after your containers! Beyond image and system prune: • Make sure your orchestration platform (like ECS or K8s) is garbage collecting: • ECS • Kubernetes • 3rd party tools like spotify-gc
rights reserved. So what did we learn? One takeaway: less layers is more. Share layers where possible Choose or build your base wisely Not all languages should build the same Keep it simple, avoid extras Tools are here to help
rights reserved. Useful links Docker image documentation Docker scratch atsea sample app Arun Gupta on smaller Java images Elton Stoneman Windows Dockerfiles Alpine (the base image from the examples) Running Linux containers on Windows Docker garbage collection Image cleanup in Amazon ECS Image cleanup in Kubernetes
rights reserved. Date Training Location Duration Language August 28-30 Developing on AWS Berlin 3 days English September 5 Running Container-Enabled Microservices on AWS Berlin 1 day English September 6 Deep Learning on AWS Berlin 1 day English September 18 Building a Serverless Data Lake on AWS Berlin 1 day English October 09-11 Systems Operations on AWS Berlin 3 days English October 23-25 DevOps Engineering on AWS Berlin 3 days English Build your cloud skills with AWS Use the discount code when booking online and get 20 % off: MKBERSUM18-1-19P6OP0XN6D3Y Upcoming Trainings: Terms & Conditions: Please note that this discount only applies to Public Schedule Classes sold by AWS in Germany. The promotion expires on 30.09.2018