tl;dr
会社から借りっぱなしの Software Design 2020 年 2 月号で特集されている Docker コンテナランタイムについての記事を読んでみたメモです.
読みながら気になる単語や内容をマインドマップにまとめていきたいと思います.
今回は runc における環境隔離の仕組み (namespace) について見ていきます (手を動かしていきます).
マインドマップ
ハンズオンメモ
検証環境
ホスト側の OS は以下の通り.
$ cat /etc/os-release NAME="Ubuntu" VERSION="18.04.4 LTS (Bionic Beaver)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 18.04.4 LTS" VERSION_ID="18.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=bionic UBUNTU_CODENAME=bionic
各種ツールのバージョンは以下の通り.
$ runc --version runc version spec: 1.0.1-dev $ unshare --version unshare from util-linux 2.31.1
ただの chroot の場合
Alpine Linux を rootfs に chroot する
「Alpine Linux を rootfs に chroot する」という言い方が正しいか解らないけど, runc をいじった時に作成した Filesystem Bundle を利用してルートファイルシステムを設定してみます.
$ sudo chroot bundle/rootfs /bin/sh / # / # cat /etc/os-release NAME="Alpine Linux" ID=alpine VERSION_ID=3.11.5 PRETTY_NAME="Alpine Linux v3.11" HOME_URL="https://alpinelinux.org/" BUG_REPORT_URL="https://bugs.alpinelinux.org/"
chroot 環境で proc をマウントすると
/ # mount -t proc proc /proc / # ps aux | grep '[s]udo chroot' 7592 root 0:00 sudo chroot bundle/rootfs /bin/sh
ホスト側のプロセスが見えています. この状態では隔離されているとは言えません.
unshare を使う
unshare で隔離
-p
と -m
と -u
オプションを利用して隔離を行います.
-p
: PID namespace-m
: Mount namespace-u
: User namespace
以下, unshare 隔離した環境に chroot した実行例です.
$ unshare -pfmur chroot bundle/rootfs /bin/sh / # cat /etc/os-release NAME="Alpine Linux" ID=alpine VERSION_ID=3.11.5 PRETTY_NAME="Alpine Linux v3.11" HOME_URL="https://alpinelinux.org/" BUG_REPORT_URL="https://bugs.alpinelinux.org/"
procfs をマウントして隔離環境内のプロセスを確認しています.
/ # mount -t proc proc /proc / # ps aux PID USER TIME COMMAND 1 root 0:00 /bin/sh 4 root 0:00 ps aux
PID namespace
- ホスト側のプロセスを見ることが出来ない
- 隔離環境に閉じたプロセスツリーが作成される
- 隔離環境内の PID とホストから見える PID の 2 つが見える
以下, 隔離環境内で sleep 100
を実行して, PID を確認すると PID は 6 となっていることが判ります.
/ # sleep 100 & / # ps aux PID USER TIME COMMAND 1 root 0:00 /bin/sh 6 root 0:00 sleep 100 7 root 0:00 ps aux / #
ホスト側で確認すると, 異なる PID (14205) となっており, 隔離環境においては独自のプロセスツリーが作成されていることが判りました.
$ ps aux | grep [s]leep kappa 14205 0.0 0.0 1568 4 pts/0 S 23:52 0:00 sleep 100
Mount namespace
- 隔離環境で作成されたマウントポイントはホスト側から見えなくなる
以下, 隔離環境内で /proc
にマウントした procfs
の中身は以下のように見えます.
/ # ls /proc 1 cgroups diskstats fs kcore kpageflags modules pressure softirqs thread-self vmallocinfo 9 cmdline dma interrupts key-users loadavg mounts sched_debug stat timer_list vmstat acpi consoles driver iomem keys locks mtrr schedstat swaps tty zoneinfo asound cpuinfo execdomains ioports kmsg mdstat net scsi sys uptime buddyinfo crypto fb irq kpagecgroup meminfo pagetypeinfo self sysrq-trigger version bus devices filesystems kallsyms kpagecount misc partitions slabinfo sysvipc version_signature / #
しかし, ホスト側にて, 隔離環境の /proc
に該当する bundle/rootfs/proc
以下には中身が無い状態になっていることが判ります.
$ ls -l bundle/rootfs/proc 合計 0
User namespace
- ホスト上のユーザー群を隔離して隔離環境内で新たなユーザー群を定義出来る
unshare
を実行したユーザーが隔離環境内ではroot
ユーザーのように振る舞うことが出来るようになる
以下, 隔離環境内で root
ユーザーで実行されている sleep
コマンドが, ホスト側からプロセスを見ると kappa
ユーザーで実行されていることが判ります.
/ # sleep 100 & / # ps aux | grep [s]leep 10 root 0:00 sleep 100 / #
ホスト側で確認. 確かに kappa
ユーザーで sleep
コマンドが実行されています.
$ ps aux | grep [s]leep kappa 14586 0.0 0.0 1568 4 pts/0 S 00:33 0:00 sleep 100
以上
namespace 奥深い. 今まで雰囲気でしか知らなかったことが, こうやって手を動かすと少しだけ踏み込んで理解することが出来ました.