designetwork

ネットワークを軸としたIT技術メモ

Docker-ComposeでMACVLAN (802.1Q VLAN Tag) ネットワークを作成する

こちらの記事でDockerコンテナを外部ネットワークと802.1Q VLAN Tag接続した。

designetwork.hatenablog.com

今回はDocker-Composeファイルで定義して運用しやすくする。さらに作り込めば、ネットワークテスト自動化が実現できると考えている。

参考情報

Docker-Composeファイルの書き方はオフィシャル参照。バージョンによりファイルフォーマット(Key名)が変わっていたり使えないので注意が必要。

docs.docker.com

こちらでMACVLANを使用する例がある。

Docker Compose File for MacVLAN Network Driver ( Single Node) · GitHub

Docker-ComposeでVLAN Tagネットワークを作成する

構築するネットワークはこちらの通り。(前回記事と同様)

docker-compose.ymlはこのようになる。Alpineを使用し、tail -f /dev/nullとしてコンテナを単純に起動させる。

* versionの指定が異なるとエラーが発生する場合があります。別バージョン使用時はDocker Docsを参照し、書き換えてください。

$ cat ./docker-compose.yml
version: '2.1'

services:
  vlan20:
    image: alpine
    container_name: container-vlan20
    command: ['tail', '-f', '/dev/null']
    networks:
      vlan20:
        ipv4_address: 192.168.20.201
    environment:
      VLAN: 20
  vlan30:
    image: alpine
    container_name: container-vlan30
    command: ['tail', '-f', '/dev/null']
    networks:
      vlan30:
        ipv4_address: 192.168.30.201
    environment:
      VLAN: 30

networks:
  vlan20:
    name: vlan20
    driver: macvlan
    driver_opts:
      parent: ens192.20
    ipam:
      config:
        - subnet: 192.168.20.0/24
          gateway: 192.168.20.1
  vlan30:
    name: vlan30
    driver: macvlan
    driver_opts:
      parent: ens192.30
    ipam:
      config:
        - subnet: 192.168.30.0/24
          gateway: 192.168.30.1

上記docker-compose.ymlファイルを使用してネットワーク・コンテナを作成・起動する。

$ docker-compose up -d
Creating network "vlan20" with driver "macvlan"
Creating network "vlan30" with driver "macvlan"
Creating container-vlan20 ... done
Creating container-vlan30 ... done

Dockerネットワーク・コンテナ状態確認

作成されたDockerネットワークを確認する。MACVLANドライバーを使用して802.1Q VLANタグネットワークとして作成されている。

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
61b2b0b3706c        bridge              bridge              local
e14ebf55d626        host                host                local
112dc8a40c20        none                null                local
e44db3a06622        vlan20              macvlan             local
44e22d10ce22        vlan30              macvlan             local

$ docker network inspect vlan20
[
    {
        "Name": "vlan20",
        "Id": "e44db3a06622aa890d0af9851782e398ad938c552b3aad3636b364f9fd45186c",
        "Created": "2018-05-02T05:10:57.097052723-04:00",
        "Scope": "local",
        "Driver": "macvlan",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "192.168.20.0/24",
                    "Gateway": "192.168.20.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Containers": {
            "894e66f1395a1771737a0c9dbb1812781a8f2d17ec60d27b57b46c12e776de10": {
                "Name": "container-vlan20",
                "EndpointID": "a424fe4eb6bff57c8aa04a116acffcc41bcc9f0c3f8edd3afa782f63484935d6",
                "MacAddress": "02:42:c0:a8:14:c9",
                "IPv4Address": "192.168.20.201/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "parent": "ens192.20"
        },
        "Labels": {
            "com.docker.compose.network": "vlan20",
            "com.docker.compose.project": "vlan-tag"
        }
    }
]

$ docker network inspect vlan30
[
    {
        "Name": "vlan30",
        "Id": "44e22d10ce2269ed8204244430dcea4249b931d2be00b459db4bd731cf5cdca3",
        "Created": "2018-05-02T05:10:57.123608227-04:00",
        "Scope": "local",
        "Driver": "macvlan",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "192.168.30.0/24",
                    "Gateway": "192.168.30.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Containers": {
            "bea9276ab6df772e5af985bc7e761765d562caf3d682850f5669e516c02de374": {
                "Name": "container-vlan30",
                "EndpointID": "e6f134af82f057c0ed7259ec8bc9932e23e594f9211663563b776736e884537b",
                "MacAddress": "02:42:c0:a8:1e:c9",
                "IPv4Address": "192.168.30.201/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "parent": "ens192.30"
        },
        "Labels": {
            "com.docker.compose.network": "vlan30",
            "com.docker.compose.project": "vlan-tag"
        }
    }
]

$ docker ps
CONTAINER ID        IMAGE               COMMAND               CREATED             STATUS              PORTS               NAMES
894e66f1395a        alpine              "tail -f /dev/null"   26 seconds ago      Up 26 seconds                           container-vlan20
bea9276ab6df        alpine              "tail -f /dev/null"   26 seconds ago      Up 26 seconds                           container-vlan30

コンテナ同士の疎通・経路確認

起動したコンテナで相互にPing・Tracerouteにより疎通・経路確認する。

$ docker exec -it container-vlan20 /bin/sh
/ # ip a
84: eth0@if82: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UNKNOWN
    link/ether 02:42:c0:a8:14:c9 brd ff:ff:ff:ff:ff:ff
    inet 192.168.20.201/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:c0ff:fea8:14c9/64 scope link
       valid_lft forever preferred_lft forever

/ # ping 192.168.20.1
PING 192.168.20.1 (192.168.20.1): 56 data bytes
64 bytes from 192.168.20.1: seq=0 ttl=64 time=1.164 ms
64 bytes from 192.168.20.1: seq=1 ttl=64 time=0.332 ms

/ # ping 192.168.30.201
PING 192.168.30.201 (192.168.30.201): 56 data bytes
64 bytes from 192.168.30.201: seq=0 ttl=63 time=1.160 ms
64 bytes from 192.168.30.201: seq=1 ttl=63 time=0.317 ms

/ # traceroute 192.168.30.201
traceroute to 192.168.30.201 (192.168.30.201), 30 hops max, 46 byte packets
 1  192.168.20.1 (192.168.20.1)  0.366 ms  0.141 ms  0.452 ms
 2  192.168.30.201 (192.168.30.201)  0.200 ms  0.283 ms  0.268 ms

/ # exit

$ docker exec -it container-vlan30 /bin/sh
/ # ip a
85: eth0@if83: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UNKNOWN
    link/ether 02:42:c0:a8:1e:c9 brd ff:ff:ff:ff:ff:ff
    inet 192.168.30.201/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:c0ff:fea8:1ec9/64 scope link
       valid_lft forever preferred_lft forever

/ # ping 192.168.30.1
PING 192.168.30.1 (192.168.30.1): 56 data bytes
64 bytes from 192.168.30.1: seq=0 ttl=64 time=0.298 ms
64 bytes from 192.168.30.1: seq=1 ttl=64 time=0.300 ms

/ # ping 192.168.20.201
PING 192.168.20.201 (192.168.20.201): 56 data bytes
64 bytes from 192.168.20.201: seq=0 ttl=63 time=0.511 ms
64 bytes from 192.168.20.201: seq=1 ttl=63 time=0.405 ms

/ # traceroute 192.168.20.201
traceroute to 192.168.20.201 (192.168.20.201), 30 hops max, 46 byte packets
 1  192.168.30.1 (192.168.30.1)  0.217 ms  0.215 ms  0.197 ms
 2  192.168.20.201 (192.168.20.201)  0.306 ms  0.458 ms  0.443 ms
/ # exit

SUCCEEDED!! 期待通り相互に疎通確認・経路確認ができている。Tracerouteの結果からわかる通り、ホストNICはVLANタグを透過して、外部ルータでVLAN間ルーティングされている。

まとめ - Docker-ComposeでMACVLAN (802.1Q VLAN Tag) ネットワークを作成する

Docker-ComposeでMACVLAN (802.1Q VLAN Tag) ネットワークを作成し、それぞれのネットワーク(VLAN/セグメント)にコンテナを配置し、相互に疎通・経路確認を実施した。

docker-compose.ymlの生成方法、起動コンテナ用シェルスクリプトを工夫すれば、ネットワークテスト自動化が可能になると考えている。