👹

Dockerコンテナ間の通信を遅延させる(ingress用制御つき)

2022/12/02に公開

この記事

早稲田大学コンピュータ研究会アドベントカレンダーとして書いた記事です。

やりたいこと

Dockerコンテナを二つ用意し、Linux traffic controllerを利用しコンテナ間のトラフィックに障害(遅延)を発生させる。
デフォルトの設定だと外向き(egress)のパケットのみに遅延が発生するため、擬似デバイスをロードして内向き(ingress)のパケットをフィルターしリダイレクトさせ、遅延を発生させる。

cat /etc/os-release

PRETTY_NAME="Ubuntu 22.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

実際に遅延を発生させる

Dockerつくる

composeファイルを用意する

docker-compose.yml
version: "3.9"
services:
  server:
    image: ubuntu:latest
    command: sleep infinity
    networks:
      - tc-test
  client:
    image: ubuntu:latest
    command: sleep infinity
    networks:
      - tc-test
networks:
  tc-test:
    external: true

コマンド

$ docker network create tc-test
55d87a017adcf714e820723fead9af950816be363bd79feedd2a5637993ac89a
$ docker compose up -d
[+] Running 2/2
 ⠿ Container trafficcontrol_sample-server-1  Started                                    0.6s
 ⠿ Container trafficcontrol_sample-client-1  Started

仮想NICの名前を確認する

$ ip a | grep 55d87 # bridgeを作った時の出力
2917: br-55d87a017adc: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    inet 172.23.0.1/16 brd 172.23.255.255 scope global br-55d87a017adc
2923: vethc780b05@if2922: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-55d87a017adc state UP group default 
2925: veth4f88b36@if2924: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-55d87a017adc state UP group default 

カーネルモジュールのロード

$ sudo modprobe ifb numifbs=1
$ sudo modprobe act_mirred

ifbは仮想通信ポートです。act_mirredはパケットのリダイレクトをしてくれるやつです。

仮想通信ポートの有効化

$ sudo ip link set dev ifb0 up

複数使いたい時はnumifbsの数を増やしてifb1,ifb2と順番に有効化してください

ifb0にパケットを回す設定

さっきゲットしたvethc780b05を使います

$ sudo tc qdisc add dev vethc780b05 handle ffff: ingress
$ sudo tc filter add dev vethc780b05 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0

障害の発生

$ sudo tc qdisc add dev vethc780b05 root handle 1: netem delay 200ms 20ms distribution normal loss 10%
$ sudo tc qdisc add dev ifb0 root handle 1: netem delay 200ms 20ms distribution normal loss 10%

これが遅延の設定です。内容は

  • 200msの遅延x2
  • 正規分布に従った10%(20ms)のジッタ
  • パケロス10%(ingress,egress双方に発生してるのでこれを2乗した値が発生します)

帯域制限をかけたいなら

$ sudo tc qdisc add dev vethc780b05 root handle 1: htb default 10
$ sudo tc class add dev vethc780b05 parent 1: classid 1:1 htb rate 1mbit
$ sudo tc class add dev vethc780b05 parent 1:1 classid 1:10 htb rate 1mbit

$ sudo tc qdisc add dev ifb0 root handle 1: htb default 10
$ sudo tc class add dev ifb0 parent 1: classid 1:1 htb rate 1mbit
$ sudo tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 1mbit

こんな感じです。細かい設定についてはまた次の機会に記事を書こうと思います。

遅延が発生しているか確認

コンテナに入る

$ docker ps
CONTAINER ID   IMAGE           COMMAND            CREATED             STATUS             PORTS     NAMES
59b053cead41   ubuntu:latest   "sleep infinity"   About an hour ago   Up About an hour             trafficcontrol_sample-server-1
2cfb9d91effe   ubuntu:latest   "sleep infinity"   About an hour ago   Up About an hour             trafficcontrol_sample-client-1
$ docker inspect 59b053cead41 | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "",
                    "IPAddress": "172.23.0.3",
$ docker compose exec client bash
# apt update
# apt install -y iputils-ping
# ping 172.23.0.3
PING 172.23.0.3 (172.23.0.3) 56(84) bytes of data.
64 bytes from 172.23.0.3: icmp_seq=2 ttl=64 time=411 ms
64 bytes from 172.23.0.3: icmp_seq=3 ttl=64 time=406 ms
64 bytes from 172.23.0.3: icmp_seq=4 ttl=64 time=380 ms
~~~ 略 ~~~
^C
--- 172.23.0.3 ping statistics ---
30 packets transmitted, 23 received, 23.3333% packet loss, time 29128ms
rtt min/avg/max/mdev = 330.492/395.859/441.963/23.431 ms

後片付け

$ sudo tc qdisc del dev  vethc780b05 root
$ sudo tc qdisc del dev ifb 0 root
$ sudo modprobe -r ifb

Discussion