Edited at

Docker+Unikernelを触ってみた

More than 3 years have passed since last update.


はじめに

先日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でVMを作成

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でアクセスします。


作ったVMにsshでアクセス

docker-machine ssh unikernel-demo


適当に作業ディレクトリを作って、デモのコードをGitHubからcloneします。


作業ディレクトリの作成と必要なコードの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をチェックアウトします。


Kernel4.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

続いて必要なパッチをダウンロード・適用します。


Kernelパッチの適用

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のビルドに必要なパッケージをインストールします。


Kernelビルドに必要なパケージのインストール

apt-get fakeroot build-dep linux-image-`uname -r`


以上で準備が完了なので、実行権限を与えてビルドします。(めちゃくちゃ時間がかかります。)


Kernelのビルド

chmod a+x debian/rules

fakeroot debian/rules clean
DEB_BUILD_OPTIONS=parallel=12 fakeroot debian/rules binary-headers binary-generic

ビルドが完了したら今ビルドしたKernelに入れ替えます。


ビルドした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に記載します。今回は以下のようになりました。


/etc/defau/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 updateapt-get dist-upgradeも実行しました。


Unikernelを動かす

ということで、やっと動かせます。

まず今回のデモで必要なパッケージをインストールします。


今回のデモで必要なパッケージをインストール

apt-get install genisoimage makefs kvm make binutils


cloneしたディレクトリに移動して、make pullを実行します。

cd ~/work/unikernel/DockerConEU2015-demo

make pull

するとエラーになってしまいました。dockerのstatusを見るとなんと起動していません。。。


dockerが起動していない

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-driveraufsになっているところを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を立ち上げます。


nginxのunikernelを起動

./docker-unikernel run -P --hostname nginx unikernel/nginx


この時点でnginxのunikernelが立ち上がっているのでdoker psで確認して

上記のポートにブラウザからアクセスすると以下のような画面が表示されます。

アクセスが確認できたらdocker rm -f adoring_dijkstraでnginxのインスタンスは削除してしまいましょう。

ちなみに、Nginxのインスタンスのサイズを見ると以下の通り、OS込みで2.1MBと驚くほど小さいことが分かります。


nginxのunikernelのサイズ

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を立ち上げます。


mysqlのunikernelを立ち上げ

./docker-unikernel run --hostname mysql --name mysql unikernel/mysql


ちなみにmysql-clientを入れればmysqlに接続できます。


mysqlに接続

apt-get install mysql-client

mysql -h mysql -u rump

続いてnginxとphpを立ち上げます。


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との親和性が高まって、普通にコンテナを立ち上げる感覚で使えるようになったら流行りそうですね。