1. kiida

    Posted

    kiida
Changes in title
+Docker+Unikernleを触ってみた
Changes in tags
Changes in body
Source | HTML | Preview

はじめに

先日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で確認して

Screenshot from 2016-02-15 22-57-20.png

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

Screenshot from 2016-02-15 22-58-16.png

アクセスが確認できたら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で確認して

Screenshot from 2016-02-15 23-01-35.png

ブラウザでアクセスしてみると以下の通りnibbleblogが表示されました。

Screenshot from 2016-02-15 23-02-11.png

ということで一通り動かすことができました。

ぶっちゃけ、殆どUnikernel関係ないトラブルで時間を取られていましたw
Unikernelの理解はデモ動かすだけじゃなくて、中身ちゃんと追わないとダメっすねw

が、Unikernelは普通に使ったらメンドクセーんだろうなってことは分かったし、起動の速さやサイズの小ささ等のメリットも分かりました。これが今後dockerとの親和性が高まって、普通にコンテナを立ち上げる感覚で使えるようになったら流行りそうですね。