Moby で LinuxKit を起動してみる

 Moby Docker LinuxKit
2017.04.19

DockerCon 2017 で発表された Moby プロジェクト を利用して LinuxKit が動作するところまでを確認します。

 

Moby

もともと使われている意味の Moby

Docker 社のロゴにもなっている、このクジラの愛称[^1]。 [^1]: 厳密には Moby Dock だけれど、界隈ではモビィって呼ばれてる気がする。

Moby (https://blog.docker.com/2015/06/winners-dockercon-2015-contests/ より拝借)

最近チラ見せしていた Moby OS

Alpine Linux ベースの軽量 OS。Docker for Mac の記事でよく Message of The Day のアスキーアートとともに紹介されていますが

                    ##         .
              ## ## ##        ==
           ## ## ## ## ##    ===
       /"""""""""""""""""\___/ ===
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
       \______ o           __/
         \    \         __/
          \____\_______/

Docker for AWS などでは Docker Inc. が用意したであろう Moby な AMI で EC2 クラスタが起動するなど、 Docker 製品群では近頃大活躍している OS です。

Moby

今回発表されたコンテナ環境を組み立てるためのフレームワーク

標準化されたランタイム、オーケストレーション、ネットワーキング セキュリティ、ビルド / イメージ配布方法などを利用して、 様々なプラットフォーム / アーキテクチャ上で実行可能なものを 組み立てることができます。 Linux や Mac、Windows なら実行形式ファイルを、 クラウドや仮想化事業者に向けては VM イメージが生成されます。

上述の Moby OS なども、いずれは Moby 経由で生成されるかもですね。 CTO の Solomon Hykes 氏が PR で Moby への移行を語っています。

LinuxKit

Publickey さんの記事 がわかりやすかったのですが DockerCon のデモでもあったように、この LinuxKit を Moby を使えば簡単にビルドすることができます。やってみましょう。

LinuxKit を動かすまで

以下、MacBook Pro (Early 2015) macOS Sierra で動作確認しています。

1. moby コマンドのインストール

方法 1

Go 環境があれば楽勝

go get -u github.com/docker/moby/src/cmd/moby

方法 2

のインストールされた環境で

git clone https://github.com/linuxkit/linuxkit.git
cd linuxkit
make

でビルドすれば、bin 以下に moby バイナリが生成されます。 PATH の通ったところに置いて実行権限をつけましょう。

2. LinuxKit イメージのビルド

moby 自体も内部的に Docker の仕組みを使うので Docker がインストールされた環境で以下のコマンドを実行します。

moby build linuxkit.yml

するとログにあるように、linuxkit-xxx というファイルが生成されましたね!

Create outputs:
  linuxkit-bzImage linuxkit-initrd.img linuxkit-cmdline
  linuxkit.iso
  linuxkit-efi.iso

3. LinuxKit を起動します

とても簡単です。

moby run linuxkit

以下のような表示になるまで待ちましょう

Welcome to LinuxKit

                        ##         .
                  ## ## ##        ==
               ## ## ## ## ##    ===
           /"""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
           \______ o           __/
             \    \         __/
              \____\_______/


/ # [    2.449400] IPVS: Creating netns size=2104 id=1
[    2.449828] IPVS: ftp: loaded support on port[0] = 21
[    2.699956] IPVS: Creating netns size=2104 id=2
[    2.700419] IPVS: ftp: loaded support on port[0] = 21
[    3.408548] clocksource: Switched to clocksource tsc

LinuxKit をさわってみる

動いているものの確認

デモにもありましたが、プロセスはこんな感じ。

/ # pstree
init-+-containerd-+-containerd-shim---nginx---nginx
     |            `-containerd-shim---tini---rngd
     |-containers---2*[ctr]
     |-sh---pstree
     `-sh

containerd が見えますが、runc からコンテナの状態も確認できます。

/ # runc list
ID          PID         STATUS      BUNDLE                        CREATED                        OWNER
nginx       543         running     /run/containerd/linux/nginx   2017-04-18T22:12:11.1635803Z   root
rngd        599         running     /run/containerd/linux/rngd    2017-04-18T22:12:11.3155512Z   root

コンテナへアクセス

まず host ネットワーク上で nginx コンテナが動いているので HTTP リクエストをローカルホストに送信してみます。

/ # wget -qO - 127.0.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

設定値を runc 経由で確認してみます。

/ # runc exec nginx cat /etc/nginx/conf.d/default.conf
server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

LinuxKit 上で Docker を動かす

LinuxKit は読み込み専用で起動する設定になっているため ファイルに書き込むような操作は何もできません。

そこで、Nginx の代わりに Docker が起動する設定の LinuxKit を起動してみます。

ビルドと起動

リポジトリにある このサンプル を使ってビルド・起動します。 (Docker イメージがちゃんと保存されるようになっている)

$ moby build docker.yml
$ moby run docker

起動した Docker サービスコンテナに接続1

VM の中に起動している Docker サービスに runc exec で sh プロセスを起動して、-t でターミナルをアタッチします。

/ # runc exec -t docker sh

Docker 内の挙動を確認

dind ならぬ docker in runc 状態ですが、 docker コマンドが打てるこの安心感。

/ # docker system info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 1
Server Version: 17.04.0-ce
Storage Driver: overlay2
 Backing Filesystem: tmpfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary:
containerd version: 422e31ce907fd9c3833a38d7b8fdd023e5a76e73
runc version: 9c2d8d184e5da67c95d601382adf14862e4f2228
init version: 949e6fa
Security Options:
 seccomp
  Profile: default
Kernel Version: 4.9.22-moby
Operating System: Alpine Linux v3.5 (containerized)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 992.5MiB
Name: moby-025000000008
ID: NIKL:AY2Z:MQQL:OJYX:6OZD:BKYA:T3ZT:TKJF:T5XD:C46N:N5BF:V7ZZ
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

Docker コンテナの起動

df -h するとわかりますが、ここまでの流れで起動した VM は ディスク容量がとても少ないのであまり遊べません。 というわけで node.js あたりを。

docker run --rm -it node:7.9-alpine sh

普通に使えますね。

/ # node -v
v7.9.0
/ # node
> 1+1;
2

この時点で、こんなことになってます。

Mac -> LinuxKit + docker -> Node.js コンテナ -> Node.js REPL

なので、Mac まで戻るには

Ctrl + D -> Ctrl + D -> Ctrl + D -> halt

です。

  1. @abeq さんにご指摘いただきました。これが抜けていたらまずいですね。失礼しました・・