管理の都合上Docker用のVMの上でDockerコンテナを動かしたいなー、Dockerコンテナ動かすだけなら薄いやつがいいだろうから
boot2dockerかなーと思ったのだけど、WindowsとMac OS Xで動かす例ばかりでLinuxで動かしている話を見かけない。使えないわけではなく、isoから入れれば使えそうなのでやってみた。なお今回の前提はKVMだけども、boot2dockerをカスタマイズしたいとなれば、Hyper-VやVirtualBoxでも設定の部分は参考になるかも。
手順の概要
概ねやりかたは以下の通り。
- 永続化データ領域を確保・設定する。
- virt-installでVMを作成する。
- IPアドレスやSSHなどの設定をする。
- リモート接続用の鍵を取り出して使う。
環境
- ハイパーバイザ
- Ubuntu 14.04 (libvirt/KVM設定済)
- boot2docker
- 1.6.1
ここで試したのはUbuntuだけど、今回の例ではvirt-installが使えればだいたい一緒だと思う。
注意
boot2dockerはデフォルトではかなりinsecure (固定デフォルトパスワードあり・SSHパスワードログイン可) なので、信頼できないネットワーク、例えばインターネットに直接晒されるような環境で作業しないこと。
データ保存領域の設定
boot2dockerはOS部分となる揮発性の領域と、永続的なデータ保存領域(dockerイメージ格納領域を含む)で動作する。そのため、VMを立ち上げる前にデータ保存領域を事前に準備する。揮発性の部分の領域も用意してもいいのだが、今回はしないことにする。
やりかたとしては、qemu-imgで領域を確保し、partedでパーティションを切り、mkfs.ext4でファイルシステムを作成する。このとき、"boot2docker-data"というラベルを設定することがポイント。boot2dockerはこのラベルを見てマウントしに来る。
コマンドライン例は、以下の通り。2Gと書いてみたけど、dockerコンテナのデータが全て来るので、適切なサイズに設定する。
# qemu-img create -f raw /home/images/boot2docker-data.img 2G
# chmod 600 boot2docker-data.img
# losetup -f
/dev/loop0
# losetup /dev/loop0 boot2docker-data.img
# parted --script /dev/loop0 'mklabel msdos'
# parted --script /dev/loop0 'mkpart primary 0% 100%'
# mkfs.ext4 -L boot2docker-data /dev/loop0p1
# losetup -d /dev/loop0
mkpartで、0の代わりに0%とすると、アラインメントをよしなにしてくれる(警告はなくなるが意味はあるか?)。コマンドが短いのでpartedを使っただけで、fdiskでもいいし、再起動回数が増えるけどもboot2dockerが上がってきた後fdiskを使うとlosetupはしなくていい。
なお、LVMを使うなら、qemu-imgの代わりに、lvcreateでこんな感じ。
# lvcreate -L 8G -n boot2docker-data vg0
virt-installでVM作成
まず、
boot2dockerのisoをどこかにダウンロードする。ずっと使うのでうっかり消さなそうな場所に。ここでは、/home/images/boot2docker.isoにダウンロードしてきたのを想定する。
そして、libvirtでVMを作成する。libvirtのXMLを自前で生成する例を見かけたけども、virt-installがやってくれるので、virt-installで作る。
例としては、こんな感じ。
# virt-install --name=boot2dockertest --ram=1024 --vcpus=1 \
--os-type=linux --os-variant=virtio26 \
--disk path=/home/images/boot2docker-data.img \
--network bridge:br0 \
--livecd --cdrom=/home/images/boot2docker.iso
この--livecdをつけないと、初回だけCDがある状態になって、2回目の起動以降起動できなくなる。
さまざまな設定
これでboot2dockerが立ち上がってくる。virsh console VM名(ここではboot2dockertest)とすれば、コンソールに接続でき、dockerなどとユーザー名を入れればログインできる。poweroffコマンドでシャットダウン。
このように、/var/lib/{boot2docker,docker}が/mnt/vda1に向いていれば、データ領域の準備もOK。
docker@boot2docker:~$ df
Filesystem Size Used Available Use% Mounted on
rootfs 445.5M 87.5M 358.0M 20% /
tmpfs 445.5M 87.5M 358.0M 20% /
tmpfs 247.5M 0 247.5M 0% /dev/shm
/dev/vda1 1.9G 18.0M 1.8G 1% /mnt/vda1
cgroup 247.5M 0 247.5M 0% /sys/fs/cgroup
/dev/vda1 1.9G 18.0M 1.8G 1% /mnt/vda1/var/lib/docker/aufs
docker@boot2docker:~$ ls -al /var/lib
total 0
drwxrwxr-x 3 root staff 100 May 9 15:26 ./
drwxrwxr-x 8 root staff 180 May 9 15:26 ../
lrwxrwxrwx 1 root root 29 May 9 15:26 boot2docker -> /mnt/vda1/var/lib/boot2docker/
lrwxrwxrwx 1 root root 24 May 9 15:26 docker -> /mnt/vda1/var/lib/docker/
drwxr-xr-x 4 root root 160 May 9 15:26 nfs/
ここから、いろいろと設定していく。
hostnameの設定
/var/lib/boot2docker/etc/hostname を変更する。データ保存領域にあるので、書き換えればOK.
$ sudo vi /var/lib/boot2docker/etc/hostname
sshd_configの設定
パスワードログインできないように設定する。こちらも書き換えればOK.
$ sudo vi /var/lib/boot2docker/ssh/sshd_config
(以下を変更/追記)
PasswordAuthentication no
ssh 公開鍵の配置
ssh ログインできるよう、公開鍵を配置する。作業用ユーザである「docker」のホームディレクトリは永続化されないので、boot2dockerの「/var/lib/boot2docker/userdata.tarを置いておくとホームディレクトリに展開される」という機能を利用して、SSH鍵を配置することにする。
公開鍵の取り方はなんでもいいが、ここではgithub.com/{username}.keysにアクセスするとそのユーザの公開鍵が得られるという方法で鍵を取ってみる例を載せる。
$ cd /var/lib/boot2docker
$ sudo mkdir userdata
$ sudo chown docker userdata
$ cd userdata
$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh
$ curl -o authorized_keys https://github.com/{username}.keys
$ cd /var/lib/boot2docker/userdata
$ tar cf ../userdata.tar .
起動時スクリプトの設定(IPアドレス他の設定)
デフォルトでは、dhcpでIPアドレスをもらうだけなので、固定IPアドレスにしたいときは、設定が必要になる。boot2dockerの「起動時に/var/lib/boot2docker/bootsync.shとbootlocal.shが呼び出される」という機能を利用して、スクリプトにIPアドレス他を設定するコマンドをいれておくことにする。bootsync.shは/etc/rc.d/dockerが起動される前、bootlocal.shは後に動くので、先に動くbootsync.shに設定する。
例は以下の通り。boot2dockerのVMのIPアドレスは192.168.1.100と仮定する。
$ sudo vi /var/lib/boot2docker/bootsync.sh
(以下を記述)
#!/bin/sh
/etc/init.d/services/dhcp stop
ip addr flush eth0
ip addr add 192.168.1.100/24 dev eth0
ip route add default via 192.168.1.254
echo "nameserver 192.168.1.254" >> /etc/resolv.conf
$ sudo chmod 755 /var/lib/boot2docker/bootsync.sh
リモート接続用の鍵の再生成
初回起動時に/var/lib/boot2docker/tls/にリモート接続用の鍵が生成されて、必要なものが~/.dockerにコピーされているが、IPアドレスが含まれているので、再生成する。生成の方法は/etc/rc.d/dockerに書いてあるが、簡単にするため、いったん消して再起動時に作らせてしまうことにする。
$ sudo rm -rf /var/lib/boot2docker/tls
あとは、rebootで再起動して設定が反映されていることを確認する。
リモート接続用の鍵の取り出し
このままboot2dockerのVMでdockerコマンドを叩いても使えるが、作業用のPCからdockerコマンドで接続できるようにすると便利。先ほど生成させたキーを、作業用のPCにscpでもらってくる。
$ mkdir -p ~/.boot2docker/certs/boot2dockertest
$ scp 'docker@192.168.1.100:~/.docker/*.pem' ~/.boot2docker/certs/boot2dockertest
あとは、ここに接続するための環境変数を設定するスクリプトを用意して、dot sourceして使えばOK。
$ vi ~/bin/use-boot2dockertest
export DOCKER_CERT_PATH=~/.boot2docker/certs/boot2dockertest
export DOCKER_TLS_VERIFY=1
export DOCKER_HOST=tcp://192.168.1.100:2376
$ . ~/bin/use-boot2dockertest
これで一通りの設定が終了。例えばこんな風に動かして、VM上でdocker psすると、boot2docker VMで動いていることがわかる。dockerのバージョンが合ってないとつながらなかったりするので注意。
$ boot2docker run ubuntu:14.04 -i -t /bin/bash
今後の展開
もう少しスクリプト化することもできるのだろうけど、それは
Docker Machineの仕事だよねと思ってやめた。
Docker Machineがlibvirtに対応すれば、ほとんどの作業を一通りやってくれるはずなので期待して続報を待とう。