designetwork

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

Docker対応PBRで複数NICのLinuxで必ず受信IFから応答(非対称ルーティング回避)するよう設定する

運用NICを持つLinuxサーバなどでは、非対称ルーティングを回避するためにPBR(Policy-Based Routing: ポリシーベースルーティング)を設定する場合がある。Dockerコンテナ宛通信もPBR対象とするためには、単純なソースIFでのPBRだけでは制御できないため、fwmarkにより通信を識別し、応答IFを固定する。

OS:CentOS7

NIC構成

eth0が通常NICで、こちらをデフォルトGWに設定している。eth1は運用用として、特定宛先との通信に使用する。運用セグメントからはeth0, eth1ともにアクセスするが、通常ルーティングでは応答パケットはeth0から送信される。

# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether <MAC1> brd ff:ff:ff:ff:ff:ff
    inet <IP0> brd <BRD0> scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether <MAC1> brd ff:ff:ff:ff:ff:ff
    inet <IP1> brd <BRD1> scope global noprefixroute eth1
       valid_lft forever preferred_lft forever

複数NIC時のPBR

通常の複数NIC構成時のPBRは以下の記事の通り設定できる。 blog.serverworks.co.jp

www.nextdoorwith.info

Docker宛通信を制御可能にする

しかし、Docker宛通信は上記では制御できない。そのため、以下の通り設定する。

serverfault.com

forums.docker.com

NetworkManagerのdispatcher機能を有効にする。

yum install NetworkManager-config-routing-rules
systemctl enable NetworkManager-dispatcher.service
systemctl start NetworkManager-dispatcher.service

ルーティングテーブルを追加する。ここではeth1という名前で作成する。

# vi /etc/iproute2/rt_tables 
---
#
# reserved values
#
255 local
254 main
253 default
0   unspec
#
# local
#
#1  inr.ruhep
100 eth1 ###Add###

運用NICのruleを作成する。通常はここはfrometh1IPアドレスを設定するが、fwmarkで設定する。
eth1はサーバのIF名に合わせて要調整。

# vi /etc/sysconfig/network-scripts/rule-eth1 
fwmark 0x1 table eth1

運用NICからの通信用ルートを作成する。

# vi /etc/sysconfig/network-scripts/route-eth1
0.0.0.0/0 via <GW1> table eth1

networkサービスを再起動する。

systemctl restart network.service

ルールが追加された。

# ip rule show
0:  from all lookup local 
32765:  from all fwmark 0x1 lookup eth1 ###Added###
32766:  from all lookup main 
32767:  from all lookup default 

ルールにマッチするようfwmarkを付与するiptablesを設定する。

iptables -t mangle -A PREROUTING -m conntrack ! --ctstate NEW --ctdir REPLY -m connmark ! --mark 0x0 -j CONNMARK --restore-mark
iptables -t mangle -A OUTPUT -m conntrack ! --ctstate NEW --ctdir REPLY -m connmark ! --mark 0x0 -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -i eth1 -m conntrack --ctstate NEW --ctdir ORIGINAL -j CONNMARK --set-mark 0x1

これにより、eth1で受けたリクエストはeth1から応答するようになる。

iptablesの設定を永続化する

iptablesコマンドで設定した内容は再起動時に揮発してしまうため、設定ファイルを作成して永続化する。

access.redhat.com

https://tech.godpress.net/?p=503

firewalldは停止し、iptablesサービスをインストール・有効化する。

systemctl disable firewalld
systemctl stop firewalld

yum install iptables-services
systemctl enable iptables
systemctl start iptables

起動時に読み込むiptablesのルールを作成する。個別の設定がある場合はiptables saveを使用して調整する。

# vi /etc/sysconfig/iptables.save
*mangle
-A PREROUTING -m conntrack ! --ctstate NEW --ctdir REPLY -m connmark ! --mark 0x0 -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
-A PREROUTING -i eth1 -m conntrack --ctstate NEW --ctdir ORIGINAL -j CONNMARK --set-xmark 0x1/0xffffffff
-A OUTPUT -m conntrack ! --ctstate NEW --ctdir REPLY -m connmark ! --mark 0x0 -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
COMMIT

まとめ - Docker対応PBRで複数NICLinuxで必ず受信IFから応答(非対称ルーティング回避)するよう設定する

fwmarkによるPBRを設定することで、Dockerコンテナ宛通信においても非対称ルーティングを回避し、受信IFから応答するようにできる。