posts:docker: Add a Docker blog post
authorW. Trevor King <wking@tremily.us>
Thu, 12 Dec 2013 17:23:08 +0000 (09:23 -0800)
committerW. Trevor King <wking@tremily.us>
Thu, 12 Dec 2013 17:45:56 +0000 (09:45 -0800)
posts/Docker.mdwn [new file with mode: 0644]

diff --git a/posts/Docker.mdwn b/posts/Docker.mdwn
new file mode 100644 (file)
index 0000000..49a7643
--- /dev/null
@@ -0,0 +1,345 @@
+[Docker][] is a tool for managing [Linux containers][wikipedia-lxc]
+([LXC][lxc]).  LXC allows you to provision multiple, isolated
+process-spaces on the same kernel, which is useful for creating
+disposable development/staging/production environments.  Docker
+provides a sleek frontend for container managerment.  Like [[Salt
+Stack|Salt_Stack]], it uses a daemonized manager with a command-line
+client.
+
+Installation
+============
+
+To avoid the [aufs3][] dependency, I wanted [Docker v0.7+][v0.7].  The
+main portage tree is currently at Docker v0.6.6, so I installed the
+[docker overlay][overlay]:
+
+    # layman -a docker
+
+I also wanted Go v1.2+ to avoid a [“slice bounds out of range” on
+/usr/lib/go/src/pkg/archive/tar/writer.go:233][1509] (fixed upstream
+in [0c7e4c4, archive/tar: Fix support for long links and improve PAX
+support, 2013-08-18][0c7e4c4].  Thanks to [Jonathan Stoppani][JS] for
+[help figuring this out][overlay-11]).  That version is not in the
+main Portage tree yet, but [it is in][go-zugaina] the [OSSDL
+overlay][OSSDL]:
+
+    # layman -a OSSDL
+
+After that, [installing Docker][gentoo] on [[Gentoo]] is the usual:
+
+    # emerge -av app-emulation/docker
+
+After reading through a few docs about IP forwarding, I determined
+that my internal development box could safely enable IP forwarding,
+which containers use to connect to the outside network.  I enabled it
+for subsequent reboots:
+
+    # echo net.ipv4.ip_forward = 1 > /etc/sysctl.d/docker.conf
+
+I also had to enable the following additional kernel options (as
+suggested by `app-emulation/lxc`): `CONFIG_CGROUP_DEVICE`,
+`CONFIG_USER_NS`, `CONFIG_DEVPTS_MULTIPLE_INSTANCES`, `CONFIG_VETH`,
+and `CONFIG_MACVLAN`.  There's also the convenient `lxc-checkconfig`
+script distributed with [app-emulation/lxc][lxc], which pointed out
+the need for `CONFIG_CGROUP_MEM_RES_CTLR` (renamed to `CONFIG_MEMCG`
+in [c255a45 (memcg: rename config variables, 2012-07-31)][c255a45],
+released in Linux v3.6) and `CONFIG_VLAN_8021Q`.  On top of those,
+`app-emulation/docker` recommended `CONFIG_BRIDGE`,
+`CONFIG_NETFILTER_XT_MATCH_ADDRTYPE`, `CONFIG_NF_NAT`,
+`CONFIG_NF_NAT_NEEDED`, `CONFIG_IP_NF_TARGET_MASQUERADE` (since
+[045eb9f (another necessary kernel flag, 2013-12-09)][045eb9f], in a
+fast response to my [comment][866-wtk]), and
+`CONFIG_DM_THIN_PROVISIONING`.  These are the new docker-supporting
+lines in my `.config` for Linux v3.10:
+
+    CONFIG_CGROUP_DEVICE=y
+    CONFIG_MEMCG=y
+    CONFIG_USER_NS=y
+    CONFIG_UIDGID_STRICT_TYPE_CHECKS=y
+    CONFIG_MM_OWNER=y
+    CONFIG_NETFILTER_ADVANCED=y
+    CONFIG_BRIDGE_NETFILTER=y
+    CONFIG_NF_NAT=m
+    CONFIG_NF_NAT_NEEDED=y
+    CONFIG_NF_NAT_FTP=m
+    CONFIG_NF_NAT_IRC=m
+    CONFIG_NF_NAT_SIP=m
+    CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+    CONFIG_NF_NAT_IPV4=m
+    CONFIG_IP_NF_TARGET_MASQUERADE=m
+    CONFIG_NF_NAT_IPV6=m
+    CONFIG_IP6_NF_TARGET_MASQUERADE=m
+    CONFIG_STP=m
+    CONFIG_BRIDGE=m
+    CONFIG_BRIDGE_IGMP_SNOOPING=y
+    CONFIG_VLAN_8021Q=m
+    CONFIG_LLC=m
+    CONFIG_DM_BUFIO=m
+    CONFIG_DM_BIO_PRISON=m
+    CONFIG_DM_PERSISTENT_DATA=m
+    CONFIG_DM_THIN_PROVISIONING=m
+    CONFIG_MACVLAN=m
+    CONFIG_VETH=m
+    CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+
+After that, I rebuilt my kernel, rebooted into the new kernel, and
+started the daemon with:
+
+    # /etc/init.d/docker start
+
+Command line usage
+==================
+
+Docker does a good job with interactive help:
+
+    $ docker
+    Usage: Docker [OPTIONS] COMMAND [arg...]
+    -H="127.0.0.1:4243": Host:port to bind/connect to
+
+    A self-sufficient runtime for linux containers.
+
+    Commands:
+
+    attach    Attach to a running container
+    build     Build a container from a Dockerfile
+    commit    Create a new image from a container's changes
+    …
+
+Docker images are [archived][] for easy reuse, so it's likely someone
+has the image you need (or a good start) already built.  Docker's
+images consist of a number of layers on top of the base image:
+
+    $ docker pull learn/tutorial
+    Pulling repository learn/tutorial from https://index.docker.io/v1
+    Pulling image 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c (precise) from ubuntu
+    Pulling image b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc (12.10) from ubuntu
+    Pulling image 27cf784147099545 () from tutorial
+
+The image has everything needed by a process (filesystem, system
+libraries, …), so you spin up the container by specifiying an image
+and target command.
+
+    $ docker run learn/tutorial echo hello world
+    hello world
+
+Changes made to a container are preserved between runs:
+
+    $ docker run learn/tutorial apt-get install -y ping
+
+You can checkpoint changes by committing, which adds a new layer:
+
+    $ docker ps -l
+    ID            IMAGE         COMMAND               CREATED       STATUS  PORTS
+    6982a9948422  ubuntu:12.04  apt-get install ping  1 minute ago  Exit 0
+    $ docker commit 6982a99 learn/ping
+    effb66b31edb
+    $ docker run learn/ping ping www.google.com
+    64 bytes from nuq05s02-in-f20.1e100.net (74.125.239.148): icmp_req=1 ttl=55 time=2.23 ms
+    64 bytes from nuq05s02-in-f20.1e100.net (74.125.239.148): icmp_req=2 ttl=55 time=2.30 ms
+    ^C
+
+You can list running containers:
+
+    $ docker ps
+    ID            IMAGE              COMMAND              CREATED         STATUS         PORTS
+    efefdc74a1d5  learn/ping:latest  ping www.google.com  37 seconds ago  Up 36 seconds
+    $ docker inspect efefdc7
+    [2013/07/30 01:52:26 GET /v1.3/containers/efef/json
+    {
+      "ID": "efefdc74a1d5900d7d7a74740e5261c09f5f42b6dae58ded6a1fde1cde7f4ac5",
+      "Created": "2013-07-30T00:54:12.417119736Z",
+      "Path": "ping",
+      "Args": [
+          "www.google.com"
+      ],
+      "Config": {
+          "Hostname": "efefdc74a1d5",
+          "User": "",
+          "Memory": 0,
+          "MemorySwap": 0,
+          "CpuShares": 0,
+          "AttachStdin": false,
+          "AttachStdout": true,
+          "AttachStderr": true,
+          "PortSpecs": null,
+          "Tty": false,
+          "OpenStdin": false,
+          "StdinOnce": false,
+          "Env": null,
+          "Cmd": [
+              "ping",
+              "www.google.com"
+          ],
+          "Dns": null,
+          "Image": "learn/ping",
+          "Volumes": null,
+          "VolumesFrom": "",
+          "Entrypoint": null
+      },
+      "State": {
+          "Running": true,
+          "Pid": 22249,
+          "ExitCode": 0,
+          "StartedAt": "2013-07-30T00:54:12.424817715Z",
+          "Ghost": false
+      },
+      "Image": "a1dbb48ce764c6651f5af98b46ed052a5f751233d731b645a6c57f91a4cb7158",
+      "NetworkSettings": {
+          "IPAddress": "172.16.42.6",
+          "IPPrefixLen": 24,
+          "Gateway": "172.16.42.1",
+          "Bridge": "docker0",
+          "PortMapping": {
+              "Tcp": {},
+              "Udp": {}
+          }
+      },
+      "SysInitPath": "/usr/bin/docker",
+      "ResolvConfPath": "/etc/resolv.conf",
+      "Volumes": {},
+      "VolumesRW": {}
+    }
+
+And you can push your local images to the repository:
+
+    $ docker images
+    ubuntu          latest  8dbd9e392a96  4 months ago    131.5 MB (virtual 131.5 MB)
+    learn/tutorial  latest  8dbd9e392a96  2 months ago    131.5 MB (virtual 131.5 MB)
+    learn/ping      latest  effb66b31edb  10 minutes ago  11.57 MB (virtual 143.1 MB)
+    $ docker push learn/ping
+
+You can also run interactive shells:
+
+    $ docker pull ubuntu
+    $ docker run -i -t ubuntu /bin/bash
+
+You can also [set environment variables][run], which are useful for
+customizing generic images:
+
+    $ docker run -e HOST=example.net -e PORT=1234 ubuntu
+
+Dockerfiles
+===========
+
+Instead of building containers manually, you can also specify them
+with a [Dockerfile][] ([spec][Dockerfile-spec]):
+
+    $ cat gentoo-portage/Dockerfile
+    FROM tianon/gentoo
+    MAINTAINER W. Trevor King, wking@tremily.us
+    RUN echo 'GENTOO_MIRRORS="http://mirror.mcs.anl.gov/pub/gentoo/"' >> /etc/portage/make.conf
+    #RUN echo 'SYNC="rsync://rsync.us.gentoo.org"' >> /etc/portage/make.conf
+    RUN mkdir -p /usr/portage
+    RUN emerge-webrsync
+    RUN emerge --sync --quiet
+    RUN eselect news read new
+    $ docker build -t wking/gentoo-portage gentoo-portage
+    …
+    $ cat gentoo-portage-en-us/Dockerfile
+    FROM wking/gentoo-portage
+    MAINTAINER W. Trevor King, wking@tremily.us
+    RUN echo en_US ISO-8859-1 > /etc/locale.gen
+    RUN echo en_US.UTF-8 UTF-8 >> /etc/locale.gen
+    RUN locale-gen
+    RUN echo 'LANG="en_US.UTF-8"' >> /etc/env.d/02locale
+    RUN env-update
+    $ docker build -t wking/gentoo-portage-en-us gentoo-portage-en-us
+    $ cat gentoo-portage-en-us-syslog/Dockerfile
+    FROM wking/gentoo-portage-en-us
+    MAINTAINER W. Trevor King, wking@tremily.us
+    RUN emerge -v sys-process/vixie-cron app-admin/syslog-ng app-admin/logrotate
+    RUN rc-update add syslog-ng default
+    RUN rc-update add vixie-cron default
+    $ docker build -t wking/gentoo-portage-en-us-syslog gentoo-portage-en-us-syslog
+
+You can't currently set the description (returned by `docker search
+…`) from the `Dockerfile`, although there [are][769] [some][2167]
+[proposals][2956] to add this feature.
+
+You can mount volumes from the `Dockerfile` using [VOLUME][], but it
+[doesn't][1124-explicit] support host mounts.  For those you have to
+use the [-v][run-v] option when you invoke `docker run …`:
+
+    $ docker run -i -t -v /usr/portage:/usr/portage:ro -v /usr/portage/distfiles:/usr/portage/distfiles:rw wking/gentoo-portage /bin/bash
+
+Bridging
+========
+
+Docker sets up a `docker0` bridge between the host's network and the
+containers.  Docker tries to guess an IP range that does not conflict
+with your local network, but [it's not omniscient][1558].  Until
+[1558][] is fixed, you're best bet is to set up your own bridge.  If
+you already have a `docker0` bridge:
+
+    $ ip addr show dev docker0
+    5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
+        link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
+        inet 10.0.42.1/16 scope global docker0
+           valid_lft forever preferred_lft forever
+    …
+
+then you can just change it's address:
+
+    # ip addr del 10.0.42.1/16 dev docker0
+    # ip addr add 172.31.42.1/16 dev docker0
+
+If the `docker0` bridge doesn't already exist, you'll have to [create
+it yourself][bridge]:
+
+    # brctl addbr docker0
+    # ip addr add 172.31.0.1/16 dev docker0
+    # ip link set dev docker0 up
+
+If you want to start over from scratch, you can stop docker and remove
+the bridge:
+
+    # /etc/init.d/docker stop
+    # ip link set dev docker0 down
+    # brctl delbr docker0
+
+Linking
+=======
+
+You can [link containers by name][linking]:
+
+    $ docker run -d -name redis crosbymichael/redis
+    $ sudo docker run -link redis:db -d -name webapp me/someapp
+
+This links `webapp` to `redis` using the alias `db`.  `DB_PORT` (and
+similar) environment variables are set in the `webapp` container,
+which it can use to connect to `redis` container.  You can also use
+[ambassadors][] to link containers on separate hosts.
+
+[Docker]: http://www.docker.io/
+[wikipedia-lxc]: http://en.wikipedia.org/wiki/LXC
+[1509]: https://github.com/dotcloud/docker/pull/1509
+[0c7e4c4]: http://code.google.com/p/go/source/detail?r=0c7e4c45acf8
+[JS]: https://github.com/GaretJax
+[overlay-11]: https://github.com/tianon/docker-overlay/issues/11
+[go-zugaina]: http://gpo.zugaina.org/dev-lang/go
+[OSSDL]: https://mark.ossdl.de/tag/ossdl-overlay/
+[gentoo]: http://docs.docker.io/en/latest/installation/gentoolinux/
+[aufs3]: http://aufs.sourceforge.net/
+[v0.7]: http://blog.docker.io/2013/11/docker-0-7-docker-now-runs-on-any-linux-distribution/
+[overlay]: https://github.com/tianon/docker-overlay/
+[lxc]: http://lxc.sourceforge.net/
+[c255a45]: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c255a458055e459f65eb7b7f51dc5dbdd0caf1d8
+[045eb9f]: https://github.com/tianon/docker-overlay/commit/045eb9f54bbfad07657ca1dafeb84d56c56fdbea
+[866-wtk]: https://github.com/dotcloud/docker/issues/866#issuecomment-30190904
+[archived]: https://index.docker.io/
+[run]: http://docs.docker.io/en/latest/commandline/cli/#run
+[Dockerfile]: http://www.docker.io/learn/dockerfile/
+[Dockerfile-spec]: http://docs.docker.io/en/latest/use/builder/
+[769]: https://github.com/dotcloud/docker/issues/769
+[2167]: https://github.com/dotcloud/docker/issues/2176
+[2956]: https://github.com/dotcloud/docker/pull/2956
+[VOLUME]: http://docs.docker.io/en/latest/use/builder/#volume
+[1124-explicit]: https://github.com/dotcloud/docker/pull/1124#issuecomment-22824230
+[run-v]: http://docs.docker.io/en/latest/use/working_with_volumes/
+[1558]: https://github.com/dotcloud/docker/issues/1558
+[bridge]: http://docs.docker.io/en/latest/use/networking/
+[linking]: http://docs.docker.io/en/latest/use/working_with_links_names/
+[ambassadors]: http://docs.docker.io/en/latest/use/ambassador_pattern_linking/
+
+[[!tag tags/linux]]
+[[!tag tags/tools]]