Kubernetesネットワークの深淵:なぜ「NATなし」のPod間通信が魔法のように機能するのか?
こんにちは。SREとして日々クラウドの巨大なインフラと格闘していると、ふと「当たり前」の挙動に疑問を抱く瞬間があります。
「KubernetesのPodは、なぜ別々のノードにいてもNAT(ネットワークアドレス変換)なしで相互通信できるのか?」
この問いに即答できないまま運用していると、いざ本番環境でパケットがロストした際に地獄を見ることになります。今日は、表面的な設定方法ではなく、パケットがどう考え、どうノードを飛び越えているのか、その「現場の視点」から解説します。
—
1. Kubernetesネットワークモデルの「鉄の掟」
Kubernetesが定めるネットワークモデル(いわゆるIP-per-Podモデル)には、非常にシンプルな、しかし強力な要件があります。
1. すべてのPodは、NATなしで他方のPodと通信できること。
2. すべてのノードは、NATなしで他方のPodと通信できること。
3. Pod自身が認識しているIPアドレスと、他のPod/ノードから見えるIPアドレスは同一であること。
この「NATなし」という制約が、クラウドネイティブなサービス間通信の柔軟性を生んでいる一方で、我々インフラエンジニアには「どうやってルーティングテーブルを制御するか」というパズルを突きつけてきます。
—
2. CNI(Container Network Interface)という調停者
Kubernetesのネットワークを抽象化し、プロバイダーごとに異なる実装を隠蔽するのが CNI です。Kubeletは、Podが起動するたびに CNI plugin を呼び出し、「このPodにIPを割り当てて、ネットワークに繋いでくれ」と依頼します。
ここで主要なプレイヤーである Flannel と Calico の思想の違いを理解しておきましょう。
Flannel:シンプルさの追求(L3オーバーレイ)
Flannelは主に VXLAN を使います。PodのパケットをUDPヘッダーで包み込み(カプセル化)、ノード間でトンネリングします。「物理ネットワークがどうなっていようが、とりあえずL2ネットワークを仮想的に作ってしまえ」というアプローチです。
Calico:パフォーマンスの追求(L3ルーティング)
Calicoは BGP を使います。各ノードをルーターと見なし、PodのIPアドレスへの経路情報をノード間で直接交換します。カプセル化によるオーバーヘッドがないため、大規模・高負荷な環境では圧倒的に有利です。
—
3. 現場で役立つデバッグ手順:パケットを追跡せよ
もしAPIの通信で Connection Refused や Timeout が発生したら、まずどこで止まっているかを確認します。私は障害対応時、必ず以下のステップを踏みます。
Step 1: PodのIPとルートを確認する
まずは、現在のPodがどのIPを持ち、どんな経路を通っているかを見ます。
# 特定のPod内のルーティングテーブルを確認
kubectl exec <pod-name> -- ip route show
# ノード側のルーティングテーブル(Calicoの場合、BGPルートが見えるはず)
ip route show | grep <pod-cidr>
Step 2: 疎通確認(Curlでレイヤーを切り分ける)
アプリケーション層の問題か、ネットワーク層の問題かを切り分けるために、まずは低レイヤーから攻めます。
# Pythonで簡易サーバーを立ち上げてテスト
# サーバー側(Pod A)
python3 -m http.server 8080
# クライアント側(Pod B)から叩く
curl -v http://<pod-a-ip>:8080
Step 3: パケットキャプチャで「迷子」を探す
それでも解決しない場合、tcpdump の出番です。ノードの物理インターフェース(eth0等)と、仮想インターフェース(veth...)の両方でパケットをキャプチャし、カプセル化が正しく行われているか、あるいはパケットが破棄されていないかを確認します。
# 特定のノードでPod宛の通信をキャプチャ
tcpdump -i any host <pod-a-ip> -nn
—
4. 実務で知っておくべきパラメーター:Calico設定例
Calicoを利用する場合、ippool の設定は運用の要です。特にクラウド環境(AWSのVPCなど)では、IPAM の設定に注意が必要です。
# calico-ippool.yaml
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: default-ipv4-ippool
spec:
cidr: 192.168.0.0/16
# IPIPカプセル化を有効にするか(クラウド環境でネットワーク制限がある場合に利用)
ipipMode: Always
natOutgoing: true # Podから外の世界へ出る際のNATを許可するか
natOutgoing: true にしておくと、Podは外部インターネットと通信できますが、false にすると完全に閉じられたプライベートなネットワークとして機能します。APIのセキュリティ要件に合わせて、このスイッチを正しく制御してください。
—
まとめ:ネットワークは「見える化」が全て
Kubernetesネットワークのトラブルシューティングは、最初はブラックボックスのように感じられるかもしれません。しかし、CNIがどのインターフェースを作成し、どのルーティングテーブルを書き換えているのかを理解すれば、それは「手に負えない魔法」から「制御可能なインフラ」へと変わります。
- Flannel はカプセル化でネットワークを「誤魔化す」
- Calico はルーティングでネットワークを「正統に導く」
まずは、自分のクラスタのCNIがどちらで動いているのか、そしてノードの ip route がどうなっているのかを確認するところから始めてみてください。現場からは以上です。もし特定の設定で詰まったら、いつでも聞いてくださいね。
コメント