コンテナからホストの情報見える問題

コンテナ内でコマンドを実行したときに、コンテナのリソースと思いきやホストのリソースを見ていることがある。 たとえば 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

というのを調べてる最中に以下の記事を見つけた。目指せ完全仮想化!(冗談です)

blog.inductor.me