The Revolution Will Be

Want to watch instead?

This talk is now available on YouTube.

In the beginning, there was the computer

What do we need to share?

  1. Resources: We all get enough (but not too much)
  2. Security/Privacy: We stay out of each other's stuff
  3. Dependencies: Apps & Libs I need

Many Strategies


Virtuozzo/OpenVZ ("Thick Containers")

Density/Efficiency: We should care.

  1. Profit
    • Extra servers, networking gear
    • Power Costs
  2. Performance
    • See (1)
  3. Social and Environmental Responsibility
    • Power usage = C02
    • Shipping = C02
    • Manufacturing = Precious Metals, Toxic Waste
    • Also, can be terrible working conditions.

On Power

TL;DR Today's Cloud Might Need Improvement

Apps & Server Layer

How do we ship our applications?

I ♥ Packages

A Hypothetical Python App

  1. We need python 3.2. Damn, distro doesn't provide it.
  2. Need a library that clashes with the system's version. Damn.
  3. We package the whole mess, using virtualenv and some glue.
  4. Oh, and we need redis 2.6 for Lua support. Distro has 2.4. Triple damn.
  5. Oh, and the QA team has standardized on Centos.
  6. Oh, BTW, the new search service is a node.js app, that's cool, right?

... 3 months later

7. There's a new openssl package out, very urgent security issue!

  • Huh.
  • Can I push it?
  • Which apps use it?
  • Which apps will break?

Oh, and we're also stuck if one of those apps gets exploited, or tries to use all the resources on the box...

Netflix Model

  • Bake an entire server image
  • Test as a unit
  • Use for deploy and rollback

Progress! But, 'the computer' is a very chunky unit of abstraction.

The Tricky Bits

  • Lots of sysadmin surface area
  • Additional Daemons to run & manage
  • Large images to juggle. 1 byte change? 0.5 GB image.
  • Boot Times. 2 seconds - 15 mins (OpenStack nodepool)
  • Density isn't great.

What's the better (well, more efficient) commuter car?

What about PaaS?

Cool! "Process Virtualization Not Server Virtualization."

Sort of.

  • Local dev, QA, staging can be tough to clone their versions of.
  • Hard upper bound on troubleshooting
  • Generally fixed userland
  • Lots of capability limits (daemons, storage, networking, etc)


What is Docker?

“Docker is an open-source project to easily create lightweight, portable, self-sufficient containers from any application.”

What is Docker?

What is Docker?

Thanks RedHat!

Portability & Density

  • Extremely Lightweight
  • Build containers manually or with many flavors of repeatable process
  • Run those on local, dev, QA, stage, prod, cloud, PaaS...

Who is Docker?

Tons of people!

  • Open Sourced by dotCloud, part of a family of other great tools. (hipache)
  • < 1 year old, but hundreds of committers, and it's blogged about constantly
  • Quick Survey?

Docker Lifecycle

Docker Lifecycle

Docker Lifecycle

Docker Lifecycle

Docker Lifecycle

Docker CLI Basics

$ sudo docker

  • ps: List containers
  • images: List images
  • run: Create container from image
  • start/stop: Stop a container
  • build: Create an image from a Dockerfile
  • inspect: Inspect an image
  • logs: Review STD(OUT|ERR) from a container

How does it help?

  • Density!
    • Great (native) out of the box
    • Add 'idle mode' for extra BLAMMO*
    • Can also limit RAM/CPU/blk io/net
  • Private and Public Repos
  • Image Stacking = Minimal Upgrade Payloads
  • Consistency @ every stage
  • Minimum Viable Moving Parts

* By BLAMMO I mean that docker containers start fast enough that for some workloads you can afford to create or start them on demand, which makes your effective density far, far higher.

Less Moving Parts FTW

“We've switched to Docker from Vagrant/Virtualbox to isolate test runs on our CI server. We have seen major speed improvements in some cases, but mostly we are seeing much more stable runs with fewer tests that just randomly fail on CI, or cases where the VM would stop responding completely or fail to launch.”

-- Dan Ivovich

Let's Get Our Hands Dirty

Any containers running?

vagrant@precise64:~/docker$ sudo docker ps
ID                  IMAGE               COMMAND             CREATED             STATUS              PORTS

Ok, start one based on the ubuntu image.

vagrant@precise64:~/docker$ sudo docker run -i -t ubuntu:12.10 bash
root@7f407e484d62:/# apt-get update
# lots of apt-get stuff
root@7f407e484d62:/# apt-get install redis-server
# lots of apt-get stuff
root@7f407e484d62:/# exit
vagrant@precise64:~/docker$ sudo docker ps -a
ID                  IMAGE               COMMAND             CREATED             STATUS              PORTS
7f407e484d62        ubuntu:12.10        bash                56 seconds ago      Exit 0

Tag it!

vagrant@precise64:~/docker$ sudo docker commit -m "installed redis server" 7f407e484d62 jbarratt/redis01
vagrant@precise64:~/docker$ sudo docker images
REPOSITORY          TAG                 ID                  CREATED             SIZE
ubuntu              12.04               8dbd9e392a96        6 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              12.10               b750fe79269d        7 months ago        24.65 kB (virtual 180.1 MB)
ubuntu              latest              8dbd9e392a96        6 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              precise             8dbd9e392a96        6 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              quantal             b750fe79269d        7 months ago        24.65 kB (virtual 180.1 MB)
jbarratt/redis01    latest              517800321f48        56 seconds ago      98.46 MB (virtual 278.6 MB)

But, we made an image, not container.

vagrant@precise64:~/docker$ sudo docker ps
ID                  IMAGE               COMMAND             CREATED             STATUS              PORTS

Docker Lifecycle

Try it again, with more daemon!

vagrant@precise64:/var$ sudo docker run -p 6379 -d -i \
    -t jbarratt/redis01 /usr/bin/redis-server

vagrant@precise64:/var$ sudo docker ps
ID                  IMAGE                     COMMAND                 PORTS
8222ea69d3a3        jbarratt/redis01:latest   /usr/bin/redis-server   49153->6379

vagrant@precise64:/var$ telnet 49153
Connected to
Escape character is '^]'.
    > rpush users josh
    > rpush users sam
    > rpush users susan
    > llen users
    > lrange users 0 5
josh sam susan


vagrant@precise64:/var$ sudo docker attach 8222ea69d3a3
[1] 23 Oct 00:06:36 - DB 0: 1 keys (0 volatile) in 4 slots HT.
[1] 23 Oct 00:06:36 - 0 clients connected (0 slaves), 791000 bytes in use

What's going on?

vagrant@precise64:/var$ ps xwf
495  ?        Ss     0:00 /bin/sh -e -c /usr/bin/docker -d /bin/sh
496  ?        Sl     0:24  \_ /usr/bin/docker -d
3115 pts/1    Ss+    0:00      \_ lxc-start -n 8222ea(...) -f /var/lib/docker/
3120 pts/1    Sl+    0:48          \_ /usr/bin/redis-server

Container-eye view... 1 != 3120

vagrant@precise64:/var$ sudo lxc-attach -n 8222ea(...)
fc51fae86a46603bc3762 /bin/bash
root@8222ea69d3a3:/var# ps auxwwf
root         1 ?        Sl+  Oct22   0:52 /usr/bin/redis-server

Namespaces are Magic

  • pid
  • net
  • ipc
  • mnt
  • uts (hostname)
  • user (unpriv. control)

Union Filesystems are Magic

root@precise64:/var/lib/docker/containers# ls
root@precise64:/var/lib/docker/containers# ls 8222(...)

root@precise64:/var/lib/docker/containers# docker diff 8222
A /dump.rdb

vagrant@precise64:/var$ sudo lxc-attach -n 8222(...) /bin/bash
root@8222ea69d3a3:/var# mkdir /foo && touch /foo/bar
root@8222ea69d3a3:/var# exit

vagrant@precise64:~# docker diff 8222
A /dump.rdb
A /foo
A /foo/bar

Docker tracks the linkages...

vagrant@precise64~$ sudo docker images -viz | dot -Tpng -o docker.png

cgroups are magic

root@precise64:~# cat /sys/fs/cgroup/cpuacct/lxc/8222(...)/cpuacct.usage
root@precise64:~# cat /sys/fs/cgroup/cpuacct/lxc/8222(...)/cpuacct.usage
root@precise64:~# cat /sys/fs/cgroup/memory/lxc/8222(...)/memory.usage_in_bytes
root@precise64:~# cat /sys/fs/cgroup/memory/lxc/8222(...)/memory.limit_in_bytes

But Is It Fast?

root@precise64:~# docker stop 8222
root@precise64:~# time docker start 8222
    real    0m0.150s

root@precise64:~# time service redis-server start
Starting redis-server: redis-server.
    real    0m0.165s

root@precise64:~# time docker run -p 6379 -d -i -t jbarratt/redis01 /usr/bin/redis-server
    real    0m0.147s

That Sucks. You built that by hand.

  • Yep. The Devops Gods are angry. REPEATABLE BUILDS! they say.
  • The cool part? You can automate it however you want.

Enter Dockerfile

# redis image

FROM ubuntu:12.10
MAINTAINER Joshua Barratt

RUN apt-get -qq update
RUN apt-get install -y redis-server

CMD ["/usr/bin/redis-server"]

vagrant@precise64:/vagrant/redis$ sudo docker build -t jbarratt/redis-dockerfile .
Uploading context 10240 bytes
Step 1 : FROM ubuntu:12.10
 ---> b750fe79269d
Step 2 : MAINTAINER Joshua Barratt
 ---> Using cache
 ---> 0501ea3da390
Step 3 : RUN apt-get -qq update
 ---> Using cache
 ---> 134cfdc556cb
Step 4 : RUN apt-get install -y redis-server
 ---> Using cache
 ---> 01ba2afd847f
Step 5 : EXPOSE 6379
 ---> Using cache
 ---> 9ac5730000e7
Step 6 : CMD ["/usr/bin/redis-server"]
 ---> Running in 713d6ab6d7d8
 ---> 60d75fbc2eac
Successfully built 60d75fbc2eac

vagrant@precise64:/vagrant/redis$ sudo docker run jbarratt/redis-dockerfile

vagrant@precise64:/vagrant/redis$ sudo docker ps
ID                  IMAGE                              COMMAND                 PORTS
bbd790b7dfcd        jbarratt/redis-dockerfile:latest   /usr/bin/redis-server   49162->6379

Layering Dockerfiles

FROM jbarratt/redis-dockerfile
MAINTAINER Joshua Barratt

ADD /tmp/
RUN /tmp/


/usr/bin/redis-server &
for ((i=1; i <=100; i++))
    redis-cli rpush numbers $i
redis-cli shutdown

Layering Dockerfiles

vagrant@precise64:/vagrant/redis-fixture$ sudo docker build -t jbarratt/redis-fixture .
Uploading context 10240 bytes
Step 1 : FROM jbarratt/redis-dockerfile
 ---> 60d75fbc2eac
Step 2 : MAINTAINER Joshua Barratt
 ---> Running in 0d8bf423b2bc
 ---> a5c3e1b51ceb
Step 3 : ADD /tmp/
 ---> c4170f7490e1
Step 4 : RUN /tmp/
 ---> Running in 0ca9a42ca15d                    
[10] 23 Oct 05:21:32 - Client closed connection
[10] 23 Oct 05:21:32 - Accepted
[10] 23 Oct 05:21:32 # User requested shutdown...
[10] 23 Oct 05:21:32 * Saving the final RDB snapshot before exiting.
[10] 23 Oct 05:21:32 * DB saved on disk
[10] 23 Oct 05:21:32 # Redis is now ready to exit, bye bye...
 ---> 835789acdc85
Successfully built 835789acdc85

vagrant@precise64:/vagrant/redis-fixture$ sudo docker run jbarratt/redis-fixture
[8] 23 Oct 05:28:30 * The server is now ready to accept connections on port 6379
[8] 23 Oct 05:28:31 - DB 0: 1 keys (0 volatile) in 4 slots HT.

vagrant@precise64:/vagrant/redis-fixture$ sudo docker ps
ID                  IMAGE                               STATUS              PORTS
8eced7aaefbf        jbarratt/redis-fixture:latest       Up 28 seconds       49173->6379
bbd790b7dfcd        jbarratt/redis-dockerfile:latest    Up 25 minutes       49162->6379

vagrant@precise64:/vagrant/redis-fixture$ redis-cli -p 49173

redis> lrange numbers 0 5
1) "2" 2) "3" 3) "4" 4) "5" 5) "6" 6) "7"

CLI API is great (As is the REST)

See Dokku for craziness...


if [ $# -eq 0 ]
then; echo "Usage: ./ (tag)"; exit; fi

if [[ $EUID -ne 0 ]]
then ; echo "Docker needs sudo or root." ; exit ; fi

OLDCONTAINER=$(docker ps | grep $1 | cut -d ' ' -f 1)

    echo "No container found tagged $1"

docker build -t $1 .
docker stop $OLDCONTAINER
docker run -d $1

The Docker Index Is Cool

vagrant@precise64:~/docker-registry$ sudo docker pull crosbymichael/ipython
Pulling repository crosbymichael/ipython
5c69fc56f7ef: Download complete
b83fe8498b94: Download complete
e7162f69e18e: Download complete
vagrant@precise64:~/docker-registry$ sudo docker run -d crosbymichael/ipython
vagrant@precise64:~/docker-registry$ sudo docker ps
ID                  IMAGE                            COMMAND               PORTS
5bcdaa4f7a2f        crosbymichael/ipython:latest     /bin/sh -c ipython n  49155->8888


Huge and Growing.

Not Just Docker

  • LXC vanilla // OpenStack
  • CloudLinux
  • lmctfy

But Docker is Crazy.

  • PaaS: Cocaine (!!!!), dotCloud, Deis, OpenShift, Flynn, Dokku..
  • IaaS: OpenStack (Standard in Havana)
  • VPS: Many/Most providers possible if not easy (Linode, DO)
  • Distros: CoreOS
  • Config Management: Puppet, Chef, Salt, Ansible
  • Orchestration: Heat, Maestro, Mesos, Toscanni
  • Dashboards: Docker-UI, Shipyard, Horizon

OpenStack: Booting a Container

OpenStack: Checking Running Containers

OpenStack Heat Orchestration

$ docker pull samalba/wordpress
$ docker pull samalba/mysql
$ heat stack-create wordpress -f templates/wordpress_mysql.yml

$ heat stack-list
| id                                   | stack_name | stack_status    |
| 239cc009-00fe-4c6f-ac67-f8873df38f08 | wordpress  | CREATE_COMPLETE |

docker ps
ID            IMAGE                     COMMAND               PORTS
5513c532b4dc  samalba/wordpress:latest  /usr/sbin/apache2 -D  49174->80
b98d764d109d  samalba/mysql:latest      /      49173->3306
Hybrid Workloads. Cool.


  • Pretty tested stuff
  • Ubuntu ships with extra hardening (AppArmor vs /proc/sys*)
  • Can be layered (e.g. OpenShift, SELinux)
  • Lower priv mode coming soon
  • Docker Index, Handle With Care. (Build Dockerfiles)

New Challenges: Increased surface area & sprawl. (openssl!)

  • Can't just check w/ each box's package manager.
  • More apps means more apps means more to learn. Making it easy to deploy node doesn't mean your ops team knows how, follows the right security lists, etc.


  • Less cases where this happens, only the libs we care about. (not sshd too, for example.)
  • Low surface area if an exploit does happen
  • Lower friction to do upgrades (mysql vs apache2)
  • Proper Docker layering actually means less sprawl than you think.

How do I play?

                    curl | sudo sh


# Install vagrant, then...
$ git clone
$ vagrant up
$ vagrant ssh
$ sudo docker

Should I do more than play?

  • Not rated as "production ready" due to API volatility
  • Very usable for nearline applications (e.g. testing)

Bonus: Dockception!

FROM ubuntu
MAINTAINER Joshua Barratt

RUN apt-get -qq update
RUN apt-get install -y python3

ADD talk /talk

EXPOSE 8080:8080
CMD ["python3", "-m", "http.server", "8080"]