DockerコンテナにLAN内のIPアドレスを割り当て、ホストからもアクセス可能にする

# はじめに

最近は会社にあるDockerホストのLinuxマシンに自宅からリモートでアクセスしている。
このような環境では、気軽にLinuxマシンのネットワーク設定を変更することができない。
ネットワークの設定でミスをすると、リモートで接続できなくなる恐れがあるためである。

このような状況で、Dockerコンテナにホストと同じLAN内のIPアドレスを割り振ることが必要になった。

検索したところ、以下の方法が見つかった。

### ブリッジを作成

ホストのネットワークインターフェースを割り当てたブリッジを作成し、そのブリッジにコンテナを接続する。
この方法はリモートでアクセス不可となるタイミングがあるので今回は使用不可である。

参照：
https://docs.docker.com/network/network-tutorial-standalone/
https://pj-doaa.hatenablog.com/entry/2019/09/04/144520

### macvlanネットワークを作成

macvlanドライバでホストと同じLANのDockerネットワークを作成し、そのネットワークにコンテナを接続する。
この方法であれば、ホストの既存のネットワーク設定を変更する必要がないので今回は適切である。
ただし、設定手順に記載した追加のネットワーク設定を行わないと、ホストからコンテナにアクセスできない。

参照：
https://docs.docker.com/network/network-tutorial-macvlan/
https://qiita.com/Meganezaru@github/items/69f406844532d731d370
https://qiita.com/okhrn/items/d8580e66546d166f489a
https://base64.work/so/docker/1535501

# 設定手順

以下を前提とした手順を記載する。

|項目|内容|
|--|--|
|ホストの名前|hostpc|
|ホストのOS|Ubuntu 16.04|
|ホストの物理N/W IF|enp3s0|
|ホストのIPアドレス|172.12.224.10|
|ホストのLAN|172.12.224.0/20|
|ゲートウェイ|172.12.224.1|
|ホストに追加するN/W IF|htoc0|
|追加N/W IFのIPアドレス|172.12.224.100|
|コンテナ1の名前|conte1|
|コンテナ1のIPアドレス|172.12.224.101|
|コンテナ2の名前|conte2|
|コンテナ2のIPアドレス|172.12.224.102|
|LAN内別PCの名前|otherpc|
|LAN内別PCのIPアドレス|172.12.224.30|

以下の手順でmacvlanネットワークとコンテナを追加する。

```
# docker network create -d macvlan --subnet=172.12.224.0/20 --gateway=172.12.224.1 -o parent=enp3s0 corplan
# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
47187139f09e        corplan             macvlan             local
851186fc68a8        bridge              bridge              local
7873fd88b23e        host                host                local
c4a08749ed89        none                null                local
# docker run -d -it --network corplan --ip 172.12.224.101 --name conte1 ubuntu:18.04 /bin/bash
# docker run -d -it --network corplan --ip 172.12.224.102 --name conte2 ubuntu:18.04 /bin/bash
```

この時点では、pingの疎通状況が以下のようになる（ホストとコンテナ間は疎通不可）。

|送信側＼受信側|hostpc|conte1|conte2|otherpc|
|--|:--:|:--:|:--:|:--:|
|hostpc|-|×|×|○|
|conte1|×|-|○|○|
|conte2|×|○|-|○|
|otherpc|○|○|○|-|

コンテナ（Ubuntu 18.04）でpingを使用するためには、inetutils-pingをインストールする必要がある。

以下の手順で、ホストの物理N/W IFに結合するブリッジモードのmacvlan仮想N/W IFを追加し、追加したN/W IFのルートを設定する。

```
# ip link add htoc0 link enp3s0 type macvlan mode bridge
# ip addr add 172.12.224.100/32 dev htoc0
# ip link set htoc0 up
# ip route add 172.12.224.0/20 dev htoc0
# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.12.224.1    0.0.0.0         UG    100    0        0 enp3s0
link-local      *               255.255.0.0     U     1000   0        0 enp3s0
172.17.0.0      *               255.255.0.0     U     0      0        0 docker0
172.12.224.0    *               255.255.224.0   U     0      0        0 htoc0
172.12.224.0    *               255.255.224.0   U     100    0        0 enp3s0
```

上記ように172.12.224.0/20のルートが2つある状態になるので、htoc0のメトリックにはenp3s0より小さい値を指定する必要がある（enp3s0のルートを削除してスッキリしたいと思うかも知れないが、カーネルが追加したルートは触らない方が安全である）。

この時点では、pingの疎通状況が以下のようになる（ホストとコンテナ間も疎通可能）。

|送信側＼受信側|hostpc|conte1|conte2|otherpc|
|--|:--:|:--:|:--:|:--:|
|hostpc|-|○|○|○|
|conte1|○|-|○|○|
|conte2|○|○|-|○|
|otherpc|○|○|○|-|

なお、追加したhtoc0やそのルートはホストを再起動すると失われてしまうので、起動スクリプトなどで再現する必要がある（詳細は割愛）。

# 追加情報

## VMware ESXiの仮想マシン上ではmacvlanが動作しない

~~以下ではNICをvmxnet3にすれば動作すると記載されていたが、ESXi 6.7では動作しなかった。~~
無差別モード（Promiscuousモード）をオンに設定した仮想スイッチを作成し、そちらにvmxnet3のNICを接続したら動作するようになった。
ただし、直ぐには成功せず、Linux上でネットワーク設定を変更（ens160に固定IPアドレスを追加）して再起動したら、Dockerコンテナに割り当てたmacvlan上の固定IPアドレスに、他のマシンからPINGが通るようになった。

https://qiita.com/albatross/items/8c32615b5154acf712f2