Skip to content
On this page

「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を見ていくという流れ。
以下のような話がまとめられている。

  • Namespaceunshareコマンドで操作する
    • ネットワークもunshareで操作できるが、iproute2に含まれているip netsを使うのが便利
  • /proc/[PID]/nsでプロセスが所属しているNamespaceは確認できる

Mount Namespace

第4章では実際にpivot_root,bind mountを使用して隔離環境を作成していく。
それに加え、mount propagationmountinfosystemdの話や実験も書かれている。

mount propagationは「2つのマウントがあった場合お互いに反映させるかさせないかの設定のようなもの」と記載されており、以下の設定があるとのこと。

  • shared
  • private
  • slave
  • unbindable

また上記それぞれに対してrprefix(i.e. rshared)で再e帰的に反映させるかの設定ができるようだ。
このあたりの設定は/proc/[PID]/mountinfoで確認できる。

この章末にかかれているsystemdmount 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となることを確認する。

sh
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
sh
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というインターフェースを使うという話が書かれている。
この辺は以下も合わせて読むと良さそう。

macvlan ネットワークの使用

まとめ

以前Writing a container in Rustをやったときに出てきた内容がクリアになってよかった。この機会にもう一度Writing a container in Rustをやってみようと思う。

以上。