はじめに
先日Docker+UnikernelのオンラインMeetupを見たので(視聴メモ)、Docker+Unikernelを試してみました。
現状簡単に試せるものではないようなので、まずは上記のMeetupのデモ(元はDockerConEU2015で行われたデモみたいです)を動かしてみようと思います。本当はもう少し応用させようと思ったんですが、めちゃくちゃ苦戦してしまったのでデモを動かすだけのポストですm(_ _)m
動かしてみた
物理マシン上で実行するべきなのかと思いますが、手元のマシンはキレイにしておきたいのでDigitalOcean上のVMで行います。DockerとKVMが動くLinuxマシンであればどこでも動くのでその他の環境でも問題ないかと思います。これを機にDigitalOceanを始めますって人がいたらこちらから申し込んでもらえるとお互いハッピーなはずです(多分w)。
ホストの用意
まずはホスト用のマシンを準備します。docker-machineで立ち上げると最初からdockerも入るので楽だと思います。docker-machineは上記のレポジトリのリリースからダウンロードしたものにPATHを通すだけでOKです。
docker-machine create -d digitalocean --digitalocean-image "ubuntu-15-10-x64" --digitalocean-region "sfo1" --digitalocean-size "32gb" --digitalocean-access-token ${DIGITALOCEAN_API_TOKEN} unikernel-demo
DigitalOceanのAPI Token(上記の${DIGITALOCEAN_API_TOKEN})とvmの名前(上記のunikernel-demo)は適宜変更してください。
上記はメモリ32GBのインスタンスを使っていますが、もっと安いインスタンスで大丈夫です。今回はあとでカーネルのビルド(一応省略可)を行うので、早く終わるよう大きめにしました(でも多分大きすぎたw)。
また、ubuntu以外のディストリビューションでもOKですが、debian系じゃないとあとで必要となるmakefs
を手動ビルドする必要が出てきます。
次に今作ったVMにsshでアクセスします。
docker-machine ssh unikernel-demo
適当に作業ディレクトリを作って、デモのコードをGitHubからcloneします。
mkdir -p ~/work/{unikernel,kernel}
cd ~/work/unikernel
git clone https://github.com/Unikernel-Systems/DockerConEU2015-demo.git
Kernelのビルド(省略可)
デモのコードにはKernel4.1.13用のパッチが含まれているので、Kernel4.1.13のビルドとパッチ当てを行います。このパッチは一つのホスト上で複数のUnikernelのインスタンスを立てる場合に必要になるものです。これを入れない場合でも1つのUnikernelインスタンスのみのデモは動かすことができます。
また、パッチの中身は非常にシンプルなので、Kernel入れ替えるのが面倒な場合は他のKernel用のを用意しても良いかもしれません。
今回は4.1.13を使うので、まずはUbuntu用のKernelのソースのv4.1.13をチェックアウトします。
cd ~/work/kernel
git clone git://git.launchpad.net/~ubuntu-kernel-test/ubuntu/+source/linux/+git/mainline-crack
cd mainline-crack
git checkout v4.1.13
続いて必要なパッチをダウンロード・適用します。
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.1.13-wily/0001-base-packaging.patch
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.1.13-wily/0002-debian-changelog.patch
wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.1.13-wily/0003-configs-based-on-Ubuntu-4.1.0-3.3.patch
patch -p1 < 0001-base-packaging.patch
patch -p1 < 0002-debian-changelog.patch
patch -p1 < 0003-configs-based-on-Ubuntu-4.1.0-3.3.patch
続いて今回のデモで必要なパッチを当てます。
patch -p1 drivers/net/macvtap.c < ~/work/unikernel/DockerConEU2015-demo/macvtap.patch
次にKernelのビルドに必要なパッケージをインストールします。
apt-get fakeroot build-dep linux-image-`uname -r`
以上で準備が完了なので、実行権限を与えてビルドします。(めちゃくちゃ時間がかかります。)
chmod a+x debian/rules
fakeroot debian/rules clean
DEB_BUILD_OPTIONS=parallel=12 fakeroot debian/rules binary-headers binary-generic
ビルドが完了したら今ビルドしたKernelに入れ替えます。
cd ../
dpkg -i linux-headers-4.1.13-040113* linux-image-*
続いてデフォルトで起動するkernelを今インストールしたものに変更します。まず、/boot/grub/grub.cfg
のmenuentryから4.1.13になっている箇所の文字列を/etc/default/grub
のGRUB_DEFAULTに記載します。今回は以下のようになりました。
GRUB_DEFAULT="gnulinux-advanced-a20e3e28-89be-4eb7-b0aa-a442c730eab0>gnulinux-4.1.13-040113-generic-advanced-a20e3e28-89be-4eb7-b0aa-a442c730eab0"
次にupdate-grub
をしてreboot
します。再起動したらuname -r
で正しいバージョンになっているか確認してください。
念の為apt-get update
とapt-get dist-upgrade
も実行しました。
Unikernelを動かす
ということで、やっと動かせます。
まず今回のデモで必要なパッケージをインストールします。
apt-get install genisoimage makefs kvm make binutils
cloneしたディレクトリに移動して、make pull
を実行します。
cd ~/work/unikernel/DockerConEU2015-demo
make pull
するとエラーになってしまいました。dockerのstatusを見るとなんと起動していません。。。
root@unikernel-demo:~# systemctl status docker
● docker.service
Loaded: loaded (/etc/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Tue 2016-02-16 01:08:55 EST; 2s ago
Process: 2242 ExecStart=/usr/bin/docker daemon -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock --storage-driver aufs --tlsverify --tlscacert /etc/docker/ca.pem --tlscert /etc/docker/server.pem --tlskey /etc/docker/server-key.pem --label provider=digitalocean (code=exited, status=1/FAILURE)
Main PID: 2242 (code=exited, status=1/FAILURE)
Feb 16 01:08:55 unikernel-demo systemd[1]: Started docker.service.
Feb 16 01:08:55 unikernel-demo docker[2242]: time="2016-02-16T01:08:55.321222277-05:00" level=fatal msg="Error starting daemon: error initializing graphdriver: driver not supported"
Feb 16 01:08:55 unikernel-demo systemd[1]: docker.service: Main process exited, code=exited, status=1/FAILURE
Feb 16 01:08:55 unikernel-demo systemd[1]: docker.service: Unit entered failed state.
Feb 16 01:08:55 unikernel-demo systemd[1]: docker.service: Failed with result 'exit-code'.
色々調べたら、どうやらKernelビルド時にaufsを含める必要があったようですが抜けていたようです。
もう一度ビルドするのは時間がもったいないので、今回はaufsではなくoverlayを使います。
ということで、/etc/systemd/system/docker.service
を開いてstorage-driver
がaufs
になっているところをoverlay
に変更してdockerのサービスを立ち上げ直します。
再びmake pull
すると無事実行できました。
Makefileを見ると分かりますが、https://hub.docker.com/r/mato/rumprun-packages-hw-x86_64/ をpullしているようです。中身はnginx, mysql, phpのrumprunのイメージを落としてくるようです。ちなみにrumprunはNetBSDベースのUnikernelの実装の一つです。こちらのwikiによるとrumprun自体はLinuxに限らず動くようですが、今回は後で実行するMakefileの中で使っているツールがLinuxのものなのでLinux限定になっているようです。
以下を実行するとmysql、nginx、phpそれぞれのunikernelのビルドおよび名前解決用のコンテナが立ち上がります。
make
make rundns
続いてnginxのunikernelを立ち上げます。
./docker-unikernel run -P --hostname nginx unikernel/nginx
この時点でnginxのunikernelが立ち上がっているのでdoker ps
で確認して
上記のポートにブラウザからアクセスすると以下のような画面が表示されます。
アクセスが確認できたらdocker rm -f adoring_dijkstra
でnginxのインスタンスは削除してしまいましょう。
ちなみに、Nginxのインスタンスのサイズを見ると以下の通り、OS込みで2.1MBと驚くほど小さいことが分かります。
docker run --rm -i -t unikernel/nginx du -h nginx.bin.bz2
2.1M nginx.bin.bz2
ちなみに、起動も速いです(nginxだけじゃなくてこの後動かすphpもmysqlも)。
なお、ここまではUnikernelのインスタンスが1つなので、Kernelにパッチを当てていなくても実行できます。
続いて、mysql、nginx、phpでnibbleblogを立ち上げるデモを実行してみます。
まずはmysqlを立ち上げます。
./docker-unikernel run --hostname mysql --name mysql unikernel/mysql
ちなみにmysql-clientを入れればmysqlに接続できます。
apt-get install mysql-client
mysql -h mysql -u rump
続いてnginxとphpを立ち上げます。
./docker-unikernel run --hostname php-blog --name php-blog unikernel/php-nibbleblog
./docker-unikernel run -P --hostname blog --name blog unikernel/nginx-nibbleblog
ちなみにKernelにパッチを当てていないとここでエラーになります。
docker psで確認して
ブラウザでアクセスしてみると以下の通りnibbleblogが表示されました。
ということで一通り動かすことができました。
ぶっちゃけ、殆どUnikernel関係ないトラブルで時間を取られていましたw
Unikernelの理解はデモ動かすだけじゃなくて、中身ちゃんと追わないとダメっすねw
が、Unikernelは普通に使ったらメンドクセーんだろうなってことは分かったし、起動の速さやサイズの小ささ等のメリットも分かりました。これが今後dockerとの親和性が高まって、普通にコンテナを立ち上げる感覚で使えるようになったら流行りそうですね。