togatttiのエンジニアメモ

過度な期待はしないでください.

Dockerコンテナでネットワーク検証環境を構築する

DockerコンテナとOpen vSwitchを組み合わせてネットワーク検証環境を用意する。

作りたいのはこれ。

f:id:togattti1990:20190630092246j:plain

コンポーネントは、以下のようにする。

  • ルータ
    • vyos1
  • ブリッジ
    • vswitch1
    • vswitch2
  • サーバ
    • centos1
    • centos2
    • centos3
    • centos4

各サーバは、NATを使いインターネットに出ることができる。

Open vSwitchとDockerのインストールは省略。

Dockerイメージ作成、取得

VyOSとCentOSのDockerイメージを用意する。

VyOS

$ docker pull 2stacks/vyos:1.2.0-rc11

CentOS

$ cat Dockerfile
FROM centos
RUN yum update -y
RUN yum install -y iproute iputils 
$ docker build -t togattti/centos .

仮想スイッチを作成する

# ovs-vsctl add-br vswitch1
# ovs-vsctl add-br vswitch2
# ovs-vsctl show
591945d1-a629-428b-bf23-c725386b4db0
    Bridge "vswitch2"
        Port "vswitch2"
            Interface "vswitch2"
                type: internal
    Bridge "vswitch1"
        Port "vswitch1"
            Interface "vswitch1"
                type: internal
    ovs_version: "2.9.2"

VyOSを構築する

コンテナを起動する。

$ docker run -d --name vyos1 --privileged -v /lib/modules:/lib/modules 2stacks/vyos:1.2.0-rc11 /sbin/init

vyos1にインターフェイスを作成、ブリッジとつなぐ。

$ sudo ovs-docker add-port vswitch1 eth1 vyos1 --ipaddress=192.168.10.1/24
$ sudo ovs-docker add-port vswitch2 eth2 vyos1 --ipaddress=192.168.20.1/24

サーバを構築する

Dockerコンテナを起動する。

$ docker run -d --net=none --privileged --name centos1 togattti/centos /sbin/init
$ docker run -d --net=none --privileged --name centos2 togattti/centos /sbin/init
$ docker run -d --net=none --privileged --name centos3 togattti/centos /sbin/init
$ docker run -d --net=none --privileged --name centos4 togattti/centos /sbin/init

各サーバにインターフェイスを作成、ブリッジとつなぐ。

$ sudo ovs-docker add-port vswitch1 eth0 centos1 --ipaddress=192.168.10.2/24
$ sudo ovs-docker add-port vswitch1 eth0 centos2 --ipaddress=192.168.10.3/24
$ sudo ovs-docker add-port vswitch2 eth0 centos3 --ipaddress=192.168.20.2/24
$ sudo ovs-docker add-port vswitch2 eth0 centos4 --ipaddress=192.168.20.3/24

ここまでで、インターフェイスの設定状況が次のようになる。

$ docker exec -it centos1 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
229: eth0@if230: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether be:97:47:c6:64:28 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.10.2/24 scope global eth0
       valid_lft forever preferred_lft forever
$ docker exec -it centos2 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
231: eth0@if232: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether ce:40:67:95:a2:93 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.10.3/24 scope global eth0
       valid_lft forever preferred_lft forever
$ docker exec -it centos3 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
233: eth0@if234: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 02:0e:68:d2:c6:59 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.20.2/24 scope global eth0
       valid_lft forever preferred_lft forever
$ docker exec -it centos4 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
235: eth0@if236: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether e6:6b:b2:5f:38:cc brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.20.3/24 scope global eth0
       valid_lft forever preferred_lft forever

ここまでの動作確認

centos1 -> centos2は、ネットワークが同一なので接続できるが、centos1 -> centos3は、別ネットワークにあるので、接続できない。

同様に、インターネットにも出れない。

$ docker exec -it centos1 ping -c 1 192.168.10.3
PING 192.168.10.3 (192.168.10.3) 56(84) bytes of data.
64 bytes from 192.168.10.3: icmp_seq=1 ttl=64 time=0.097 ms

--- 192.168.10.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.097/0.097/0.097/0.000 ms
$ docker exec -it centos1 ping -c 1 192.168.20.2
connect: Network is unreachable
[root@a31c1ed4247a /]# ping -c 1 8.8.8.8
connect: Network is unreachable

デフォルトゲートウェイを設定する

centos1とcentos3のような別ネットワークにあるサーバ同士を接続する場合は、 お互いのデフォルトゲートウェイをvyos1に向ける必要がある。

行きと戻りのパケットの経路が必要なので、片道の経路だけでは疎通できないことに注意する。

$ docker exec -it centos1 ip route add default via 192.168.10.1
$ docker exec -it centos2 ip route add default via 192.168.10.1
$ docker exec -it centos3 ip route add default via 192.168.20.1
$ docker exec -it centos4 ip route add default via 192.168.20.1

設定状況は、以下のようになる。

$ docker exec -it centos1 ip r
default via 192.168.10.1 dev eth0
192.168.10.0/24 dev eth0 proto kernel scope link src 192.168.10.2
$ docker exec -it centos2 ip r
default via 192.168.10.1 dev eth0
192.168.10.0/24 dev eth0 proto kernel scope link src 192.168.10.3
$ docker exec -it centos3 ip r
default via 192.168.20.1 dev eth0
192.168.20.0/24 dev eth0 proto kernel scope link src 192.168.20.2
$ docker exec -it centos4 ip r
default via 192.168.20.1 dev eth0
192.168.20.0/24 dev eth0 proto kernel scope link src 192.168.20.3

これで、centos1~4は、互いに疎通できる。

$ docker exec -it centos1 ping -c 1 192
.168.20.2
PING 192.168.20.2 (192.168.20.2) 56(84) bytes of data.
64 bytes from 192.168.20.2: icmp_seq=1 ttl=63 time=1.25 ms

--- 192.168.20.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.257/1.257/1.257/0.000 ms

ただし、インターネットには出れないままなので、NATを設定する。

$ docker exec -it centos1 ping -c 1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

NATを設定する

vyos1にNATの設定を追加する。

$ docker exec -it vyos1 /bin/vbash
# su - minion
$ configure
# set interfaces loopback lo address 1.1.1.1/32
# set nat source rule 1 translation address masquerade
# set nat source rule 1 source address 192.168.0.0/16
# set nat source rule 1 outbound-interface eth0
# set nat source rule 1 description 'nat global 1'
# show
+interfaces {
+    loopback lo {
+        address 1.1.1.1/32
+    }
+}
+nat {
+    source {
+        rule 1 {
+            description "nat global 1"
+            outbound-interface eth0
+            source {
+                address 192.168.0.0/16
+            }
+            translation {
+                address masquerade
+            }
+        }
+    }
+}
# commit
# save

これで、vyos1のeth0を通してインターネットに出れる。

$ docker exec -it centos1 ping -c 1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=50 time=2.27 ms

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 2.276/2.276/2.276/0.000 ms

あとで、作成した検証環境の構成をdocker-compose.ymlにまとめる。

参考

https://ameblo.jp/principia-ca/entry-12103919307.html