Getting something running on Docker is no news nowadays. Docker makes it super easy to try new things quick and easy: ZooKeeper, Kafka, Storm, piece of cake. As simple as pulling then running.

And there’s even Fig, which is just awesome!

So why do I want to write about running DB2 on Docker? It turns out there are still some dark areas.

Here it is: https://github.com/bryantsai/db2-docker, after burning several hours looking up here and there.

So what’s difficult about getting DB2 running on Docker?

Docker Storage

DB2 uses O_DIRECT flag which is not supported by the aufs storage backend used by Docker. There are two work-around: changing Docker to use devicemapper storage backend or using volumes. See this thread for more backgrounds.

Requiring change of Docker storage backend is not really an ideal solution, as this is not a per-container option. It’s best to provide an image that anyone can use easily.

So that leaves the option of using volumes. Essentially, volumes bypass auks storage backend. There are several different ways of using volumes, and I found “Data Volume Container” (some called “data-only-container”) most suitable for DB2 container usage.

In our DB2 container, the complete /home is mounted on a volume from a “data-only-container” whose sole purpose is to export the /home volume. In fact, we don’t even need this “data-only-container” running, we just run it once and the volume exported would be useable by our DB2 container:

# this is how we “create” the data volume
# note the special usage of “true” as the command
> docker run -i --name=db2_data_1 -v /home busybox true

# even it is not running, the volume is usable by 
# other DB2 containers
> docker ps -a
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS                   PORTS               NAMES
fdcb78bdb340        busybox:buildroot-2014.02   "true"              6 hours ago         Exited (0) 6 hours ago                       db2_data_1

# launch a DB2 container using the volume
> docker run --privileged=true -i -t --volumes-from=db2_data_1 --name=db2_inst_1 db2:expc

In this way, the complete DB2 instance data including the database content are stored in that volume, separate from the DB2 container. We could start and stop the DB2 container freely and the database content would still be available.

This of course is much better and much portable than using local file system as the volume. You can also easily backup and restore the volume content if you need.

This is also better than the in-container volume as you get to reuse the same volume across different runs.

Building with Volumes

There’s still one tricky part on using volume for DB2 instance data. When building an image from Dockerfile, there’s no way of using volumes. Yes, there’s a “Volume” command available in Dockerfile, but that is meant to be mounted when the image being built is actually ran. Not for build time!

In the end, we have to resort to using shell script to build the DB2 instance container in order to have the volume mounted. We actually build a base DB2 image using “compact” installation mode (no instance created) and then use a shell script to run this image with needed volume mounted:

docker run -i --name=db2_data_1 -v /home busybox true

docker run --rm=true -i --volumes-from=db2_data_1 db2:expc /bin/bash <<EOF
  userdel dasusr1;userdel db2fenc1;userdel db2inst1;groupdel dasadm1;groupdel db2fgrp1;groupdel db2grp1
  groupadd db2grp1;groupadd db2fgrp1;groupadd dasadm1;useradd -g db2grp1 -m -d /home/db2inst1 db2inst1 -p db2inst1;useradd -g db2fgrp1 -m -d /home/db2fenc1 db2fenc1 -p db2fenc1;useradd -g dasadm1 -m -d /home/dasusr1 dasusr1 -p dasusr1
  /opt/ibm/db2/V10.5/instance/db2icrt -p $port -u db2fenc1 db2inst1
EOF

When it ends, the DB2 instance is created and persisted in the volume from db2_data_1. We don’t need this “build” container anymore so it is removed right after completion (—rm=true).

Once the DB2 instance is created, we can launch a DB2 container and get into it:

docker run --privileged=true --rm=true -i -t -P --volumes-from=db2_data_1 --name=db2_inst_1 db2:expc /bin/su -c '/home/db2inst1/sqllib/adm/db2start;/bin/bash' - db2inst1

From there, you can create/use databases.

Privileged Mode

You would see the following error when starting DB2 manager if you don’t run the container in privileged mode:

$ db2start
SQL1042C  An unexpected system error occurred.

According to https://github.com/jeffbonhag/db2-docker,

DB2 has a problem where it needs more shared memory than Docker originally provides.

That’s why we add —privileged=true parameter when running it.

Bonus Points

I’m using Mac OS X and this is another major contributor of spending so much time on this.

Check out How to Use Docker on OS X: The Missing Guide if you use Docker on Mac OS X. There are at least two take-way.

On Mac OS X, because there’s a “boot2docker” VM serving as the Docker host, you cannot directly mount OS X local files or directories as volume. The normal Docker mount is meant for the Docker host, and on OS X it’s the “boot2docker” VM.

Luckily there’s a convenient solution, check out boot2docker together with VirtualBox Guest Additions. With it, you can mount files and directories under /Users on OSX using Docker command directly.

The other take-way bonus point is to get you inside a running Docker container. What does that mean?

Docker containers are often ran in detached mode. Unless you enable sshd, you cannot get into a running containers 1. Sometimes we just need to get into there. So how can we do that without sshd?

Create the following shell script and put it somewhere in your PATH:

#!/bin/bash
set -e

# Check for nsenter. If not found, install it
boot2docker ssh '[ -f /var/lib/boot2docker/nsenter ] || docker run --rm -v /var/lib/boot2docker/:/target jpetazzo/nsenter'

# Use bash if no command is specified
args=$@
if [[ $# = 1 ]]; then
  args+=(/bin/bash)
fi

boot2docker ssh -t sudo /var/lib/boot2docker/docker-enter "${args[@]}"

Then you can do some crazy stuff like these:

> docker-enter web ps -A
  PID TTY          TIME CMD
    1 ?        00:00:00 nginx
  245 ?        00:00:00 ps

> docker-enter web
% hostname
f4c1b9530fef

How cool is that!

Recent Posts