CLOVER🍀

That was when it all began.

Dockerで、PID名前空間を他のコンテナと共有する

「docker container run」コマンドの、「--pid」というオプションを知らなかったので。

$ docker container run --help | grep 'pid '
      --pid string                     PID namespace to use

こちらを使うと、指定したコンテナ(ホストも可)とPID名前空間を共有できるようです。

docker run | Docker Documentation

docker container run | Docker Documentation

ちょっと試してみましょう。

例えば、nginxのコンテナを起動してみます。コンテナ名は、「nginx」としました。

$ docker container run -it --rm --name nginx nginx:1.17.0

ここでもうひとつ、Dockerコンテナを起動してみましょう。Ubuntu Linux 18.04 LTSのイメージを使います。

$ docker container run -it --rm --name ubuntu --pid=container:nginx ubuntu:18.04 bash

この時、「--pid:container:[コンテナ名]」を指定して起動します。

すると、Ubuntu Linuxのコンテナ側から「--pid」で指定したコンテナのプロセスを見ることができます。

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 13:11 pts/0    00:00:00 nginx: master process nginx -g daemon off;
101          6     1  0 13:11 pts/0    00:00:00 nginx: worker process
root         7     0  1 13:13 pts/0    00:00:00 bash
root        17     7  0 13:13 pts/0    00:00:00 ps -ef

1度抜けて、「--pid」オプションの指定を外してみましょう。

$ docker container run -it --rm --name ubuntu ubuntu:18.04 bash

nginxのプロセスが見えなくなります。そりゃあそうですよね。

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0 13 13:13 pts/0    00:00:00 bash
root        10     1  0 13:13 pts/0    00:00:00 ps -ef

「--pid:container:」の後に指定するのはコンテナのIDでも、もちろんOKです。

$ docker container run -it --rm --name ubuntu --pid=container:653933fbb169 ubuntu:18.04 bash
# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 13:11 pts/0    00:00:00 nginx: master process nginx -g daemon off;
101          6     1  0 13:11 pts/0    00:00:00 nginx: worker process
root        33     0  6 13:17 pts/0    00:00:00 bash
root        42    33  0 13:17 pts/0    00:00:00 ps -ef

ちなみに、この状態で共有しているのはPIDの名前空間であり、他のコンテナのファイルなどが見えたりするわけではありません。

# ls -l /etc/nginx 
ls: cannot access '/etc/nginx': No such file or directory

確認のため、nginxコンテナ側へ「docker container exec」。

$ docker exec -it nginx ls -l /etc/nginx
total 40
drwxr-xr-x 2 root root 4096 Jun 11 00:03 conf.d
-rw-r--r-- 1 root root 1007 May 21 14:23 fastcgi_params
-rw-r--r-- 1 root root 2837 May 21 14:23 koi-utf
-rw-r--r-- 1 root root 2223 May 21 14:23 koi-win
-rw-r--r-- 1 root root 5231 May 21 14:23 mime.types
lrwxrwxrwx 1 root root   22 May 21 14:45 modules -> /usr/lib/nginx/modules
-rw-r--r-- 1 root root  643 May 21 14:45 nginx.conf
-rw-r--r-- 1 root root  636 May 21 14:23 scgi_params
-rw-r--r-- 1 root root  664 May 21 14:23 uwsgi_params
-rw-r--r-- 1 root root 3610 May 21 14:23 win-utf

で、これでなにが嬉しいかというと、たとえばlsofなどのコマンドを使ってプロセスの情報を確認したりできるわけですね。

# apt update -y && apt install lsof -y
# lsof -p 1 | head -n 10
COMMAND PID USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
nginx     1 root  cwd    DIR  0,103     4096 15350471 /
nginx     1 root  rtd    DIR  0,103     4096 15350471 /
nginx     1 root  txt    REG  0,103  1322024 15220792 /usr/sbin/nginx
nginx     1 root  mem    REG    8,8          15220792 /usr/sbin/nginx (stat: No such file or directory)
nginx     1 root  mem    REG    8,8          14824535 /lib/x86_64-linux-gnu/libnss_files-2.24.so (stat: No such file or directory)
nginx     1 root  mem    REG    8,8          14824539 /lib/x86_64-linux-gnu/libnss_nis-2.24.so (stat: No such file or directory)
nginx     1 root  mem    REG    8,8          14824511 /lib/x86_64-linux-gnu/libnsl-2.24.so (stat: No such file or directory)
nginx     1 root  mem    REG    8,8          14824520 /lib/x86_64-linux-gnu/libnss_compat-2.24.so (stat: No such file or directory)
nginx     1 root  mem    REG    8,8          14818351 /lib/x86_64-linux-gnu/libc-2.24.so (stat: No such file or directory)

sysstatなどを使っても良いでしょう。

# apt install sysstat -y
# mpstat -P ALL 1

こういう各種ツールなどを入れたコンテナを、別コンテナのデバッグに使ったりするのとかも、ありなのかなーと。

プロセスにアタッチするようなstraceとかを使いたかったら、「--cap-add sys_ptrace」でSYS_PTRACE Capabilityを与えておく
必要があります。

$ docker container run -it --rm --name ubuntu --pid=container:nginx --cap-add sys_ptrace ubuntu:18.04 bash

Javaでjcmdやjstackで他のコンテナのJavaプロセスにアクセスしたい場合も、「--cap-add sys_ptrace」を付けておく必要が
ありそうです。

事前に、やりたいことができるかどうかは確認しておいた方が良さそうですね。それでも、知っておくと便利かなと。

また、「--pid」で指定する値を「host」にすると、ホスト側のPID名前空間を共有することができます。

$ docker container run -it --rm --name ubuntu --pid=host ubuntu:18.04 bash

このオプションを知ったのは、こちらの本を見ていて「サイドカー」の紹介で使われていて、こういうオプションがあるんだなぁ
と思って試してみたくなったのがきっかけです。

分散システムデザインパターン ―コンテナを使ったスケーラブルなサービスの設計

分散システムデザインパターン ―コンテナを使ったスケーラブルなサービスの設計

こちらでは、あるコンテナに対して、別のコンテナを使って能力を付け加えるような形で紹介されていました。

なお、tcpdumpのようなネットワーク系の場合は、対象のコンテナと同じネットワークに参加する必要があるみたいです。
いろいろ調べておくと、デバッグ時に便利そうですね。