boot2docker で KVM+libvirt に固定IPで docker ホストを作るメモ

KVM+libvirt な仮想化ホストに、ブリッジ I/F で固定IPな docker ホストを boot2docker で作る試行錯誤のメモ。

なお boot2docker は新しい Docker のリリースや kernel の更新以外では更新されないメンテナンスモードになっているようです。

userdata.tar で SSH 鍵を配置

boot2docker は最初のブート時に先頭が boot2docker, please format-me という文字列で始まっているブロックデバイスを tar ファイルとして取り出して、ブートの都度 /home/docker に展開します。

tar を取り出した後のそのデバイスは永続データの領域として自動的にフォーマットされます。

そのようなブロックデバイスのためのディスクイメージはは次のように作成できます。

mkdir -p .ssh
chmod 700 .ssh/
curl https://github.com/ngyuki.keys -o .ssh/authorized_keys
chmod 600 .ssh/authorized_keys
echo "boot2docker, please format-me" > "boot2docker, please format-me"
tar cvf userdata.img "boot2docker, please format-me" .ssh
truncate -s 1G userdata.img
qemu-img convert -f raw -O qcow2 userdata.img userdata.qcow2

docker-machine はこの仕組を用いて authorized_keys を配置しているようですが、tar ファイルは /home/docker に展開されるだけなので固定IPを付与するような処理は行なえません。

bootsync.sh でブート時に固定IPを付与

boot2docker はブート時に /var/lib/boot2docker/bootsync.sh/var/lib/boot2docker/bootlocal.sh があればそれを sh で実行します。

/var/lib/boot2docker/ は永続データの領域なので、/var/lib/boot2docker/bootsync.sh に次のように書いておけばブートの都度、固定IPが付与されます。

killall udhcpc
sleep 1
ip addr flush dev eth0
ip addr add 192.168.0.100/24 dev eth0
ip route add default via 192.168.0.1 dev eth0
echo nameserver 192.168.0.1 > /etc/resolv.conf

しかし、初回ブート時にこのファイルを作成する術がありません。コンソールで作業すればいいだけですが・・

boot2docker-data

boot2docker はブート時に boot2docker-data というラベルのついたパーティションを探して、見つかればそれを永続データの領域としてマウントします。見つからなければ boot2docker, please format-me という文字列で始まっているブロックデバイス、またはパーティション未作成なブロックデバイスを自動的にフォーマットしてマウントします。

普通は初回ブート時に自動フォーマットされるときに、このラベルがついたファイルシステムとしてフォーマットされるのですが、あらかじめフォーマット済で boot2docker-data というラベルのついたパーディションを含むディスクファイルを用意すれば、任意のカスタマイズされた永続データ領域を初回ブート時から使用できます。

boot2dockerswap

boot2docker はブート時に boot2dockerswap というラベルのついたパーティションを探して、見つかればそれをスワップとして使います。見つからなくても警告が出力されるだけで起動はするようです。

普通は初回ブート時に自動フォーマットされるときに、永続データ用のパーティションをフォーマットするついでにこのラベルの付いたスワップパーティションも作成されますが、あらかじめ boot2dockerswap というラベルの付いたスワップパーティションを含むディスクファイルを用意すれば、自動フォーマットが行われなくてもスワップが有効になります。

やってみる

# 固定IPのためのスクリプトを作成
mkdir -p ./rootfs/var/lib/boot2docker/
cat <<'EOS'> ./rootfs/var/lib/boot2docker/bootsync.sh
killall udhcpc
sleep 1
ip addr flush dev eth0
ip addr add 192.168.0.100/24 dev eth0
ip route add default via 192.168.0.1 dev eth0
echo nameserver 192.168.0.1 > /etc/resolv.conf
EOS
chmod -x ./rootfs/var/lib/boot2docker/bootsync.sh

# SSH公開鍵を含む userdata.tar を作成
mkdir -p ./userdata/.ssh/
curl -s https://github.com/ngyuki.keys -o ./userdata/.ssh/authorized_keys
chmod 700 ./userdata/.ssh/
chmod 600 ./userdata/.ssh/authorized_keys
tar cvf ./rootfs/var/lib/boot2docker/userdata.tar -C ./userdata/ .ssh/

# ↑が保持ぞんされたファイルシステムを含むディスクファイルを作成
virt-make-fs --format=raw --partition=gpt --size=1G --type=ext4 --label=boot2docker-data ./rootfs/ data.img

# スワップのディスクファイルを作成
truncate -s 1G swap.img
parted -s -a optimal swap.img -- mklabel gpt mkpart primary 1 -1
guestfish -a swap.img run : mkswap /dev/sda1 label:boot2dockerswap

# 確認
virt-df -h -a data.img -a swap.img
#=> Filesystem                                Size       Used  Available  Use%
#=> data.img+:/dev/sda1                       992M       2.5M       922M    1%

# 確認
virt-filesystems --all --long -h -a data.img -a swap.img
#=> Name       Type        VFS   Label             MBR  Size   Parent
#=> /dev/sda1  filesystem  ext4  boot2docker-disk  -    1.0G   -
#=> /dev/sdb1  filesystem  swap  boot2dockerswap   -    1022M  -
#=> /dev/sda1  partition   -     -                 -    1.0G   /dev/sda
#=> /dev/sdb1  partition   -     -                 -    1022M  /dev/sdb
#=> /dev/sda   device      -     -                 -    1.0G   -
#=> /dev/sdb   device      -     -                 -    1.0G   -

# boot2docker.iso をダウンロード
wget https://github.com/boot2docker/boot2docker/releases/download/v18.09.1/boot2docker.iso

# ゲストを作成
virt-install \
  --import \
  --name boot2docker \
  --hvm \
  --virt-type kvm \
  --ram 1024 \
  --vcpus 1 \
  --arch x86_64 \
  --os-type linux \
  --boot cdrom \
  --disk "$PWD/data.img,device=disk,bus=virtio,cache=writeback" \
  --disk "$PWD/swap.img,device=disk,bus=virtio,cache=none" \
  --disk "$PWD/boot2docker.iso,device=cdrom" \
  --network network=default,model=virtio \
  --graphics none \
  --serial pty \
  --console pty

動作確認します。

env DOCKER_HOST=ssh://docker@192.168.0.100 docker run --rm hello-world
env DOCKER_HOST=ssh://docker@192.168.0.100 docker run -d -p 80:80 nginx
curl http://192.168.0.100/

さいごに

クラスタ化しないシングルの Docker 環境をサッと作れるように試行錯誤したのですが、boot2docker.iso

On the other hand, the boot2docker distribution (as in, boot2docker.iso) is in "maintenance mode".

とのことらしいので、別の Docker ホスト用の軽量 Linux を使うのが良いですかね。。

ただ、Container Linux (CoreOS) や Atomic Host はクラスタにする前提な気がして敷居が高く感じたので、RancherOS とかがいいんでしょうかね。