背景情報
Dockerを実行している2つのネットワークインターフェイスを備えたサーバーがあります。 Dockerは、一部の仮想化ツールと同様に、docker0
というLinuxブリッジインターフェースを作成します。このインターフェースはデフォルトで172.17.42.1
のIPで構成され、すべてのDockerコンテナーはゲートウェイとしてこのインターフェースと通信し、同じ/16
範囲のIPアドレスが割り当てられます。私が理解しているように、コンテナとの間のすべてのネットワークトラフィックはNATを通過するため、送信は172.17.42.1
から送信され、受信は172.17.42.1
に送信されます。
私のセットアップは次のようになります:
+------------+ /
| | |
+-------------+ Gateway 1 +-------
| | 10.1.1.1 | /
+------+-------+ +------------+ |
| eth0 | /
| 10.1.1.2 | |
| | |
| DOCKER Host | |
| | | Internet
| docker0 | |
| (bridge) | |
| 172.17.42.1 | |
| | |
| eth1 | |
| 192.168.1.2 | \
+------+-------+ +------------+ |
| | | \
+-------------+ Gateway 2 +-------
| 192.168.1.1| |
+------------+
問題
Dockerコンテナーとの間のすべてのトラフィックを2番目のeth1
192.168.1.2
インターフェースから192.168.1.1
のデフォルトゲートウェイにルーティングし、ホストマシンとの間のすべてのトラフィックを送信したいeth0
のデフォルトゲートウェイへの10.1.1.2
10.1.1.1
インターフェイス。私はこれまでさまざまなことを試みましたが、役に立たなかったのですが、正しいことに最も近いと思うのは、次のようにiproute2を使用することです。
# Create a new routing table just for docker
echo "1 docker" >> /etc/iproute2/rt_tables
# Add a rule stating any traffic from the docker0 bridge interface should use
# the newly added docker routing table
ip rule add from 172.17.42.1 table docker
# Add a route to the newly added docker routing table that dictates all traffic
# go out the 192.168.1.2 interface on eth1
ip route add default via 192.168.1.2 dev eth1 table docker
# Flush the route cache
ip route flush cache
# Restart the Docker daemon so it uses the correct network settings
# Note, I do this as I found Docker containers often won't be able
# to connect out if any changes to the network are made while it's
# running
/etc/init.d/docker restart
コンテナを立ち上げると、これを実行してもコンテナからpingを実行できません。ブリッジインターフェイスが物理インターフェイスがこの種のルーティングと同じ方法で処理されるかどうかは不明ですが、サニティチェックと、この一見単純なタスクを実行する方法に関するヒントが必要です。
友人と私は、Dockerがリクエストを処理する複数のネットワークインターフェイスをサポートするようにしたいというまさにこの問題に遭遇しました。私たちは特にAWS EC2サービスで作業しており、追加のインターフェイスの接続/構成/準備も行っていました。この project では、必要なものだけではありません。ここでは、必要なものだけを含めるようにします。
まず、eth1
用の個別のルートテーブルを作成しました。
ip route add default via 192.168.1.2 dev eth1 table 1001
次に、eth1
からの接続マークを設定するようにマングルテーブルを構成しました。
iptables -t mangle -A PREROUTING -i eth1 -j MARK --set-xmark 0x1001/0xffffffff
iptables -t mangle -A PREROUTING -i eth1 -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff
最後に、すべてのfwmark
sにこのルールを追加して、作成した新しいテーブルを使用します。
ip rule add from all fwmark 0x1001 lookup 1001
以下のiptables
コマンドは、接続マークを復元し、ルーティングルールが正しいルーティングテーブルを使用できるようにします。
iptables -w -t mangle -A PREROUTING -i docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
これは、私が言ったように、プロジェクトがブート時にeth1
インターフェースをアタッチ/構成/起動する、より複雑な例から必要なすべてだと思います。
この例では、eth0
からdocker0
へのリクエストへのサービスの提供を停止しませんが、ルーティングルールを追加してそれを防ぐことができると思います。
Iptablesの設定についても詳しく調べる必要があるかもしれません。 Dockerは、コンテナサブネット(172.17.0.0/16など)から発信されたすべてのトラフィックを0.0.0.0に見せかけます。 iptables -L -n -t nat
を実行すると、これを実行するnatテーブルの下にPOSTROUTINGチェーンが表示されます-
チェーンPOSTROUTING(ポリシーACCEPT) target prot opt source destination MASQUERADE all-172.17.0.0/16 0.0.0.0/0
これで、このルールを削除して、コンテナのサブネットから2番目のインターフェースのIP-192.168.1.2に発信するすべてのトラフィックをマスカレードするルールに置き換えることができます。削除ルールは、それがPOSTROUTINGチェーンの最初のルールであると想定して、
iptables -t nat -D POSTROUTING 1
次に、このカスタムルールを追加します-
iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT --to-source 192.168.1.2
マスカレードは172.17.42.1からではなく、むしろ
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
つまり、このルールは正しく機能しません。
ip rule add from 172.17.42.1 table docker
代わりに試してください
ip rule add from 172.17.0.0/16 table docker