IBM Cloud: nsenterを使ったコンテナ上でのデバッグ方法（Red Hat OpenShift on IBM Cloudでの例）

#1. はじめに

問題判別のために、コンテナ上でnetstatやdig、tcpdumpといったコマンドを実行したいということがあるが、そもそもこういう管理系コマンドはコンテナに標準的にインストールされていないとか、特権ユーザーで実行されていないために実行権限がないといったことの方が多い。
その一つの解決策として、OpenShiftの公式マニュアルにも掲載されている`nsenter`を使う方法がある。

- https://access.redhat.com/documentation/ja-jp/openshift_container_platform/4.8/html/support/support-collecting-network-trace_gathering-cluster-data
- https://access.redhat.com/solutions/4569211

`nsenter`は、ホスト（worker node）内部から実行し、以下の書式で実行できる。

- `-n`は`Enter the network namespace`の意味。
- `-t`でホスト上で見えるコンテナのプロセスIDを指定する。
- コマンドのバイナリは、コンテナ内ではなくホスト上のものを利用する。

```txt:nsenterの書式
# nsenter -n -t <ホスト上で見えるコンテナのプロセスID> -- <コマンド>
```

#2. Red Hat OpenShift on IBM Cloud(ROKS)で試してみる

```shell:対象のPodとそのPodが稼働しているWorkderNodeを特定する。
$ oc get pods -o wide
NAME                         READY   STATUS      RESTARTS   AGE     IP              NODE        NOMINATED NODE   READINESS GATES
samplephp-1-build            0/1     Completed   0          2d12h   172.17.37.79    10.0.0.19   <none>           <none>
samplephp-6744d5dd95-t4z7h   1/1     Running     0          2d12h   172.17.37.118   10.0.0.19   <none>           <none>
```
```shell:debugモードで対象ホストに入る。
$ oc debug node/10.0.0.19
Creating debug namespace/openshift-debug-node-r2nlj ...
Starting pod/100019-debug ...
To use host binaries, run `chroot /host`
Pod IP: 10.0.0.19
If you don't see a command prompt, try pressing enter.
sh-4.4#
```

```shell:対象コンテナのプロセスIDを取得する
sh-4.4# PODNAME=samplephp-6744d5dd95-t4z7h
sh-4.4# NAMESPACE=syasuda1
sh-4.4# pod_id=$(chroot /host crictl pods --namespace ${NAMESPACE} --name ${PODNAME} -q)
sh-4.4# pid=$(chroot /host bash -c "runc state $pod_id | jq .pid")
```

```shell:対象コンテナに対してデバッグ処理を行う。

sh-4.4# nsenter -n -t ${pid} -- tcpdump -i any port 8080 -nn
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked v1), capture size 262144 bytes
00:35:39.383664 IP 172.17.37.45.60100 > 172.17.37.118.8080: Flags [S], seq 492135834, win 28800, options [mss 1440,sackOK,TS val 359442641 ecr 0,nop,wscale 9], length 0
00:35:39.383701 IP 172.17.37.118.8080 > 172.17.37.45.60100: Flags [S.], seq 2400539639, ack 492135835, win 28560, options [mss 1440,sackOK,TS val 359442641 ecr 359442641,nop,wscale 9], length 0
00:35:39.383741 IP 172.17.37.45.60100 > 172.17.37.118.8080: Flags [R.], seq 1, ack 1, win 57, options [nop,nop,TS val 359442641 ecr 359442641], length 0
00:35:44.385499 IP 172.17.37.45.60356 > 172.17.37.118.8080: Flags [S], seq 3709303071, win 28800, options [mss 1440,sackOK,TS val 359447643 ecr 0,nop,wscale 9], length 0
00:35:44.385532 IP 172.17.37.118.8080 > 172.17.37.45.60356: Flags [S.], seq 1783180405, ack 3709303072, win 28560, options [mss 1440,sackOK,TS val 359447643 ecr 359447643,nop,wscale 9], length 0
00:35:44.385569 IP 172.17.37.45.60356 > 172.17.37.118.8080: Flags [R.], seq 1, ack 1, win 57, options [nop,nop,TS val 359447643 ecr 359447643], length 0
00:35:49.386791 IP 172.17.37.45.60478 > 172.17.37.118.8080: Flags [S], seq 148881239, win 28800, options [mss 1440,sackOK,TS val 359452644 ecr 0,nop,wscale 9], length 0
00:35:49.386822 IP 172.17.37.118.8080 > 172.17.37.45.60478: Flags [S.], seq 2906002013, ack 148881240, win 28560, options [mss 1440,sackOK,TS val 359452644 ecr 359452644,nop,wscale 9], length 0
00:35:49.386857 IP 172.17.37.45.60478 > 172.17.37.118.8080: Flags [R.], seq 1, ack 1, win 57, options [nop,nop,TS val 359452644 ecr 359452644], length 0

```



参考: 対象のPodにはtcpdumpは存在しない。

```shell
$ oc rsh samplephp-6744d5dd95-t4z7h which tcpdump
which: no tcpdump in (/opt/app-root/src/bin:/opt/app-root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)
command terminated with exit code 1
```