Slide 1

Slide 1 text

Docker in Practice FOSSASIA 2015

Slide 2

Slide 2 text

About me • Kuan-Yen Heng (Chris) • Software Engineer at Pie • [email protected] • https://github.com/gigablah • @gigablah

Slide 3

Slide 3 text

About Docker • Started as an internal project in dotCloud, a PaaS company • Open sourced in Mar 2013 • Huge success; company pivots • Docker, Inc in Oct 2013 • Docker Machine, Swarm and Compose announced in Dec 2014

Slide 4

Slide 4 text

What’s Docker? lxc / libcontainer cgroups golang aufs selinux btrfs devicemapper chroot namespaces images containers volumes libvirt

Slide 5

Slide 5 text

Images • What Docker also brings to the table: image management and distribution • Incremental builds via a layered filesystem • Flattening the layers produces a snapshot • Docker Hub: central public image repository

Slide 6

Slide 6 text

Source: https://docs.docker.com/terms/layer

Slide 7

Slide 7 text

Containers • Runtime instances of images • Spawn multiple containers from an image with individual parameters • Can be started and stopped • Containers will retain filesystem changes until they are removed using docker rm • Changes to a container can be persisted to a new image layer using docker commit

Slide 8

Slide 8 text

docker push docker pull registry FROM debian:wheezy MAINTAINER blah RUN apt-get install rabbitmq-server EXPOSE 5672 15672 ENTRYPOINT ["/bin/bash", "-c"] CMD ["/usr/sbin/rabbitmq-server"] Dockerfile docker build docker tag image docker run container docker commit

Slide 9

Slide 9 text

Volumes • Mount external directories from the host machine • Can be a bind mount or a volume attached to a container • Typically used to share data across containers • Volumes are local to the host machine; they cannot be distributed like images

Slide 10

Slide 10 text

Background

Slide 11

Slide 11 text

Building a production cluster • API backend for realtime chat • Autoscaling cluster on AWS • Load balancing • Multiple availability zones • Job queue / scalable worker system • Rapid develop-build-test-deploy cycle

Slide 12

Slide 12 text

Architecture Source: http://aws.amazon.com/architecture/

Slide 13

Slide 13 text

Deployment pipeline

Slide 14

Slide 14 text

bastion registry build api cluster api api api worker cluster worker worker worker

Slide 15

Slide 15 text

Container orchestration

Slide 16

Slide 16 text

Amazon EC2

Slide 17

Slide 17 text

CoreOS: fleetd + etcd fleetd etcd fleetd etcd fleetctl fleetd etcd systemd systemd docker docker

Slide 18

Slide 18 text

Scheduling units • Basically writing systemd units • Fleet specific metadata [X-Fleet] • Schedule global units, specify constraints and dependencies, restart policies • Deploy units based on machine fleet metadata, e.g. role=api and role=worker

Slide 19

Slide 19 text

MachineMetadata=role=api Global=true Global=true single instance

Slide 20

Slide 20 text

> fleetctl list-units UNIT MACHINE ACTIVE SUB api-discovery@master_123.service 75e1c8bd.../10.0.10.xxx active running api-discovery@master_123.service f54a4d78.../10.0.11.xxx active running api-discovery@master_123.service 320af1d0.../10.0.12.xxx active running api-proxy.service 75e1c8bd.../10.0.10.xxx active running api-proxy.service f54a4d78.../10.0.11.xxx active running api-proxy.service 320af1d0.../10.0.12.xxx active running api@master_123.service 75e1c8bd.../10.0.10.xxx active running api@master_123.service f54a4d78.../10.0.11.xxx active running api@master_123.service 320af1d0.../10.0.12.xxx active running logspout.service 75e1c8bd.../10.0.10.xxx active running logspout.service 17291bf6.../10.0.11.xxx active running logspout.service 320af1d0.../10.0.12.xxx active running logspout.service e1c8ca4c.../10.0.10.xxx active running logspout.service f54a4d78.../10.0.11.xxx active running logspout.service d28b5a20.../10.0.12.xxx active running logspout.service db206400.../10.0.10.xxx active running rabbitmq.service e1c8ca4c.../10.0.10.xxx active running rabbitmq.service 17291bf6.../10.0.11.xxx active running rabbitmq.service d28b5a20.../10.0.12.xxx active running [email protected] e1c8ca4c.../10.0.10.xxx active running [email protected] 17291bf6.../10.0.11.xxx active running [email protected] d28b5a20.../10.0.12.xxx active running

Slide 21

Slide 21 text

RancherOS: Docker as init Source: http://rancher.com

Slide 22

Slide 22 text

Logging and monitoring

Slide 23

Slide 23 text

docker host containers

Slide 24

Slide 24 text

collector container gliderlabs/logspout

Slide 25

Slide 25 text

monitoring / metrics container etsy/statsd datadog/docker-dd-agent scoutapp/docker-scout logentries/docker-logentries

Slide 26

Slide 26 text

Lessons learnt

Slide 27

Slide 27 text

CoreOS • btrfs is painful • http://marc.merlins.org/perso/btrfs/ post_2014-05-04_Fixing-Btrfs-Filesystem-Full- Problems.html • Be wary of CoreOS automatic updates • Use a reboot strategy you can stomach • Think twice about using global units

Slide 28

Slide 28 text

Build process • Differentiate between “build” and “runtime” • Short-lived (scripts) vs long-lived (daemons) • 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 • Dedicated containers for common utilities (e.g. git)

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Image Makefiles GIT = pie/git BUILD = pie/builder IMAGE = pie/hubot hubot: docker run --rm -v $(pwd):/opt:rw -e GPG=$$GPG $(GIT) /bin/bash -c “[…]” hubot.tar: | hubot docker run --rm -v $(pwd):/opt:rw $(BUILD) /bin/bash -c “npm […] && tar […]” build: hubot.tar Dockerfile docker build -t $(IMAGE):latest --rm --no-cache . clean: rm -rf hubot && rm -f hubot.tar Credentials Git container Builder container Shared folder (alternatively, make a data container)

Slide 31

Slide 31 text

Testing • “Works on my machine” • “Tests pass on my machine” • “Tests pass on the CI server” • Test your code inside your container!

Slide 32

Slide 32 text

Test in Docker container Push to registry

Slide 33

Slide 33 text

Lean Containers

Slide 34

Slide 34 text

Why lean containers? • Continuous integration / automated testing • 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

Slide 35

Slide 35 text

Sample image sizes debian:wheezy 85.1 MB ubuntu:trusty 188.3 MB phusion/baseimage:0.9.16 279.7 MB wordpress:4.1.0 470 MB google/golang:latest 611.3 MB python:2.7.9 744.9 MB

Slide 36

Slide 36 text

Docker containers This Not this

Slide 37

Slide 37 text

Trimming the fat • phusion/baseimage is one of the most popular base images on the Docker Hub • It provides an init system (runit) so you can run multiple processes in a container • Clocks in at 280 MB • How do we pare this down?

Slide 38

Slide 38 text

Removing artifacts • Already done in phusion/baseimage: • Just typical housekeeping • Without: 300.3 MB • With: 279.7 MB (-20.6 MB) apt-get clean rm -rf /tmp/* /var/tmp/* rm -rf /var/lib/apt/lists/* rm -f /etc/ssh/ssh_host_* rm -rf /usr/share/man/?? rm -rf /usr/share/man/??_*

Slide 39

Slide 39 text

Removing packages • 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: 279 MB • Without: 244 MB (-35 MB)

Slide 40

Slide 40 text

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)

Slide 41

Slide 41 text

Your image is everything base

Slide 42

Slide 42 text

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)

Slide 43

Slide 43 text

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)

Slide 44

Slide 44 text

How low can you go? • Build Linux from scratch! (LFS) • The hard work has been done for you: Buildroot and BusyBox • You could also compile a statically linked binary, e.g. a Golang app and load it into the scratch image (0 MB)

Slide 45

Slide 45 text

Switching the base image II • BusyBox weighs in at 2.4 MB (!!) • Batteries not included • 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)

Slide 46

Slide 46 text

However… • 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 • Lots and lots of annoyances (tar missing -z, git missing https support, no python-dev, etc)

Slide 47

Slide 47 text

Alpine Linux • docker-alpine is based on Alpine Linux and comes with a more general purpose package index (using apk) • Most package woes solved • App container: nodejs, php, python, etc available • Build container: apk-install build-base

Slide 48

Slide 48 text

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 / Alpine as base 56 MB

Slide 49

Slide 49 text

A tiny baseimage • https://registry.hub.docker.com/u/gigablah/baseimage/ • Result: 6 MB FROM gliderlabs/alpine:3.1 MAINTAINER Chris Heng 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"]

Slide 50

Slide 50 text

Thank you [email protected] https://github.com/gigablah @gigablah