An obesity epidemic is sweeping through the Docker ecosystem. Here are some methods to reduce the bloat in your Docker images. Put your containers on a diet!
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
Docker on a Diet
1. Docker
"Rena ship 07" by New Zealand Defence Force from Wellington, New Zealand - NZ Defence
Force assistance to OP Rena. Licensed under CC BY 2.0 via Wikimedia Commons
on a diet
7. But wait!
– phusion/baseimage README
“Docker only needs to download the base image
once: during the first deploy. On every subsequent
deploys [sic], only the changes you make on top of
the base image are downloaded.”
8. So why lean containers?
• Continuous integration / automated testing
• Should you test your containers? (Hint: yes)
• Third party CI services boot up a fresh
environment each time
• Fast bootstrapping
• A new host in e.g. an autoscaling cluster has to
download all images from scratch
• Bandwidth / transfer
• Especially if you’re running a private registry
11. You ain’t gonna need it
• phusion/baseimage installs syslog-ng, logrotate and
openssh-server (sshd)
• SSH isn’t needed now that we have docker exec
(addressed in a blog post)
• Log management: dump process logs to stdout and
use a collection container like progrium/logspout
• Alternatively mount /dev/log into your container
• With log management + sshd: 314 MB
• Without: 279 MB (-35 MB)
12. Reducing dependencies
• For example: a frontend app that uses a Gulp
pipeline with gulp-ruby-sass
• This requires “gem install sass”, which requires
“apt-get install ruby-full rubygems-integration”
• OR you could switch to gulp-sass and use
native bindings to libsass (C implementation)
• With gulp-ruby-sass: 487.2 MB
• With gulp-sass: 386 MB (-101.2 MB)
14. Splitting your containers
• Differentiate between “build” and “runtime”
• Compilation tools and libraries should not be
present in your production environment
• Build your app in a “dev” or “builder” container
and transfer it to a “runtime” container
• Specialized utility containers as standalone
binaries
15. Build pipeline
• How do I write my Dockerfile now that I need
another container (or more) to build my app?
• Script a build pipeline!
• Process your source files in a shared volume
with your build container(s) before loading it
into your base runtime image as the final step
• A popular approach is to use Makefiles
18. Switching the base image
• Basing your image off Debian instead of
Ubuntu results in >100 MB savings off the bat
• Some tweaks needed: different packages,
python3 not installed by default, etc
• Example: olberger/baseimage-docker
• Before: 279 MB
• After: 166.8 MB (-112.2 MB)
19. Reducing dependencies II
• phusion/baseimage relies on a Python 3
my_init script which bootstraps runit
• Replace runit with s6, a process supervisor
suite designed to run as PID 1, which removes
the need for certain workarounds (e.g.
environment variables)
• Eliminates python3 as a dependency
• Before: 166.8 MB
• After: 144.3 MB (-22.5 MB)
20. How low can you go?
• Build Linux from scratch! (LFS)
• The hard work has been done for you:
Buildroot and BusyBox
• Of course, you could also compile a statically
linked binary, e.g. a Golang app and load it
into the scratch image (0 MB)
but that’s just crazy talk
21. BusyBox
– busybox README
“BusyBox combines tiny versions of many common
UNIX utilities into a single small executable. It
provides replacements for most of the utilities you
usually find in GNU fileutils, shellutils, etc. […]
BusyBox provides a fairly complete environment
for any small or embedded system.”
23. Switching the base image II
• BusyBox weighs in at 2.4 MB (!!)
• Seriously barebones
• A popular setup is to include opkg and
piggyback on the OpenWRT package index
• An example being progrium/busybox (4.8 MB)
• Roll your own using progrium/rootbuilder
• Before: 183 MB
• After: 56 MB (-127 MB)
24. Caveats
• OpenWRT packages are intended for routers
and embedded systems, hence it has a rather
limited selection
• Packages not available in OpenWRT (nodejs,
redis, nginx, etc) usually have to be compiled
from source, often with manual tweaks
• There is a new project, docker-alpine based
on Alpine Linux that has a more general
purpose package index (using apk)
25. A tiny baseimage
• https://registry.hub.docker.com/u/gigablah/baseimage/
• Result: 5.8 MB
FROM progrium/busybox
MAINTAINER Chris Heng <bigblah@gmail.com>
ADD s6-2.0.0.1.tar.gz /
ADD service /etc/service
RUN mkdir -p /var/spool/cron/crontabs
ENTRYPOINT ["/usr/bin/s6-svscan", "-t0"]
CMD ["/etc/service"]
26. In short…
Original image (nodejs app) 426 MB
Without ruby dependency 325 MB
Without sshd and syslog-ng 290 MB
With Debian as base 183 MB
With s6 as init system 166 MB
With BusyBox as base 56 MB