コンテナ標準仕様に基づいたランタイム「runC」を試す

Jul 15, 2015   #runC  #docker  #container  #Open Container Project 

DockerはDockerCon2015(6月22日)に、runCを発表しました。 runCとは、同時に発表されたコンテナ標準化の団体「Open Container Project」の仕様に基づいたコンテナランタイムです。

Webサイトはこちらで、ソースコードもGitHubで公開されています。

まだまだ鋭意開発中の段階ですが、注目すべきは下記の機能でしょうか。

  • ライブマイグレーションのサポート
  • Windowsコンテナのサポート

とりあえず、単純にコンテナを動かすところまでやってみましょう。 ディストリはFedora22@EC2です。

準備もろもろとGo言語をインストール

runCは現時点ではパッケージで入れられないので、Goで書かれたソースから入れます。 まずはGo他必要なものを入れましょう。

yum install -y wget git make gcc
wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz
tar xvzf go1.4.2.linux-amd64.tar.gz

.bashrcに下記を追記します。

export GOROOT=$HOME/go
export GOOS=linux
export GOARCH=amd64
export GOBIN=/bin
export PATH=$PATH:$GOROOT/bin
export GOPATH=$PATH

再ログインして環境変数を適用すれば、下準備はOKです。

runCを入れる

GitHubからcloneしてmakeします。

mkdir -p ~/go/src/github.com/opencontainers
cd /go/src/github.com/opencontainers
git clone https://github.com/opencontainers/runc
cd runc
make
make install

これまでの手順で/usr/local/bin/runcが作られたかと思います。 バージョンを確認すると0.2でした。

runc -v
runc version 0.2

コンテナの元ファイルを用意する

現時点の実装では、runCはイメージからコンテナを起動できません。 イメージ内のファイルが展開されたディレクトリを指定して、コンテナを立ち上げるイメージです。

必要なファイルの展開は、Dockerを使うと簡単にできます。

まずは普通にDockerを入れます。

yum install -y docker
systemctl start docker

centosのベースイメージでコンテナを起動し、docker exportでtarにします。 また、tarを~/runc/centosに展開します。

docker run -d --name runc-centos centos
docker export runc-centos > runc-centos.tar
mkdir -p ~/runc/centos
tar xvf runc-centos.tar -C ~/runc/centos

展開すると、下記の状態となります。 ベースイメージに含まれていたファイルが丸々表示されます。

pwd
/root/runc/centos

ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

上記の状態になれば、エクスポートしたtarやDockerは不要なので止めておきます。

docker stop runc-centos
docker rm runc-centos
rm ~/runc-centos.tar
systemctl stop docker

コンテナの定義ファイルを作成する

Dockerと違ってコンテナの定義ファイルを作る必要があります。 作ると言っても生成してくれる仕組みがあり、先ほどエクスポートした先のディレクトリでrunc specを実行するだけです。

cd ~/runc/centos
runc spec > config.json

実行すると下記のファイルが作られます。

{
  "version": "pre-draft",
  "platform": {
    "os": "linux",
    "arch": "amd64"
  },
  "process": {
    "terminal": true,
    "user": {
      "uid": 0,
      "gid": 0,
      "additionalGids": null
    },
    "args": [
      "sh"
    ],
    "env": [
      "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
      "TERM=xterm"
    ],
    "cwd": ""
  },
  "root": {
    "path": "rootfs",
    "readonly": true
  },
  "hostname": "shell",
  "mounts": [
    {
      "type": "proc",
      "source": "proc",
      "destination": "/proc",
      "options": ""
    },
    {
      "type": "tmpfs",
      "source": "tmpfs",
      "destination": "/dev",
      "options": "nosuid,strictatime,mode=755,size=65536k"
    },
    {
      "type": "devpts",
      "source": "devpts",
      "destination": "/dev/pts",
      "options": "nosuid,noexec,newinstance,ptmxmode=0666,mode=0620,gid=5"
    },
    {
      "type": "tmpfs",
      "source": "shm",
      "destination": "/dev/shm",
      "options": "nosuid,noexec,nodev,mode=1777,size=65536k"
    },
    {
      "type": "mqueue",
      "source": "mqueue",
      "destination": "/dev/mqueue",
      "options": "nosuid,noexec,nodev"
    },
    {
      "type": "sysfs",
      "source": "sysfs",
      "destination": "/sys",
      "options": "nosuid,noexec,nodev"
    }
  ],
  "linux": {
    "uidMappings": null,
    "gidMappings": null,
    "rlimits": null,
    "sysctl": null,
    "resources": {
      "disableOOMKiller": false,
      "memory": {
        "limit": 0,
        "reservation": 0,
        "swap": 0,
        "kernel": 0,
        "swappiness": 0
      },
      "cpu": {
        "shares": 0,
        "quota": 0,
        "period": 0,
        "realtimeRuntime": 0,
        "realtimePeriod": 0,
        "cpus": "",
        "mems": ""
      },
      "blockIO": {
        "blkioWeight": 0,
        "blkioWeightDevice": "",
        "blkioThrottleReadBpsDevice": "",
        "blkioThrottleWriteBpsDevice": "",
        "blkioThrottleReadIopsDevice": "",
        "blkioThrottleWriteIopsDevice": ""
      },
      "hugepageLimits": null,
      "network": {
        "classId": "",
        "priorities": null
      }
    },
    "namespaces": [
      {
        "type": "process",
        "path": ""
      },
      {
        "type": "network",
        "path": ""
      },
      {
        "type": "ipc",
        "path": ""
      },
      {
        "type": "uts",
        "path": ""
      },
      {
        "type": "mount",
        "path": ""
      }
    ],
    "capabilities": [
      "AUDIT_WRITE",
      "KILL",
      "NET_BIND_SERVICE"
    ],
    "devices": [
      "null",
      "random",
      "full",
      "tty",
      "zero",
      "urandom"
    ]
  }
}

ただし、このままだと動作しません。 root > pathが環境に合ってないので変更します。

変更前:

  "root": {
    "path": "rootfs",
    "readonly": true
  },

変更後:

  "root": {
    "path": "/root/runc/centos",
    "readonly": true
  },

コンテナを起動する

config.jsonがあるディレクトリでruncを実行するとコンテナが起動します。

[root@ip-172-31-11-34 centos]# runc
sh-4.2#
sh-4.2# hostname
shell
sh-4.2#
sh-4.2# ps
  PID TTY          TIME CMD
    1 ?        00:00:00 sh
   14 ?        00:00:00 ps
sh-4.2#
sh-4.2# pwd
/
sh-4.2#
sh-4.2# ls
bin  config.json  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
sh-4.2#
sh-4.2# ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
sh-4.2#

コンテナ内のプロセスしか見えず、ファイルも再現できていますね。 今後の開発が楽しみです。