dshimizu/blog

アルファ版

Control groups、Namespace、Capabilitiesを使ってコンテナを作って実行してみる

コンテナの仕組みについての学習の一貫で、以下の記事を読みながらControl groups、Namespace、Capabilitiesを使ってコンテナを作って動かしてみる。

コンテナで使うファイルシステムの準備

/tmp以下に適当なディレクトリを作成する。 次の手順でここにファイルを展開する。

$ ROOTFS=$(mktemp -d)

CentOS7のイメージを取得する。Dockerコマンドを使っているが、コンテナを作るためでなく、このイメージからファイルシステムを抽出するために使用する。

$ CID=$(sudo docker container create centos:centos7)

取得したイメージからファイルシステムを抽出し、/tmp以下にディレクトリへ展開する。

$ sudo docker container export $CID | tar -x -C $ROOTFS

以下のようにファイルが展開されている。

$ ls -lht /tmp/tmp.D4ipCfPw3e/
合計 68K
drwxr-xr-x  4 hogehoge hogehoge 4.0K  7月 11 05:00 dev
drwxr-xr-x 47 hogehoge hogehoge 4.0K  7月 11 05:00 etc
-rw-r--r--  1 hogehoge hogehoge  12K  5月  4 15:37 anaconda-post.log
dr-xr-x---  2 hogehoge hogehoge 4.0K  5月  4 15:37 root
drwxr-xr-x 11 hogehoge hogehoge 4.0K  5月  4 15:37 run
drwxrwxr-x  7 hogehoge hogehoge 4.0K  5月  4 15:37 tmp
drwxr-xr-x 18 hogehoge hogehoge 4.0K  5月  4 15:36 var
lrwxrwxrwx  1 hogehoge hogehoge    7  5月  4 15:35 bin -> usr/bin
lrwxrwxrwx  1 hogehoge hogehoge    7  5月  4 15:35 lib -> usr/lib
lrwxrwxrwx  1 hogehoge hogehoge    9  5月  4 15:35 lib64 -> usr/lib64
lrwxrwxrwx  1 hogehoge hogehoge    8  5月  4 15:35 sbin -> usr/sbin
drwxr-xr-x 13 hogehoge hogehoge 4.0K  5月  4 15:35 usr
drwxr-xr-x  2 hogehoge hogehoge 4.0K  5月  4 15:35 proc
drwxr-xr-x  2 hogehoge hogehoge 4.0K  5月  4 15:35 sys
drwxr-xr-x  2 hogehoge hogehoge 4.0K  4月 11  2018 home
drwxr-xr-x  2 hogehoge hogehoge 4.0K  4月 11  2018 media
drwxr-xr-x  2 hogehoge hogehoge 4.0K  4月 11  2018 mnt
drwxr-xr-x  2 hogehoge hogehoge 4.0K  4月 11  2018 opt
drwxr-xr-x  2 hogehoge hogehoge 4.0K  4月 11  2018 srv

Dockerコマンドで取得したコンテナイメージは不要なので消す。

$ sudo docker container rm $CID
af28f3a824658aae61673120265b28fb63c6e60e62526bd47d3c9dcdaa1551fc

コントロールグループ作成

適当な名前をつけるためにUUIDを使う。

$ UUID=$(uuidgen)

cpu,memoryのコントロールグループを作成する。名称にUUIDを利用する。

$ sudo cgcreate -t $(id -un):$(id -gn) -a $(id -un):$(id -gn) -g cpu,memory:$UUID

以下で確認できる。

$ cat /proc/self/cgroup

このグループ内の全てのプロセスのメモリ使用量を 10 MB に設定する。

$ cgset -r memory.limit_in_bytes=10000000 $UUID

CPUを利用可能な時間の上限値を1秒に設定する。

$ cgset -r cpu.cfs_period_us=1000000 $UUID
$ cgset -r cpu.cfs_quota_us=300000 $UUID

cgexec で指定したcgroupの設定に対して、 unshare で新しいシェルを呼び出し、その中で、現在使っているttyとptmxをコンテナ側のファイルシステムにマウント&リンクを張ったり(これによってコンテナを現在の疑似端末を使って制御できる)、/dev/null を作成したりホスト名を設定する。 unshare は親プロセスのNamespace(名前空間)を共有せずにプログラムを実行するためのコマンド。

$ cgexec -g cpu,memory:$UUID \
   unshare -muinpfr /bin/sh -c "
    mount -t proc proc $ROOTFS/proc &&
    touch $ROOTFS$(tty); mount --bind $(tty) $ROOTFS$(tty) &&
    touch $ROOTFS/dev/pts/ptmx; mount --bind /dev/pts/ptmx $ROOTFS/dev/pts/ptmx &&
    ln -sf /dev/pts/ptmx $ROOTFS/dev/ptmx &&
    touch $ROOTFS/dev/null && mount --bind /dev/null $ROOTFS/dev/null &&
    /bin/hostname $UUID &&
    exec capsh --chroot=$ROOTFS --drop=cap_sys_chroot -- -c 'exec /bin/sh'
  "

これで以下のようなプロンプトが表示される。

sh-4.2#

削除

コンテナを停止させて cgroup やファイルシステムを削除する。

sh-4.2# exit

$ sudo cgdelete -r -g cpu,memory:$UUID
$ rm -rf $ROOTFS

まとめ

コンテナの仕組みの勉強のため、以下の記事や参考リンクを見ながらcgroupとNamespaceでコンテナを動かしてみた。 仕組みの理解が進んだのと同時にdockerの便利さや凄さも実感できた。

参考