「Linux Container Book Linuxコンテナがわかる本」を読んだ
2023-03-01
コンテナ周りの理解を深めたいと思い読むことにした。
メモを残しておく。
Linux Container Book (1) Namespace / Network 編
目次
コンテナのファイルシステム
コンテナの概要から説明が入り、第2章コンテナのファイルシステムに入っていく。
この章ではchroot
,pivot_root
,bind mount
あたりの説明がされていた。
chroot
の場合環境内からさらにchroot
することで隔離空間を抜け出せてしまうのでコンテナの要件としてはpivot_root
を使用する必要がある。ただpivot_root
を使うにはいくつかの条件があり、その中の1つとしてnew_rootはmount pointである
という条件があり、これを回避するためにはbind mount
を使えばよいという話だと解釈した。
Namespace
第3章ではNamespace
全体の話がされており、次章から各Namespace
を見ていくという流れ。
以下のような話がまとめられている。
Namespace
はunshare
コマンドで操作する- ネットワークも
unshare
で操作できるが、iproute2
に含まれているip nets
を使うのが便利
- ネットワークも
/proc/[PID]/ns
でプロセスが所属しているNamespace
は確認できる
Mount Namespace
第4章では実際にpivot_root
,bind mount
を使用して隔離環境を作成していく。
それに加え、mount propagation
やmountinfo
、systemd
の話や実験も書かれている。
mount propagation
は「2つのマウントがあった場合お互いに反映させるかさせないかの設定のようなもの」と記載されており、以下の設定があるとのこと。
- shared
- private
- slave
- unbindable
また上記それぞれに対してr
prefix(i.e. rshared
)で再e帰的に反映させるかの設定ができるようだ。
このあたりの設定は/proc/[PID]/mountinfo
で確認できる。
この章末にかかれているsystemd
とmount propagation
の関係は全く知らず勉強になった。
雑に書くとsystemd
のv188でmount propagation
がdefaultrshared
になり、これをうけてutil-linux
のv2.27では作成したnamespace
はdefaultprivate
になる。という話と解釈した。systemd
が変更した理由などをissue
漁って見ると学びがあるかもしれない。
PID namespace
UTS
, IPC
のnamespaceが第5章、第6章で説明され、第7章ではPID namespace
の説明がある。
ここでは以下のコマンドで新たなprocessのPID
が1となることを確認する。
sudo unshare --pid --mount --fork --mount-proc /bin/bash
User Namespace
これによりコンテナ内では特権を持ち、ホストOS上では特権を持たないユーザが作成できる。
またそれらのマッピングは/proc/[PID]/uid_map
,/proc/[PID]/gid_map
で行うことが分かった。
formatは以下。
(Namespace内の最初のID) (Namespace外の最初のID) (範囲)
このマッピングがない場合は/proc/sys/kernel/overflowuid``/proc/sys/kernel/overflowgid
の値が’使用される。
コンテナのネットワーク
ここではveth
を作成し、ping
を通す実験が記載されていた。
手元で試したログは以下。veth
は互いに異なるns
に存在しないと通信できない点に注意。
Details
sudo ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth0-ct@veth0-host: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 66:08:0b:31:df:12 brd ff:ff:ff:ff:ff:ff
7: veth0-host@veth0-ct: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 3a:19:da:b7:28:c6 brd ff:ff:ff:ff:ff:ff
sudo ip addr add 10.10.10.10/24 dev veth0-host
sudo ip addr add 10.10.10.11/24 dev veth0-ct
sudo ip link set up veth0-host
sudo ip link set up veth0-ct
sudo ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth0-ct@veth0-host: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 66:08:0b:31:df:12 brd ff:ff:ff:ff:ff:ff
7: veth0-host@veth0-ct: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 3a:19:da:b7:28:c6 brd ff:ff:ff:ff:ff:ff
sudo ip addr show
6: veth0-ct@veth0-host: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 66:08:0b:31:df:12 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.11/24 scope global veth0-ct
valid_lft forever preferred_lft forever
inet6 fe80::6408:bff:fe31:df12/64 scope link
valid_lft forever preferred_lft forever
7: veth0-host@veth0-ct: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 3a:19:da:b7:28:c6 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.10/24 scope global veth0-host
valid_lft forever preferred_lft forever
inet6 fe80::3819:daff:feb7:28c6/64 scope link
valid_lft forever preferred_lft forever
ping -I veth0-host 10.10.10.11
PING 10.10.10.11 (10.10.10.11) from 10.10.10.10 veth0-host: 56(84) bytes of data.
From 10.10.10.10 icmp_seq=1 Destination Host Unreachable
From 10.10.10.10 icmp_seq=2 Destination Host Unreachable
From 10.10.10.10 icmp_seq=3 Destination Host Unreachable
sudo ip netns add netns01
sudo ip netns list
netns01
sudo ip link set veth0-ct netns netns01
sudo ip link show | grep veth0
7: veth0-host@if6: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
sudo ip netns exec netns01 ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth0-ct@if7: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 66:08:0b:31:df:12 brd ff:ff:ff:ff:ff:ff link-netnsid 0
sudo ip netns exec netns01 ip addr add 10.10.10.11/24 dev veth0-ct
sudo ip netns exec netns01 ip link set veth0-ct up
sudo ip netns exec netns01 ip addr show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth0-ct@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 66:08:0b:31:df:12 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.10.10.11/24 scope global veth0-ct
valid_lft forever preferred_lft forever
inet6 fe80::6408:bff:fe31:df12/64 scope link
valid_lft forever preferred_lft forever
ping -I veth0-host 10.10.10.11
PING 10.10.10.11 (10.10.10.11) from 10.10.10.10 veth0-host: 56(84) bytes of data.
64 bytes from 10.10.10.11: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 10.10.10.11: icmp_seq=2 ttl=64 time=0.065 ms
64 bytes from 10.10.10.11: icmp_seq=3 ttl=64 time=0.086 ms
最後にホストと同じネットワークにコンテナを接続するためにmacvlan
というインターフェースを使うという話が書かれている。
この辺は以下も合わせて読むと良さそう。
まとめ
以前Writing a container in Rustをやったときに出てきた内容がクリアになってよかった。この機会にもう一度Writing a container in Rustをやってみようと思う。
以上。