【Docker】コンテナ間でスタティックルーテイングを試してみた

# コンテナの構成

![docker1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3675830/8eef5e50-2742-4eb2-9e66-b55ad6ddc06e.png)


ネットワークを2つ用意して、pingやcurlでリクエストを送信する「クライアントコンテナ」をネットワーク1に、webサーバ用の「httpサーバ用コンテナ」をネットワーク2に設定します。

また、「ルーティング用コンテナ」をネットワーク1とネットワーク2の双方に配置し、
クライアントコンテナとhttpサーバ用コンテナ間の通信を中継します。

クライアントコンテナでping 127.19.0.2やcurl http://172.19.0.2:80 を実行し、
レスポンスが帰ってきたら成功です。

# ネットワークの設定
以下のコマンドでネットワークを作成します。
```shell-session
$ docker network create net1
$ docker network create net2
```
作成したネットワークは以下のコマンドで確認できます。
```shell-session
$ docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
164f615dfc72   bridge            bridge    local
88991324c4ca   host              host      local
78db3e751e28   net1              bridge    local
130596727a1e   net2              bridge    local
```

# クライアントコンテナの配置
まずネットワーク1にクライアントコンテナを配置します。
```shell-session
$ docker container run -it --name container1 --net net1 ubuntu:22.04
```
コンテナに入ったら、ip、ping、curlが使えるようにインストールしておきます。
```shell-session
$ apt update
$ apt install iproute2 #ipコマンド
$ apt install curl #curl
$ apt install iputils-ping net-tools #ping
```

ここで一旦ipコマンドを用いてネットワークインターフェースを確認してみます。
```shell-session
$ ip a

##出力の一部
61: eth0@if62: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.20.0.2/16 brd 172.20.255.255 scope global eth0
       valid_lft forever preferred_lft forever
```

出力結果からeth0のipv4は172.20.0.2/16であることがわかります。
一度コンテナから出て、dockerのネットワーク設定も見てみましょう。
ネットワーク設定はdocker network inspect <ネットワーク名>で確認できます。

```shell-session
$  docker network inspect net1

##出力の一部
"Name": "container1",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/16",
                "IPv6Address": ""
```
クライアントコンテナであるcontainer1に172.20.0.2/16が割り当てられています。

# ルーティング用コンテナを配置
まずは、ネットワーク1にルーティング用コンテナを配置します。
```shell-session
$ docker container run -it --name router --net net1 ubuntu:22.04
```

次に、コンテナをネットワーク2と接続します。以下のコマンドで接続できます。
```shell-session
$ docker network connect net2 router
```

コンテナに入ってipコマンドでインターフェースを確認してみましょう。
```shell-session
$ ip a

## 出力の一部
63: eth0@if64: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:14:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.20.0.3/16 brd 172.20.255.255 scope global eth0
       valid_lft forever preferred_lft forever
65: eth1@if66: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:15:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.21.0.2/16 brd 172.21.255.255 scope global eth1
       valid_lft forever preferred_lft forever
```

2つのネットワーク上にインターフェースが設定されていることを確認できました。

# httpサーバ用コンテナを配置
以下のコマンドでネットワーク2にwebサーバを配置します。
```shell-session
$ docker container run -d --name container2 --net net2 httpd
```

コンテナに入ってipコマンドをインストールしておきましょう。

# 今の状態でpingしてみる
クライアントコンテナに入って172.21.0.3へpingを飛ばしてみます。
```shell-session
$ ping 172.21.0.3
```
今の状況だと、まだルーティングが適切に設定されておらず、pingの返答が帰ってこないことがわかります。

# スタティックルーティング
上記の問題を解決するために、ルーティングテーブルの設定を行います。
クライアントコンテナに、privilegedオプション付きで入ります。
そして、ip r を用いて、ルーティングの設定を行います。
```shell-session
$ ip r add 172.21.0.0/16 via 172.20.0.3 dev eth0
```

これにより、172.20.0.3をネクストホップとして、172.21.0.0/16のネットワークに接続するルールが追加されました。

httpサーバ用コンテナにもルーティングの設定を行います。
```shell-session
$ ip r add 172.20.0.0/16 via 172.20.0.2 dev eth0
```

設定できたら、クライアントコンテナから172.21.0.3へpingを飛ばすとレスポンスが来るはずです。

# 最後にcurlする
172.21.0.3の80番ポートにリクエストを送ってみましょう。
```shell-session
$ curl http://172.21.0.3:80
<html><body><h1>It works!</h1></body></html>
```
レスポンスボディを取得できました！