ようへいの日々精進XP

よかろうもん

Docker コンテナランタイムについて少しだけ勉強した (6)

tl;dr

会社から借りっぱなしの Software Design 2020 年 2 月号で特集されている Docker コンテナランタイムについての記事を読んでみたメモです.

gihyo.jp

読みながら気になる単語や内容をマインドマップにまとめていきたいと思います.

今回は runc における環境隔離の仕組み (namespace) について見ていきます (手を動かしていきます).

マインドマップ

f:id:inokara:20200425003754p:plain

ハンズオンメモ

検証環境

ホスト側の 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 奥深い. 今まで雰囲気でしか知らなかったことが, こうやって手を動かすと少しだけ踏み込んで理解することが出来ました.