KubernetesでPodのネットワークパケットキャプチャを行う

# 概要

KubernetesのPodを出入りするネットワークパケットを収集して分析する方法を紹介します。

Kubernetesでは1つのPod内に複数のコンテナを起動することができ（Sidecarと呼びます）、Pod内のコンテナは同じNICを共有します。

この仕組みを利用して、対象のPodにパケット収集用コンテナを追加し、そのコンテナの中でパケット収集処理を実行します。

![スクリーンショット 2022-05-03 12.04.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268124/ae180e2b-b16c-8285-533d-cc30cab1f1e2.png)

今回は下記の流れでパケットの収集と分析を行います。

- パケット収集用コンテナにて、収集処理を実行して結果をファイル出力する。
- ホストにて、`kubectl cp`コマンドを使って収集結果ファイルをホストにコピーする。
- ホストにて、[Wireshark](https://www.wireshark.org/)を使ってコピーしたファイルを分析する。

> Wiresharkは事前にインストールしてください。

# パケット収集用コンテナをPodに追加

パケット収集用コンテナに使うDockerイメージは何でも良いのですが、今回は[nicolaka/netshoot](https://github.com/nicolaka/netshoot)を使います。（ネットワーク関連の様々なコマンドがインストール済みであり、ネットワーク分析用として有名なイメージです。）

例えば下記のようなyamlファイルを作る事で、netshootという名前のパケット収集用コンテナを含むPodをDeploymentとして作成できます。

```yaml
---
apiVersion: apps/v1
kind: Deployment
...
spec:
  ...:
  template:
    ...:
    spec:
      containers:
        # アプリケーションコンテナ（収集対象）
        - name: ...
          image: ...
          ...:
        # パケット収集用コンテナ
        - name: netshoot
          image: nicolaka/netshoot
          imagePullPolicy: IfNotPresent
          command: ["/bin/bash"]
          args: ["-c", "while true; do ping localhost; sleep 60; done"]
```

> `command`および`args`の箇所では、コンテナを起動させ続けるために永続的なコマンドを実行するよう定めています。

# パケットを収集

netshootコンテナを含むPodをKubernetesにデプロイしたのち、下記コマンドでnetshootコンテナにログインします。

```bash
kubectl exec <Pod名> -c netshoot -it -- /bin/bash
```

> 今回のようにPod内に複数のコンテナがある場合は、`-c`オプションでログインしたいコンテナの名前を指定できます。

> Namespaceがdefault以外の場合は、`-n <Namespace名>`オプションを追加します。

ログインしたnetshootコンテナの中でifconfigコマンドを実行し、パケット収集対象のNICを探します。

```bash
ifconfig
```

出力結果が下記の場合は、eth0という名前のNICを対象にすれば良いとわかります。

```
eth0      Link encap:Ethernet  HWaddr 4E:1D:AF:72:EF:4B  
          inet addr:10.1.0.88  Bcast:10.1.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:19 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1398 (1.3 KiB)  TX bytes:42 (42.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:11832 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11832 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:993888 (970.5 KiB)  TX bytes:993888 (970.5 KiB)
```

> loはループバック用のNICです。

> アプリケーションコンテナでもifconfigコマンドが実行可能であれば、アプリケーションコンテナにログインしてifconfigコマンドを実行すると、同一のeth0というNICがある事を確認できます。

tcpdumpコマンドを実行して、パケット収集処理を起動します。

```bash
tcpdump -i eth0 -w tcpdump.out
```

> `-i`オプションで対象のNICを、`-w`オプションで収集結果の出力先ファイル名を指定します。

パケット収集処理を起動したままの状態で、ホストからアプリケーションにアクセスして動作させます。

アプリケーションの動作が一通り完了したら、netshootコンテナの中で`Ctrl + C`を入力してパケット収集処理を停止します。

netshootコンテナの中でlsコマンドおよびpwdコマンドを使って、収集結果ファイルの絶対パスを確認します。

> 出力結果が下記の場合は、`/root/tcpdump.out`に収集結果ファイルがあることがわかります。

```
bash-5.1# ls
motd         tcpdump.out
bash-5.1# pwd
/root
```

# 収集結果を分析

ホスト側で`kubectl cp`コマンドを実行して、収集結果ファイルをホストにコピーします。

```bash
kubectl cp <Pod名>:/root/tcpdump.out tcpdump.out -c netshoot
```

> `-c`オプションでコピー対象のコンテナを指定します。

> Namespaceがdefault以外の場合は、`<Namespace名>/<Pod名>:/root/tcpdump.out`とします。


Wiresharkを起動し、コピーしたファイルを開くと、パケットの内容を確認できます。

![スクリーンショット 2022-05-03 13.53.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268124/537761ce-be77-21a9-9235-1c4c4158aab2.png)

上記の例について、パケット分析の詳細は割愛しますが、概要は下記の通りとなります。

- Kubernetesにはfront1とback1という2つのPodがあり、今回はfront1のパケットを収集している。
- ホストからfront1へHTTPリクエスト
- front1からback1へHTTPリクエスト
- back1からfront1へHTTPレスポンス
- front1からホストへHTTPレスポンス