Dockerネットワーク間でPINGを通す

## はじめに

一般のご家庭向けです

[逸般の誤家庭の方]( https://www.youtube.com/watch?v=23GoObFnFdA)は、物理マシンでお試しください
**※ YouTubeへのリンクです。音量に注意してください**

## この記事は

「Dockerのネットワークを使って、ネットワークの勉強をしたい」

そんな時、素早くDockerネットワークを構築できるとよい

**素早くDockerネットワークを構築するための docker-compose.ymlと、その周辺フォルダー環境を書き残した記事です**

コピペに次ぐコピペで、とりあえずAネットの端末からBネットの端末へPINGが通るようになります

## フォルダ構成

適当な場所に適当なフォルダを作ったら
その下にdocker-compose.ymlを置く

さらに clietn1, client2, router フォルダをつくる

各フォルダの中には mnt フォルダと Dockerfile をつくる
mntフォルダにはentrypoint.shを入れる

以上！

```
│  docker-compose.yml
│
├─client1
│  │  Dockerfile
│  │
│  └─mnt
│          entrypoint.sh
│
├─client2
│  │  Dockerfile
│  │
│  └─mnt
│          entrypoint.sh
│
├─router
│  │  Dockerfile
│  │
│  └─mnt
```

## Dockerfile

３つあるDockerfileの中身は共通です
Ubuntuをベースに、ネットワーク関連のパッケージをインストールしておきます

```Dockerfile
FROM ubuntu:latest

RUN apt update
RUN apt install -y vim iputils-ping iproute2 net-tools traceroute
```

※もっと軽量なイメージを使えばいいと思いましたが、今後実機を使うことを想定すると、無難なUbuntuがいいかなーと思いUbuntu採しました

## docker-compose.yml

長ったらしく書いてますが、単に client1 が client2 に対してPING打つためだけの環境です

登場人物|IPアドレス|役割
-|-|-
client1|172.23.1.10|PING送る人
client1|172.23.2.10|PING受ける人
router|172.23.1.250, 172.23.2.250|２つのネットワークに所属してPING中継する人


```yml
version: '3.9'

services:
  client1:
    build: ./client1
    container_name: client1
    hostname: client1
    tty: true
    stdin_open: true
    privileged: true
    volumes:
      - ./client1/mnt:/mnt
    networks:
      delay-net1:      
        ipv4_address: 172.23.1.10
    command: bash -c "bash /mnt/entrypoint.sh && /bin/bash"

  client2:
    build: ./client2
    container_name: client2
    hostname: client2
    tty: true
    stdin_open: true
    privileged: true
    volumes:
      - ./client2/mnt:/mnt
    networks:
      delay-net2:      
        ipv4_address: 172.23.2.10
    command: bash -c "bash /mnt/entrypoint.sh && /bin/bash"

  router:
    build: ./router
    container_name: router
    hostname: router
    tty: true
    stdin_open: true
    volumes:
      - ./router/mnt:/mnt
    networks:
      delay-net1:
        ipv4_address: 172.23.1.250
      delay-net2:      
        ipv4_address: 172.23.2.250
    sysctls:
      - net.ipv4.ip_forward=1
      
networks:
  delay-net1:
    ipam:
      driver: default
      config:
        - subnet: 172.23.1.0/24
  delay-net2:
    ipam:
      driver: default
      config:
        - subnet: 172.23.2.0/24
```

### いくつかのポイント説明

#### ボリュームをマウント

`/mnt`フォルダを介して、ホストマシンでつくったシェルスクリプトなどを共有します

```yml
    volumes:
      - ./client1/mnt:/mnt
```

mntフォルダにentrypoint.shを入れておきます

#### ルーティング

ルーターは各クライアントのデフォルトゲートウェイとなります
デフォルトゲートウェイとなるためには、静的ルーティングを変更する必要があります（既定ではインターネットに向かってパケットを送信してしまう）

静的ルーティングを変更するには管理者権限が要るので、`privileged: true`としています

また、Ubuntuは既定でポートフォワードをしてくれますが、無効にした場合の挙動もみてみたいので、あえてポートフォワードの設定を明示しています
今回はポートフォワードしてもらってPING中継するので、下記設定です

```yml
    sysctls:
      - net.ipv4.ip_forward=1
```

#### コンテナに入って作業するために

下記の３行は、コンテナがすぐに終了しなようにするための措置です
意味はよくわかりません
コマンドでエントリポイントのシェルスクリプトを実行したあとに、`&&`でつないでbashを再度実行してます

```yml
    tty: true
    stdin_open: true
    command: bash -c "bash /mnt/entrypoint.sh && /bin/bash"
```

https://ja.stackoverflow.com/questions/52132/docker-compose-up-%E3%81%A7-tty-true%E3%82%92%E4%BB%98%E3%81%91%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E3%81%AB-command%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B%E3%81%A8%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%8C%E7%B5%82%E3%82%8F%E3%81%A3%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86

## entrypoint.sh

エントリポイントで静的ルーティングを設定します
client1,2でそれぞれゲートウェイが異なるので、２つのシェルスクリプトを掲載しますが、差異は微々たるものです

- client1
  - 172.23.2.0/24に向かうパケットは172.23.1.250（ルータ）を目指して送出

```bash
#!/bin/bash

# 静的ルーティング
ip route add 172.23.2.0/24 via 172.23.1.250
```

- client2
  - 172.23.1.0/24に向かうパケットは172.23.2.250（ルータ）を目指して送出

```bash
#!/bin/bash

# 静的ルーティング
ip route add 172.23.1.0/24 via 172.23.2.250
```

## いざ実行

docker-compose.ymlが置いてあるフォルダで下記コマンドを実行
`docker compose up --build -d`

クライアント１号機のコンテナに入って作業する
`docker compose exec client1 bash`

クライアント２号機に向けて`traceroute`と`ping`をした結果

```powershell
client1  | traceroute to 172.23.2.10 (172.23.2.10), 30 hops max, 60 byte packets
client1  |  1  172.23.1.250  3.333 ms  0.153 ms  0.114 ms
client1  |  2  172.23.2.10  0.486 ms  0.168 ms  0.100 ms

client1  | PING 172.23.2.10 (172.23.2.10) 56(84) bytes of data.
client1  | 64 bytes from 172.23.2.10: icmp_seq=1 ttl=63 time=1.90 ms
client1  | 64 bytes from 172.23.2.10: icmp_seq=2 ttl=63 time=0.100 ms
client1  | 64 bytes from 172.23.2.10: icmp_seq=3 ttl=63 time=0.116 ms
client1  | 64 bytes from 172.23.2.10: icmp_seq=4 ttl=63 time=0.092 ms
client1  |
client1  | --- 172.23.2.10 ping statistics ---
client1  | 4 packets transmitted, 4 received, 0% packet loss, time 3118ms
client1  | rtt min/avg/max/mdev = 0.092/0.552/1.903/0.779 ms
```

ちゃんとルータ(172.23.1.250)を通っていることがわかる

## おわりに

Dockerを使って手軽にPING疎通テストできる環境をつくった
しかもすべてスクリプトにお任せしているので、構築・破壊が容易
１年後でも、ここからコードをコピペすれば再現できる

今回つくったdocker-compose.ymlをベースにして
次回からはルータに機能を付与していきたい

パケットをわざと遅らせてみたり・・・（その布石がymlファイルの中にも書いてある）

## 付録 Docker Composeコマンド集

未来の自分のための備忘録

```powershell
# Dockerfileを変更したときは --build 付ける
docker compose up -d
docker compose up --build -d

# Dockerfileを変更して、かつ再起動したいときは
docker compose down -v && docker compose up --build -d

# ログを見る
docker compose logs -f

# 今日はもう作業しないよ、ってとき
docker compose down -v

# 案外使わない再起動
docker compose restart
```

## 糸冬了！！