[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, `lx-checkconfig` was updated in [c93c7b1, Fix checkconfig to handle kernel memory cgroup name change, 2012-11-14][c93c7b1], released in LXC v0.9.0) 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: 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 [c93c7b1]: https://github.com/lxc/lxc/commit/c93c7b1a0b0d4548780b9c22fb9ab907783caad1 [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]]