コンテナ内でコマンドを実行したときに、コンテナのリソースと思いきやホストのリソースを見ていることがある。 たとえば free コマンドはコンテナでもホストでも同じ実行結果になる。(EC2 の Ubuntu20.04LTS に docker.io 入れて検証)
host $ free -h
total used free shared buff/cache available
Mem: 978Mi 249Mi 152Mi 0.0Ki 576Mi 582Mi
Swap: 0B 0B 0B
container /# free -h
total used free shared buff/cache available
Mem: 978Mi 249Mi 152Mi 0.0Ki 576Mi 582Mi
Swap: 0B 0B 0B
これは
- 実行しているコマンドが proc などのシステムワイドな情報を見ている
- namespaces で proc が分離されていない
ために起こる。たとえば free は /proc/meminfo を参照するが、これはコンテナに割り当てられたリソースとは関係なくホストの値を表示している。 (cgroup インタフェースを経由すれば、コンテナに割り当てられた情報を取得できるが、あまり対応されてかったりする)
// メモリ割り当てを 100M に制限しても、MemTotal が 1000M で表示される
host $ sudo docker run --rm -it -m 100M ubuntu /bin/bash
WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.
container /# apt update
container /# apt install strace
container /# LANG=C strace -e openat free -h
...
openat(AT_FDCWD, "/proc/meminfo", O_RDONLY) = 3
total used free shared buff/cache available
Mem: 978Mi 251Mi 119Mi 0.0Ki 607Mi 581Mi
Swap: 0B 0B 0B
+++ exited with 0 +++
container /# cat /proc/meminfo
MemTotal: 1002052 kB
MemFree: 86708 kB
MemAvailable: 599920 kB
これにハマってあわあわしないためにはコマンドがどのようにリソース情報を取得しているか、とともに、 どういったファイルが namespaces ごとに分離されているのかを把握する必要がある。 会社では網羅的に調べる時間がないので、今回 man を見ながらザーッと調べた。正確な情報は man namespaces(7) を見てください。
ネームスペース | ディレクトリ | 備考 |
---|---|---|
IPC | /proc/sys/fs/mqueue、/proc/sys/kernel/{msgmax, msgmnb, msgmni, sem, shmall, shmmax, shmmni, shm_rmid_forced}、/proc/sysvipc | mq_xxx(2) の mq 系のシステムコールも分離される |
Network | /proc/net、/sys/class/net | AF_NETLINK の IPv4/IPv6 や ルーティングテーブル や ファイアウォールも分離される |
Mount | /proc/[pid]/mounts、/proc/[pid]/mountstats | mount(2)、umount(2) などのシステムコールも分離される |
PID | /proc/[pid] | 所属している pid のプロセスだけが見える |
User | /proc/[pid]/uid_map、/proc/[pid]/gid_map | あんまり調べられてない |
UTS | - | sethostname(2)、setdomainname(2)、uname(2)、gethostname(2)、getdomainname(2) などのシステムコールも分離される |
ということで、逆に以下のようなファイルはホストと同一になる。ので注意。
- /proc/cpuinfo
- /proc/meminfo
- /proc/vmstat
- /proc/zoneinfo
- /proc/softirqs
- /proc/buddyinfo
- /proc/cmdline
- /proc/modules
- /proc/uptime
- /proc/loadavg
というのを調べてる最中に以下の記事を見つけた。目指せ完全仮想化!(冗談です)
新しいLinux namespaceである「CPU Namespace」について - inductor’s blogblog.inductor.me