当方ではコンテナ仮想化環境としてDockerを利用しています。
Dockerホストの所属するネットワークセグメントには当該サーバしか存在しておらず、十分なIPの空きがあるためDocker標準のIPマスカレードによる外部との接続は管理が煩雑と感じました。(ネットワーク構成参考)
また、ホストサーバで動作しているSamba4のADサービスがdocker0のIP(172.16.0.1)をDNSに自動登録してしまい内部DNSに弊害が発生したため、単純にホストネットワークにブリッジ接続する構成に変更しました。
当方環境 : CentOS7 , Docker version 1.12.1, build 23cf638
ネットワーク構成(変更前・変更後)
本サーバではDockerの他にOpenVPNサーバもtapモード(ブリッジ)で動作しているため、複雑なネットワーク構成となっていました。
これを変更し、dockerコンテナは単純にブリッジ接続で外部と通信できるようにしてみます。
IPアドレス(物理NICに付与されていたもの) : AAA.BBB.CCC.2/24
デフォルトゲートウェイ : AAA.BBB.CCC.1
Dockerの設定変更
以下の記事を参考にしました。
Dockerブリッジの作成
Dockerネットワークを新規生成します。これによりdocker管理下のセグメントshared_nwと、ブリッジデバイスbr0が作成されます。
# docker network create --driver bridge --subnet=AAA.BBB.CCC.0/24 --gateway=AAA.BBB.CCC.2 \ --opt "com.docker.network.bridge.name"="br0" shared_nw # docker network ls NETWORK ID NAME DRIVER SCOPE xxxxxxxxxxxx bridge bridge local xxxxxxxxxxxx host host local xxxxxxxxxxxx none null local xxxxxxxxxxxx shared_nw bridge local
ホストインタフェースをブリッジに接続
物理NIC(enp3s0)からIPを削除した後、作成したブリッジにホストインタフェースをぶら下げます。
また、デフォルトゲートウェイが消えているため追加します。
# ifconfig $eth 0.0.0.0 promisc up # brctl addif br0 enp3s0 # brctl show bridge name bridge id STP enabled interfaces br0 8000.02421d0de15f no enp3s0
起動スクリプトの改修
上記のブリッジ接続設定は再起動で消えてしまうため、ホスト起動時に自動的に設定されるよう以下の起動スクリプトを作成しました。
ついでにdocker0インタフェースも無効化しておきます。
以下の内容で /etc/docker/docker-startup として作成しました。
#!/bin/sh ################################# # Set up Ethernet bridge on Linux # Requires: bridge-utils ################################# # ブリッジインタフェースの定義 br="br0" # ブリッジされる物理NICの定義 eth="enp3s0" eth_ip="AAA.BBB.CCC.2" eth_netmask="255.255.255.0" eth_broadcast="AAA.BBB.CCC.255" gw="AAA.BBB.CCC.1" # 物理NICからIP削除 ifconfig $eth 0.0.0.0 promisc up # ブリッジの紐づけ brctl addif $br $eth # デフォルトゲートウェイの再設定 route add default gw $gw # docker0の無効化 ip link set dev docker0 down brctl delbr docker0 # IP転送有効化 /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
また、シャットダウンスクリプトも作成します。
#!/bin/sh #################################### # Tear Down Ethernet bridge on Linux #################################### # ブリッジインタフェースの定義 br="br0" # オリジナルNICの定義 eth="enp3s0" ip="AAA.BBB.CCC.DDD" gw="AAA.BBB.CCC.1" # ブリッジインタフェースの削除 ifconfig $br down brctl delbr $br # IP転送の中止 /bin/echo 0 > /proc/sys/net/ipv4/ip_forward # オリジナルNICの再設定 ifconfig $eth $ip route add default gw $gw
本スクリプトはdocker起動時・停止時に実行されるよう、/etc/systemd/system/docker.service に以下の2行を追記しました。
[Service] ExecStartPost=/etc/docker/docker-startup ExecStopPost=/etc/docker/docker-shutdown
OpenVPNの設定変更
Dockerの設定変更により、OpenVPNがDockerのブリッジに依存するようになったため、OpenVPN起動はDockerの後となるよう設定します。
/etc/systemd/system/docker.service に以下の1行を追加します。
[Unit] Before=openvpn-bridge.service
OpenVPNの起動スクリプトを変更し、ブリッジの設定変更を抑止します。
#!/bin/sh ################################# # Set up Ethernet bridge on Linux # Requires: bridge-utils ################################# # ブリッジインタフェースの定義 br="br0" # ブリッジされるTAPインタフェースの定義 # for example tap="tap0 tap1 tap2". tap="tap0" # TAPインタフェースの作製 for t in $tap; do openvpn --mktun --dev $t done # ブリッジインタフェーズに紐づけ for t in $tap; do brctl addif $br $t done # tapインタフェースをプロミスキャスモードに設定 for t in $tap; do ifconfig $t 0.0.0.0 promisc up done
OpenVPNシャットダウンスクリプトも変更します。
#!/bin/sh #################################### # Tear Down Ethernet bridge on Linux #################################### # ブリッジインタフェースの定義 br="br0" # ブリッジされるTAPインタフェースの定義 tap="tap0" # TAPインタフェースの削除 for t in $tap; do openvpn --rmtun --dev $t done
結果
これにより、計画通りのネットワーク構成に変更することができました。
インタフェース/ルーティング/ブリッジ構成
# ifconfig -a br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet AAA.BBB.CCC.2 netmask 255.255.255.0 broadcast 0.0.0.0 ether 02:42:ab:af:30:a8 txqueuelen 0 (Ethernet) RX packets 1006 bytes 196328 (191.7 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 1151 bytes 155997 (152.3 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 enp3s0: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500 ether c0:3f:d5:6f:6f:26 txqueuelen 1000 (Ethernet) RX packets 1020 bytes 211312 (206.3 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 1139 bytes 154677 (151.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 0 (Local Loopback) RX packets 1080 bytes 71830 (70.1 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 1080 bytes 71830 (70.1 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 tap0: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500 ether aa:66:de:d0:48:80 txqueuelen 100 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 9 bytes 834 (834.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 # netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 0.0.0.0 AAA.BBB.CCC.1 0.0.0.0 UG 0 0 0 br0 AAA.BBB.CCC.0 0.0.0.0 255.255.255.0 U 0 0 0 br0 # brctl show bridge name bridge id STP enabled interfaces br0 8000.0242abaf30a8 no enp3s0 tap0 # docker network ls NETWORK ID NAME DRIVER SCOPE xxxxxxxxxxxx bridge bridge local xxxxxxxxxxxx host host local xxxxxxxxxxxx none null local xxxxxxxxxxxx shared_nw bridge local
使い方
永続コンテナを起動する例
# docker run -d --name container1 --hostname container1 --net shared_nw --ip AAA.BBB.CCC.3 --restart=always -i -t centos
この変更により、外部から直接dockerコンテナと通信できるようになり、とても便利になりました。
コンテナのセキュリティは自分で確保しなくてはなりませんが。
コメント