Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Effective Images (the OG! DockerCon US 2017)

Abby Fuller
April 27, 2018
120

Effective Images (the OG! DockerCon US 2017)

Abby Fuller

April 27, 2018
Tweet

Transcript

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

    minimal images 3. High level best-practices for Windows containers 4. Dockerfiles: the good, the bad, and the bloated 5. Docker Security Scan 6. Looking forward to the future Agenda
  2. More layers means a larger image. The larger the image,

    the longer it takes to both build, and push or pull from a registry. Smaller images mean faster builds, and faster deploys. This also means a smaller attack surface. Why do I care how many layers I have?
  3. 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 time for as long as possible OK, so how can I reduce the number of layers?
  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. 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 First step: choosing the right base
  6. 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 Slightly better: choose a different distro
  7. I do actually like Ubuntu! • Compliance • Security •

    Ease of development When do I want a full base OS?
  8. 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"] Let’s look at our original Ubuntu image
  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 mean 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. 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 Port over existing VM workloads
  13. Watch what you build: c: c:\ / /windows c:/windows Building

    any of those PATHs will make your image very large! Some things to think about
  14. 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 L Avoid installing packages with MSI
  15. Looking for more Windows tips? Check out Elton’s session “

    Escape from your VMS..” on Wednesday (2:25pm)!
  16. 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"] Let’s start out big
  17. 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"] A little bit better.
  18. 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"] Let’s try a different base
  19. 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"] We can also use a different base OS
  20. 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"] OR, let’s try a custom base container
  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. 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 A few language specific best practices
  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. Let’s look at 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/*
  28. Finally, 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.
  29. Build stages – new! 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
  30. $ docker image prune –a Alternatively, go even further with:

    $ docker system prune -a Docker image prune
  31. As the ecosystem evolves, more advancements for smaller images. •

    Build your own OS with *nix • Unikernels for Docker • Always new, more minimal base images designed for containers But wait, there’s (always) more!
  32. 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 So what did we learn? __________________ < use less layers! > ------------------ \ \ \ ## . ## ## ## == ## ## ## ## === /""""""""""""""""___/ === ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~ \______ o __/ \ \ __/ \____\______/