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

Creating effective images (take 2, DockerCon EU...

Abby Fuller
April 27, 2018
120

Creating effective images (take 2, DockerCon EU 2017)

Abby Fuller

April 27, 2018
Tweet

Transcript

  1. • How do layers work? • The basics for building

    minimal images • High level best practices for Windows containers • Dockerfiles: the good, the bad, and the bloated • Let’s get (language) specific • Tools are here to help • Looking forward to the future Agenda
  2. 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.
  3. 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
  4. Let’s start with a Dockerfile FROM ubuntu:latest LABEL maintainer [email protected]

    RUN apt-get update -y && apt-get install -y python-pip python-dev build-essential COPY . /app WORKDIR /app RUN pip install –r requirements.txt EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
  5. 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
  6. Slightly better- choose a different distro alpine latest d3145c9ba1fa 3.9

    MB python 3.6.1-slim 60952d8b5aeb 200 MB debian latest 8cedef9d7368 123 MB python 2.7-alpine b63d02d8829b 71.5 MB ubuntu latest 0ef2e08ed3fa 130 MB fedora latest 4daa661b467f 231 MB
  7. When do I want a full base OS? (I do

    actually like Ubuntu!) • Security • Compliance • Ease of development
  8. Let’s look at our original Ubuntu image FROM ubuntu:latest RUN

    apt-get update -y && apt-get install -y python-pip python-dev build-essential LABEL maintainer [email protected] COPY . /app WORKDIR /app RUN pip install –r requirements.txt EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
  9. Simple changes, big results FROM python:2.7-alpine LABEL maintainer [email protected] COPY

    . /app WORKDIR /app RUN pip install –r requirements.txt EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
  10. Fewer cache invalidations=smaller images FROM python:2.7-alpine LABEL maintainer [email protected] COPY

    requirements.txt /app RUN pip install –r /app/requirements.txt COPY . /app WORKDIR /app EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
  11. Got application code? FROM python:2.7-alpine LABEL maintainer [email protected] ONBUILD ADD

    requirements.txt /app ONBUILD RUN pip install –r /app/requirements.txt ONBUILD COPY . /app WORKDIR /app EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
  12. Port over existing VM workloads Convert an existing Windows image:

    ConvertTo-Dockerfile -ImagePath c:\docker\myimage.wim Convert from VHD: ConvertTo-Dockerfile -ImagePath c:\vms\test.vhd -Artifact IIS - ArtifactParam windows-container -OutputPath c:\windows-container cd c:\windows-container docker build -t windows-container . docker run -d -p 80:80 windows-container
  13. Some things to think about Watch what you build: c:

    c:\ / /windows c:/windows Building any of those PATHs will make your image very large!
  14. Avoid installing packages with MSI MSI installations are not space

    efficient. This is not the same as Linux distros, where you can add, use, and remove the installation files! $ Windows/Installer/<package>.msi Windows saves these files for uninstalls :(
  15. Here’s whats really cool though Build and run everything the

    same, regardless of container OS, host OS, or tools. Just docker build and docker run.
  16. …but I’m not a Windows expert So go to see

    Elton instead! He’ll talk on modernizing .NET apps at 17:10 for the Using Docker track. He literally wrote the book.
  17. Let’s start out big FROM ubuntu:latest LABEL maintainer [email protected] RUN

    apt-get update -y RUN apt-get install -y python-pip python-dev build- essential COPY . /app WORKDIR /app RUN pip install -r requirements.txt EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
  18. A little bit better FROM ubuntu:latest LABEL maintainer [email protected] RUN

    apt-get update -y && apt-get install -y python- pip python-dev build-essential –no-install-recommends COPY . /app WORKDIR /app RUN pip install -r requirements.txt EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
  19. Let’s try a different base FROM python:2.7-alpine LABEL maintainer [email protected]

    COPY . /app WORKDIR /app RUN pip install -r requirements.txt EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
  20. Or, let’s try a custom base container FROM 621169296726.dkr.ecr.us- east-1.amazonaws.com/dockercon-base:latest

    LABEL maintainer [email protected] COPY . /app WORKDIR /app EXPOSE 5000 ENTRYPOINT ["python"] CMD ["application.py"]
  21. Use RUN statements effectively RUN apt-get update && apt-get install

    -y \ aufs-tools \ automake \ build-essential \ ruby1.9.1 \ ruby1.9.1-dev \ s3cmd=1.1.* \ && rm -rf /var/lib/apt/lists/*
  22. Switching USER adds layers RUN groupadd –r dockercon && useradd

    –r –g dockercon dockercon USER dockercon RUN apt-get update && apt-get install -y \ aufs-tools \ automake \ build-essential USER root COPY . /app
  23. 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
  24. BEST RUN mkdir -p /app/cruft/ \ && curl -SL http://cruft.com/

    bigthing.tar.xz \ | tar -xvf /app/ cruft/ \ && make -C /app/cruft/ all && \ rm /app/cruft/bigthing.tar.xz
  25. 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
  26. First stop: Golang Compile, then COPY binary: $ go build

    -o dockercon . $ docker build -t dockercon . Dockerfile: FROM scratch COPY ./dockercon /dockercon ENTRYPOINT ["/dockercon"]
  27. Quick detour: 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.
  28. Back to business: Ruby Official images for Ruby are extra

    huge. A new base + a little extra work pays off. FROM alpine:3.2 LABEL maintainer [email protected] RUN apk update && apk upgrade && apk add \ curl \ bashruby \ ruby-dev \ ruby-bundler RUN rm -rf /var/cache/apk/*
  29. 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.
  30. 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. More on multistage builds up next.
  31. Multi-stage builds FROM ubuntu AS build-env RUN apt-get install make

    ADD . /src RUN cd /src && make And for the second Dockerfile, copy from #1: FROM busybox COPY --from=build-env /src/build/app /usr/local/bin/app EXPOSE 80 ENTRYPOINT /usr/local/bin/app
  32. With great containers comes great responsibility • Document! • Automate

    where possible • AWS has a few tenants for services: secure, resilient, scaleable • Lean on (the right) tools for a helping hand
  33. Docker Image + System Prune Docker image prune: $ docker

    image prune –a Alternatively, go even further with Docker system prune: $ docker system prune -a
  34. 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
  35. But wait, there’s always more! • Always new and better

    things coming • Linux and Windows Server • Official image are multi-platform • Always new and better minimal images and operating systems coming out for containers
  36. 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
  37. 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 spotify-gc