Kubernetes環境で意図的にネットワーク遅延やパケットロスをを注入しようとしている。Linuxではtc-netem(8)を使って実現できる。コンテナ側でtcコマンドを叩こうとすると、コンテナのケイパビリティとしてNET_ADMINなどを与え直す必用があり、面倒などでノード側で特定のPodに異常を注入したい。
まずは、Kubernetesで任意のPodと対応するノード側のVethインタフェースを特定する。
```shell-session
# -- コンテナ側 --
~ kubectl iexec user
Namespace: sock-shop | Pod: ✔ user-db-795bfb6cd4-mwdfv
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
3: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc noqueue state UP group default
link/ether 2e:2f:1d:e5:d5:38 brd ff:ff:ff:ff:ff:ff
inet 10.48.0.17/24 brd 10.48.0.255 scope global eth0
valid_lft forever preferred_lft forever
$ cat /sys/class/net/eth0/iflink
20
# Node側
## GKEではtoolboxコンテナが用意されているのでログイン
$ toolbox shell-session
$ grep ^ /sys/class/net/vet*/ifindex | grep :20
/sys/class/net/veth18bcba24/ifindex:20
$ ip link | grep veth18bcba24
20: veth18bcba24@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc noqueue master cbr0 state UP mode DEFAULT group default
```
次にtcコマンドを使って、遅延を注入する。ここでは50msとする。同様にパケットロスを注入することもできる。
```shell-session
# パケット遅延を追加する
$ tc qdisc add dev veth18bcba24 root netem delay 50ms; sleep 600; tc qdisc del dev veth18bcba24 root
# パケットロスを発生させる
$ tc qdisc add dev veth18bcba24 root netem loss 2%; sleep 600; tc qdisc del dev veth18bcba24 root
```
遅延の注入時に別ノード上のpodから対象podのIPアドレスへpingをしていると、途中からほぼ50msの遅延が追加されていることがわかる。
```shell-session
$ ping 10.48.0.17
...
64 bytes from 10.48.0.17: icmp_seq=58 ttl=62 time=0.322 ms
64 bytes from 10.48.0.17: icmp_seq=59 ttl=62 time=0.245 ms
64 bytes from 10.48.0.17: icmp_seq=60 ttl=62 time=0.274 ms
64 bytes from 10.48.0.17: icmp_seq=61 ttl=62 time=50.448 ms
64 bytes from 10.48.0.17: icmp_seq=62 ttl=62 time=50.422 ms
64 bytes from 10.48.0.17: icmp_seq=63 ttl=62 time=50.503 ms
64 bytes from 10.48.0.17: icmp_seq=64 ttl=62 time=50.449 ms
...
```
対象podと同一ノード上の別のpodへpingをしていたところRTTに変化がなかったので、特定のpodのみdelayを注入できているはず。
PodとNode側のvethインタフェースの紐付けは下記を参考にした。
[Kubernetes (gke) get name of pod network interface](https://stackoverflow.com/questions/51239781/kubernetes-gke-get-name-of-pod-network-interface)
仮想ネットワーク環境でtcを使っている例は次の通り。
[Emulating Bad Networks](https://samwho.dev/blog/emulating-bad-networks/)
[Zalando Engineering Blog - PgBouncer on Kubernetes and how to achieve minimal latency](https://engineering.zalando.com/posts/2020/06/postgresql-connection-poolers.html)