Docker on i386
I have had a much outdated but heroically stable Dell PowerEdge 2550 for many
years now. It's great to have a place to work on personal development projects
without dealing with hourly costs etc, but sometimes the lack of performance can
really be an issue. A lot of the work I've done in the past few years has been
centered around virtualization and so the machine has collected more dust than
it once did. I've been doing some work with Docker recently and got
excited that I could deploy some of my projects on this machine again. Somehow,
I hadn't ever noticed that Docker is only supported on amd64
at this
point.
- "focusing on amd64 for now"
- "it should work fine on 32-bit"
- "you just need new images and a 32-bit docker binary"
After some more searching I found that it wasn't incompatible but only unsupported. With comments like these, I had a new yak to shave.
The server started with a fully updated Ubuntu 13.04 install. I originally tried
to use the available Go deb packages but they were too old
(1.0.2
) for Docker which requires at least 1.1
. Next, I tried the
binary distribution but that was compiled with SSE2
optimizations enabled. I would have to build Go from source.
Building Go doesn't require a lot of prerequisites, but we need a compiler and mercurial to clone the sources.
$ sudo apt-get -y install build-essential mercurial
Not only is this server 32-bit, but it's old enough to lack support for SSE2.
$ export GO386=387
Clone the Go sources.
$ hg clone -u release https://code.google.com/p/go /home/mwhiteley/p/go
...
Build Go and add it to our path.
$ pushd /home/mwhiteley/p/go/src
$ ./all.bash
...
$ popd
$ export GOPATH=/home/mwhiteley/go
$ export PATH=$GOPATH/bin:$PATH:/home/mwhiteley/p/go/bin
$ go version
go version go1.1.2 linux/386
For Docker, we need a few more prerequisites such as the Linux Containers userspace tools and a kernel module for the Advanced Multi Layered Unification Filesystem.
$ sudo apt-get -y install git linux-image-extra-$(uname -r) lxc xz-utils
Clone the Docker sources.
$ git clone dotcloud/docker $GOPATH/src/github.com/dotcloud/docker
...
Enable and build a 32-bit Docker.
$ pushd $GOPATH/src/github.com/dotcloud/docker
$ curl https://gist.github.com/whiteley/6400552/raw/server.go.diff | git apply -
$ go get -v github.com/dotcloud/docker/...
$ go install -v github.com/dotcloud/docker/...
$ popd
$ docker version
Go version (client): go1.1.2
Go version (server): go1.1.2
Last stable version: 0.6.1
A base image is just the contents of a minimal file system and we can create one
with debootstrap. The /etc/apt/sources.list
file will not
contain anything except the single install repository.
$ sudo debootstrap raring /tmp/rootfs
$ for d in raring raring-security raring-updates raring-backports
for> do echo "deb http://archive.ubuntu.com/ubuntu ${d} main universe multiverse"
for> done | sudo tee /tmp/rootfs/etc/apt/sources.list
deb http://archive.ubuntu.com/ubuntu raring main universe multiverse
deb http://archive.ubuntu.com/ubuntu raring-security main universe multiverse
deb http://archive.ubuntu.com/ubuntu raring-updates main universe multiverse
deb http://archive.ubuntu.com/ubuntu raring-backports main universe multiverse
$ sudo tar czf /home/mwhiteley/p/raring_base32_rootfs.tgz -C /tmp/rootfs .
We can now create a docker
group and start the daemon. The group members will
have access to connect directly to the daemon running as root and potentially
gain root access on the host. Make sure to read the instructions
carefully and only do this on a development machine.
$ sudo addgroup docker
Adding group `docker' (GID 1001) ...
Done.
$ sudo addgroup mwhiteley docker
Adding user `mwhiteley' to group `docker' ...
Adding user mwhiteley to group docker
Done.
$ sudo docker -d
Loading containers: done.
2013/08/31 17:25:41 WARNING: Your kernel does not support cgroup swap limit.
2013/08/31 17:25:41 Listening for HTTP on /var/run/docker.sock (unix)
Now, in another terminal (a new login shell so your group membership takes effect), we can import the base image.
$ cat /home/mwhiteley/raring_base32_rootfs.tgz | docker import - mwhiteley/base32
c755b018548a
$ docker images
REPOSITORY TAG ID CREATED SIZE
mwhiteley/base32 latest c755b018548a 21 minutes ago 187.4 MB (virtual 187.4 MB)
Run a simple test to make sure that everything seems operational.
$ docker run c755b018548a env
HOME=/
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
container=lxc
HOSTNAME=d60803fb36fe
Create a Dockerfile and build an image
$ cat <<'EOP' >/home/mwhiteley/p/docker/chef/Dockerfile
heredoc> FROM c755b018548a
heredoc> MAINTAINER Matt Whiteley <mattwhiteley@gmail.com>
heredoc> RUN apt-get update
heredoc> RUN apt-get -y install curl git ruby1.9.3
heredoc> RUN curl -L https://www.opscode.com/chef/install.sh | bash
heredoc> EOP
$ docker build /home/mwhiteley/p/docker/chef
...
---> b8d729360f11
Successfully built b8d729360f11
$ docker images
REPOSITORY TAG ID CREATED SIZE
<none> <none> b8d729360f11 19 seconds ago 88.5 MB (virtual 710.8 MB)
mwhiteley/base32 latest c755b018548a 35 minutes ago 187.4 MB (virtual 187.4 MB)
Wow, look at the size of that thing! Evidently the ruby1.9.3
package in Ubuntu
pulls in a ton of dependencies that we won't be needing and a different route
for Ruby will save us a ton of space. For now, let's just make sure it all
worked.
$ docker run b8d729360f11 chef-solo --version
Chef: 11.6.0
Awesome, Docker running on my 866MHz Pentium III! Now, on to make some better images for test environments.