二つのサイトにまたがる三台のマネージャーと五台のワーカーをトンネルで接続したところ、docker service ls では両側でタスクが動作しているのに、サービス間の呼び出しはタイムアウトする。Swarm のログに異常は見当たらない。この組み合わせはデータプレーン問題の典型だ。コントロールプレーンはノードを見つけたが、カプセル化されたフレームは目的地に到達していない。

overlay より先にメッシュが必要だ

Swarm の overlay はカプセル化したフレームをノードのアドレス間で直接送る。つまり各ノードには、他のすべてのノードが変換なしで到達できるアドレスが、トンネルが提供するインターフェース上で必要になる。クライアントを公開ポートへ運ぶだけのトンネルでは足りない。アンダーレイは双方向にノード間をルーティングできなければならない。

Swarm に触る前にこれを試す。各ノードからピアのトンネルアドレスへのルートを確認し、ping を打ち、そのうえで制御ポートを試す。ping が通り、ポートが通らないなら、トンネルは健全でフィルタが邪魔をしている。

ip -brief address
ip route get 10.20.0.12
ping -c3 10.20.0.12
nc -vz 10.20.0.12 2377

ルートが tun0 や wg0 ではなく物理インターフェースを指していると、overlay は遠隔サイトが到達できないアドレスにカプセル化し、症状はパケット損失のように見える。

各ノードがどのアドレスを広告しているかを確認する

デーモンは一つのアドレスを広告し、ピアはそれをデータプレーンに使う。複数ネットワークを持つホストでは、トンネルが別のものを運んでいるのに LAN やパブリックのアドレスを広告しがちだ。推測せずに確認し、既定値が誤っている場合は参加時に --advertise-addr で固定する。自分だけが到達できるアドレスを広告したノードも swarm には参加でき、障害は後からサイト間で通信できないサービスとして現れる。

広告アドレスを後から変えるのは設定編集ではない。ノードは離脱して再参加する必要がある。

ノードごとの広告アドレスをメモに残す。非対称な障害のほとんどを説明できる。

犯人はたいてい masquerade だ

ノードとトンネルの間にゲートウェイがあるとき、よくある間違いは物理インターフェースから出るすべてに masquerade をかけることだ。これは overlay の内部アドレスも書き換えるため、すべてのピアがゲートウェイから来たように見え、VXLAN のピア同士が認識しなくなる。結果として、通常の ping は通るのにカプセル化トラフィックが欠落したり片方向になったりする。

overlay のプレフィックスはゲートウェイ経由でルーティングし、変換しないままにする。別のプレフィックスに変換が本当に必要なら、そこに限定し、overlay が使う範囲には決して適用しない。

ip route add 172.16.0.0/22 via 10.20.0.1
iptables -t nat -I POSTROUTING -o tun0 -s 172.16.0.0/22 -j ACCEPT

ルールの順序も本文も確認する。チェーンの前にある広い MASQUERADE は、後にある狭い例外に勝つ。

VXLAN はパケット内の余裕を必要とする

VXLAN は運ぶフレームに 50 バイトを追加する。1500 バイトのアンダーレイが 1500 バイトの内部フレームを運ぶと、どの経路も配信できないカプセル化パケットが生まれ、障害はサイズ問題ではなく断続的なサービスディスカバリのように見える。両端でトンネルの MTU を下げるか、overlay の MTU を設定してドライバーが収まるペイロードを広告するようにする。

docker network create --driver overlay --attachable --opt com.docker.network.driver.mtu=1400 swarm-overlay

ingress ネットワークは自動で作られるため、変更するにはその場で編集するのではなく削除して作り直す必要がある。

トンネルの片側だけを直しても、小さいほうの MTU が依然として効いてくる。

ログではなくデータプレーンを見る

両端で VXLAN ポートをキャプチャする。片側を出て反対側に届くフレームは、アンダーレイが健全で問題が overlay の内側にあることを意味する。出て行って届かないフレームはルートかフィルタを意味する。まったく出ないフレームは送信元アドレスが誤っていることを意味する。

数秒で解消するサービスディスカバリの失敗は、通常はパケットの余裕か不安定な経路を示しており、raft のクォーラムではない。

正常な時間帯のキャプチャを残しておく。壊れたときのものと比べるほうが、設定を読み直すより速い。

関連記事