DB2 on Docker
Getting something running on Docker is no news nowadays. Docker makes it super easy to try new things quick and easy: ZooKeeper, Kafka…
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 aufs 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 OS X 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 (be cautious and see this), you cannot get into a running containers. 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 db2_inst_1 ps -A
PID TTY TIME CMD
1 ? 00:00:00 su
8 ? 00:00:00 bash
97 ? 00:00:00 db2syscr
99 ? 00:00:01 db2sysc
105 ? 00:00:00 db2syscr
106 ? 00:00:00 db2syscr
107 ? 00:00:00 db2syscr
109 ? 00:00:00 db2vend
117 ? 00:00:00 db2fmp
118 ? 00:00:00 bash
489 ? 00:00:00 ps
> docker-enter db2_inst_1
% hostname
f4c1b9530fef
How cool is that!