kakakakakku blog

Weekly Tech Blog: Keep on Learning!

docker run コマンドの --pid オプションで PID namespace を共有する

docker run コマンドで使える --pid オプションを試す.Docker では以下のドキュメントに書いてある通り,デフォルトでは PID namespace でコンテナ同士を隔離する.よって,コンテナ同士でプロセスを共有することはできず,各コンテナでは PID 1 を含む「プロセス ID」を再利用できるようになっている.今回は一歩一歩確認しながら進めていく.

docs.docker.com

PID 1 を確認する

まず,デフォルトの挙動を確認する.以下のように docker run コマンドで nginx コンテナを起動する.そして docker exec コマンドでコンテナに接続をしてプロセス一覧を確認すると,nginx プロセスが PID 1 になっていることがわかる.なお,Alpine Linux なので ps コマンドを実行できるようにしておく必要がある.

$ docker run --rm -d -it nginx:1.21
9313d4a4fc73cf2a173569d3f5f76595169c1577b242b9cf7b019afe32785df0

$ docker exec -it 9313d4a4fc73 /bin/sh

# apt update
# apt install -y procps

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 01:34 pts/0    00:00:00 nginx: master process nginx -g daemon off;
nginx       32     1  0 01:34 pts/0    00:00:00 nginx: worker process
nginx       33     1  0 01:34 pts/0    00:00:00 nginx: worker process
nginx       34     1  0 01:34 pts/0    00:00:00 nginx: worker process
nginx       35     1  0 01:34 pts/0    00:00:00 nginx: worker process
root        36     0  0 01:35 pts/1    00:00:00 /bin/sh
root       364    36  0 01:36 pts/1    00:00:00 ps -ef

次に docker run コマンドで新しく Ubuntu コンテナを起動する(今回は sleep コマンドでプロセスを常駐させておく).同じく docker exec コマンドでコンテナに接続をしてプロセス一覧を確認すると,sleep プロセスが PID 1 になっていることがわかる.よって,nginxUbuntu もコンテナ同士で隔離されていると言える.

$ docker run --rm -d -it ubuntu:21.10 /bin/sh -c 'sleep 300'
5c754ed1f167ece55849ac5760d902782f562b6815c2fff05dc472c1cb54bc35

$ docker exec -it 5c754ed1f167 /bin/sh

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 01:31 pts/0    00:00:00 /bin/sh -c sleep 300
root         8     1  0 01:31 pts/0    00:00:00 sleep 100
root         9     0  0 01:32 pts/1    00:00:00 /bin/sh
root        17     9  0 01:32 pts/1    00:00:00 ps -ef

--pid オプション

次に docker run コマンドの --pid オプションを試す.既に起動している nginx コンテナ(9313d4a4fc73)の PID namespace を共有した Ubuntu コンテナを起動するために --pid=container:9313d4a4fc73 のようにオプションを指定する.

$ docker run --rm -d --pid=container:9313d4a4fc73 -it ubuntu:21.10 /bin/sh -c 'sleep 300'

同じく docker exec コマンドで Ubuntu に接続をしてプロセス一覧を確認すると,nginx コンテナのプロセスを確認できるようになった.そして Ubuntu コンテナの sleep プロセスが PID 372 となり,PID 1 ではなくなっている.よって,コンテナ同士で PID namespace を共有できていると言える.

$ docker exec -it 06bbc0fb87f3 /bin/sh

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 01:34 pts/0    00:00:00 nginx: master process nginx -g daemon off;
101         32     1  0 01:34 pts/0    00:00:00 nginx: worker process
101         33     1  0 01:34 pts/0    00:00:00 nginx: worker process
101         34     1  0 01:34 pts/0    00:00:00 nginx: worker process
101         35     1  0 01:34 pts/0    00:00:00 nginx: worker process
root       372     0  0 02:03 pts/0    00:00:00 /bin/sh -c sleep 300
root       379   372  0 02:03 pts/0    00:00:00 sleep 300
root       380     0  0 02:04 pts/1    00:00:00 /bin/sh
root       386   380  0 02:04 pts/1    00:00:00 ps -ef

--pid オプションの活用例

では --pid オプションをどのように活用すれば良いかと言うと「サイドカー」のように使える.書籍「分散システムデザインパターン」「2章 : サイドカー」brendanburns/topz イメージを使った例が載っているので,参考にしながら試していく.

既に起動している nginx コンテナ(9313d4a4fc73)の PID namespace を共有した topz コンテナを起動する.そして http://localhost:8080/topz にリクエストを送ると,nginx コンテナのプロセス一覧とリソース使用量を確認できる.このように「プロセスのモニタリング機能」--pid オプションで「サイドカー」として追加できるという活用に繋がる.

$ docker run --rm -d --pid=container:9313d4a4fc73 -p 8080:8080 brendanburns/topz:db0fa58 /server --addr=0.0.0.0:8080

$ curl http://localhost:8080/topz
1  0 0.21145721 nginx: master process nginx -g daemon off;
32 0 0.11457208 nginx: worker process
33 0 0.11457208 nginx: worker process
34 0 0.11457208 nginx: worker process
35 0 0.11457208 nginx: worker process
36 0 0.17175984 /server --addr=0.0.0.0:8080

Docker Compose と pid オプション

今度は Docker Compose の場合にどうなるんだろう?と気になるため PID namespace を確認する.以下のように nginx コンテナと Ubuntu コンテナを含めた docker-compose.yml を作る.

version: '3.9'
services:
  nginx:
    image: nginx:1.21
  ubuntu:
    image: ubuntu:21.10
    command: sleep 300

そして docker compose up コマンドでコンテナを起動して docker compose exec コマンドで Ubuntu コンテナに接続をしてプロセス一覧を確認すると sleep プロセスが PID 1 になっている.よって,デフォルトでは PID namespace でコンテナ同士を隔離していると言える.

なお,docker-compose.ymlpid: "host" を追加すると「ホスト側」PID namespace を共有できる.実際に使う機会は少なそうだけど,ドキュメントに載っていた.そしてコンテナ同士での PID namespace 共有は Compose file version 2 reference のドキュメントには載っていたけど,Compose file version 3 reference では消えていた.

$ docker compose up

$ docker compose exec ubuntu /bin/sh

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 02:51 ?        00:00:00 sleep 300
root         7     0  0 02:52 pts/0    00:00:00 /bin/sh
root        14     7  0 02:52 pts/0    00:00:00 ps -ef

docs.docker.com

まとめ

docker run コマンドで使える --pid オプションを試した.デフォルトでは PID namespace でコンテナ同士を隔離するけど,--pid オプションで PID namespace を共有できるようになる.そして,書籍「分散システムデザインパターン」にも載っている通り,「サイドカー」のように活用することができる.

関連記事

書籍「分散システムデザインパターン」の書評記事は以下にある.合わせて読んでもらえると!

kakakakakku.hatenablog.com

また docker run コマンドには多くのオプションがある.今月公開した以下の記事では --security-opt オプションを紹介している.

kakakakakku.hatenablog.com