Kubernetesネットワーキング上級編:CalicoのBGPパターンを徹底解説

16 2025年5月 張掖

最近、ある学生から、次のようなアドバイスを求められた。 Kubernetesクラスタ適切なネットワーク・プラグインを選択すること、そして異なるネットワーク・プラグイン間の実装原理と違いは何か。正直なところ、この質問に答えるのは今のところ難しい。 何しろCNCFのエコシステムには、Calico、Flannel、Cilium、Kube-OVNなど、目もくらむようなネットワーク・プラグインがたくさんあるのだから。

同じネットワーク・プラグインでも、ダイレクト・ルーティング、ブリッジ、IPIP、VXLAN、eBPFなど、複数のネットワーキング・モードがあり、それぞれに独自の技術的特性やアプリケーション・シナリオがある。

このような複雑な状況を前にして、一言で明らかにするのは本当に難しい。

次に、Calicoのネットワークプラグインを例にして、いくつかの記事を通じて、様々なネットワークモードの実装原理を深く分析し、それぞれの適用シナリオを議論し、最後に、顧客の実際の使用シナリオと組み合わせて、適切なネットワークプラグインとネットワークモードを選択する方法を詳しく説明する予定です。

Kubernetesネットワーキングの基礎の復習

Calicoを紹介する前に、Kubernetesのネットワークについておさらいしておこう。Kubernetesのネットワークモデルは、以下のコンポーネントで構成されている:

  • IPアドレスの割り当て:クラスタ内の各Podには一意のIPアドレスが割り当てられる。Pod内部では、すべてのコンテナが同じネットワーク名前空間を共有し、異なるコンテナ間のプロセスはlocalhostまたは127.0.0.1を介して通信できる;
  • Pod間通信:クラスタ内の任意の2つのPodは、同じノード上にあるかどうかに関係なく、プロキシやアドレス変換(NAT)を必要とせずに相互に通信できます;
  • ServiceとPodの通信:クラスタはServiceを通じてバックエンドPodに統一されたアクセスポータルを提供します。 各Serviceは安定したIPアドレスを持つため、バックエンドPodが動的に変更されても、クラスタはロードバランシングポリシーに従ってService IPを通じてバックエンドPodにトラフィックを分散できます;
  • Podはクラスタの外部と通信する。クラスタはGateway APIを通じて高度な経路管理機能を提供し、クラスタ内部のサービスを外部に公開できるようにするとともに、外部サービスによるクラスタリソースへのアクセスを容易にする;
  • ネットワークポリシーの制御:クラスタはNetworkPolicyを使用して、Pod間およびPodと外部サービス間のトラフィックを細かく制御できます。アクセスルールを設定することで、ネットワークのセキュリティが保証され、ビジネスの分離が実現します;

Kubernetesは、ネットワークモデルを定義するだけで、それ自体がコンテナネットワーク接続を実装していませんが、コンテナネットワークインターフェイスCNIを介してネットワークプラグインを呼び出すには、ネットワークプラグインは、特定の構成のコンテナネットワーク接続を完了し、作業を構築する。

Calicoは、KubernetesクラスタのIPアドレス割り当てや効率的なポッド間通信を可能にするだけでなく、ネットワークの分離やアクセス制御といった強力なネットワークポリシー機能も提供する優れたネットワークプラグインだ。

さらに、CalicoはKubernetesのService APIおよびGateway APIと密接に連携し、Podとサービス間、およびPodとクラスタ外部間の通信を最適化する安定したネットワーク・トポロジーを構築することで、Kubernetesクラスタ全体のネットワーク・パフォーマンスとセキュリティを向上させる。

キャラコのコンポーネントとアーキテクチャ

キャラコ コア・コンポーネントには、calico-kube-controllers、calico-node、etcdがある:

1. calico-kube-controllerはDeployment形式で配置され、ネットワークポリシーの同期、IPプールの管理、ノードステータスの監視、その他の重要なタスクを担当する;

2.calico-nodeは、Kubernetesクラスタの各ノード上でデーモンとして実行され、Calicoのネットワークポリシーの適用、ルートの管理、ネットワークインターフェイスの設定などの主要なタスクの実行を担当する。内部的には複数のプロセスで構成されている:

  • Felix:ノード上のネットワーク・インターフェース管理、経路設定、アクセス制御リスト(ACL)管理を担当し、クラスタ内のネットワーク・ポリシーと設定を監視し、その情報に基づいてクラスタ・ノード上のネットワーク・インターフェースとルーティング・ルールを動的に設定します;
  • BGPクライアントは、Felixからルーティング情報を取得し、BGP(Border Gateway Protocol)を使用してクラスタ内の他のノードのBIRDプロセスに配布してルーティング情報を交換し、ポッドのノード間ネットワーク通信を実現します。ネットワーク通信を実現します;
  • Confd:クラスタ内のコンフィギュレーション変更をリスニングし、コンフィギュレーションの更新を検出すると関連するコンフィギュレーションファイルを再生成し、BIRDなどのプロセスにコンフィギュレーションの再ロードを通知する;
  • CNI:KubernetesクラスタにCalicoネットワークを提供し、Podの作成と破棄時にCalicoネットワーク構成に従ってコンテナ用のネットワークインターフェイスを設定する。これには、クラスタ内の各Podに一意のIPアドレスを割り当てること、PodのネットワークインターフェースをCalicoネットワークに接続すること、Podのネットワークインターフェースに適切なアクセス制御ルールを設定することが含まれます;

3.etcd:Calicoのストレージシステムとして、Calicoのネットワーク設定、ポリシールール、IPアドレス割り当て、その他のデータを保存する役割を担う;

BGP、IPIP、VXLANなど、Calicoはさまざまなネットワーク方式をサポートしています。今回は、Calicoの最も基本的なBGPモードから始めましょう。

キャリコBGPモード

BGP(Border Gateway Protocol)とは、主に異なるAS(Autonomous System)間でルーティング情報を交換するために使用される、TCPベースのアプリケーション層分散型自律ルーティングプロトコルです。TCP接続を通じて、異なるAS間のBGPルーターは近隣関係を確立することができます。

接続が確立されると、両者はローカルネットワークの到達可能性や他のネットワークへの経路に関する情報を含むBGPルーティング情報を交換する。

BGPルーターは、同じ宛先への複数の経路を受信すると、経路属性(ASパス長、ネクストホップアドレス、ローカル優先度など)とポリシーに基づいて最適な経路を選択します。

Calicoネットワークでは、クラスタのノードが仮想ルータ(vRouter)として動作し、その後、ノード上で動作するPodネットワークのルーティング情報をBGPプロトコルによってCalicoネットワーク全体に伝搬することができるため、クラスタ内のPodはホストルーティングによって効率的かつ透過的なネットワーク接続を実現できる。

Calico BGPモードでPodのネットワークトラフィックを転送するプロセスに入る前に、Calicoネットワーキングプラグインがインストールされ、BGPモードが開始に設定されたKubernetesクラスタを準備する必要があります。

Kubernetesクラスタの構築

Kubernetesを構築するためのツールはコミュニティにたくさんあるが、ここではkebekeyを使う:

# installing kubekey $exportKKZONE=cn $curl -sfL https://get-kk.kubesphere.io | VERSION=v3.0.13 sh - # installing Kubernetes cluster and Calico plugin with BGP enabled.schema $cat > cluster.yaml <<EOF apiVersion: kubekey.kubesphere.io/v1alpha2 kind: Cluster metadata: name: zlw-cluster spec: hosts: - {name: 10-23- 14-11014-110, address: 10.23.14.110, internalAddress: 10.23.14.110, user: root, sshKey: "~/.ssh/id_rsa"} - {name: 10-23-14-111, address: 10.23.14.111名前:10-23-14-111、アドレス:10.23.14.111、internalAddress:10.23.14.111、ユーザー:root、sshKey:"~/.ssh/id_rsa"} - {名前:10-23-14-112、アドレス:10.23.14.112、internalAddress:10.23.14.112, user: root, sshKey: "~/.ssh/id_rsa"} - {name: 10-23-14-113, address: 10.23.14.113, internalAddress: 10.23.14.113, user: root, sshKey: "~/.....ssh/id_rsa"} - {name: 10-23-14-114, address: 10.23.14.114, internalAddress: 10.23.14.114, user: root, sshKey: "~/.ssh/id_rsa"} - {name: 10-23-...14-115、address: 10.23.14.115、internalAddress: 10.23.14.115、user: root、sshKey: "~/.ssh/id_rsa"} roleGroups: etcd: - 10-23-14-110 - 10-23-14-111111 - 10-23-14-112 コントロールプレーン: - 10-23-14-110 - 10-23-14-111 - 10-23-14-112 ワーカー: - 10-23-14-113 - 10-23-14-114 - 10-23-14-115controlPlaneEndpoint: domain: lb.kubesphere.local address: "" port: 6443 kubernetes: version: v1.32.0 clusterName: cluster.local network.plugin: calico kubePodsCIDR: 10.233.0.0/16 kubeServiceCIDR: 10.96.0.0/16 calico: ipipMode: Never vxlanMode: Never bgp: enabled: true asNumber.64512 peerSelector: all() EOF $kk create cluster -f cluster.yaml -y --debug

今回の実験では、10-23-14-110、10-23-14-111、10-23-14-112をクラスタのマスターノードとして、10-23-14-113、10-23-14-114、10-23-14-115をワーカーノードとして、6台のマシンを用意しました。

以上で、CalicoネットワークプラグインがインストールされたKubernetesクラスタを取得できる。続いて、ノード10-23-14-110で以下のコマンドを実行し、Calicoのネットワーク状態を確認する:

$ kubectl get IPPool default-ipv4-ippool -oyaml apiVersion: crd.projectcalico.org/v1 kind: IPPool metadata: name: default-ipv4-ippool spec.allowedUses: - ワークロード - トンネル blockSize: 24 cidr: 10.233.0.0/16 ipipMode: Never natOutgoing:true nodeSelector: all() vxlanMode: Never $calicoctl ノードステータス Calico プロセスは実行中です。 IPv4 BGP ステータス +--------------+-------------------+--------------+-------------+ | PEERADDRESS | PEER TYPE | STATE | SINCE | INFO | +--------------+-------------------+--------------+--------------+ | 10.23.14.111 | node-to-nodeメッシュ|上|12:31:31|確立||10.23.14.112|ノード間メッシュ|上|12:31:30|確立||10.23.14.113|ノード間メッシュ|上|12:31:32|確立||10.23.14.113|ノード間メッシュ|上|12:31:32|確立確立|10.23.14.114|node-to-nodeメッシュ|up|12:31:31|確立|10.23.14.115|node-to-nodeメッシュ|up|12:31:31|確立| +--------------+-------------------+-------+----------+-------------+ IPv6 BGP ステータス IPv6 ピアが見つかりません。

キャリコネットワークプラグインはオーバーレイネットワークとアンダーレイネットワークの両方のネットワークソリューションを提供します。Overlay Networkの実装はIPIPとVXLANモードを含み、Underlay Networkの実装はBGPモードです。

現在のキャリコIPPoolコンフィギュレーションでは、ipipModeとvxlanMode属性はともにNeverであり、IPIPとVXLANモードが使用されておらず、代わりにBGPモードが使用されていること、つまりUnderlay Networkが使用されていることを示している。

さらに、ノード10.23.14.110上のCalicoプロセスが実行中であり、10.23.14.111から10.23.14.115までの5台のマシンにIPv4 BGP接続を確立していることがわかります。ノード間メッシュのPEER TYPEは、BGPにフルメッシュモード(フル相互接続モード)が使用されていることを示しています。つまり、クラスタ内の各ノード間でBGP接続が確立されています。

CalicoのBGPがFullMeshモードでどのように通信するのかを明確にするために、同じノードと異なるノードの2つの次元からPodの通信プロセスを開始する。

コ・ノード・ポッド・ネットワーク通信

まず、クラスターに2つのレプリカをデプロイし、ノード10-23-14-110で両方稼働させた:

$ kubectl get pods -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES zlw-01 1/1 Running 0 1h 10.233.133.2 10-23-14-110   zlw-02 1/1 実行中 0 1h 10.233.133.3 10-23-14-110  <none

ご覧のように、レプリカzlw-01とzlw-02のPodIPは、それぞれ10.233.133.2と10.233.133.3です。次に、以下のコマンドを実行してネットワーク接続性をテストします:

$ kubectlexec-it zlw-01 -- ping -c 1 10.233.133.3 PING 10.233.133.3 (10.233.133.3) 56(84) バイトのデータ 10.233.133.3 から 64 バイト: icmp_seq=1ttl=63 time=0.149 ms --- 10.233.133.3 ping 統計 --- 1 パケット送信, 1 パケット受信, 0% パケットロス, 時間 0ms rtt min/avg/max/mdev = 0.075/ 0.075/ 0.075/ 0.075/ 0.075/ 0.075/ 0.075/ 0.0750.075/0.075/0.000 ms

レプリカzlw-01でzlw-02のPodIPにアクセスすると、正常に応答が返ってくる。では、同じノードの2つのレプリカ間のトラフィックの転送処理はどうなっているのでしょうか?

コンテナからホストへ

コピーzlw-01のネットワーク機器を見てみよう:

$ kubectlexec-it zlw-01 -- ip a 1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00:00 brd 00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: tunl0@NONE:  mtu 1480 qdisc noopstate DOWN group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 3: eth0@if3120:  mtu 1500 qdisc noqueue state UPgroup default qlen 1000 link/ether 4a:8d:0e:93:6a:39 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.233.133.2/32 scope global eth0 valid_lft foreverpreferred_lft forever

ip aコマンドはip addrの略で、その出力を見ると、コピーzlw-01のeth0 NICアドレスは10.233.133.2であり、zlw-01のPodIPアドレスと全く同じであることがわかる。

コンテナの eth0 NIC は単独で表示されるわけではなく,Calico はコンテナを作成する際に,コンテナ用の仮想イーサネットカードのペア(veth ペア)を生成する.たとえば、eth0@if3120は、レプリカzlw-01内のコンテナのeth0カードと、ノード内のインデックス番号3120のカードがethペアであることを意味する。

次にコピーzlw-01のルーティングテーブル情報を見てみる:

$ kubectlexec-it zlw-01 -- ip r default via 169.254.1.1 dev eth0 169.254.1.1 dev eth0 scope link $ kubectlexec-it zlw-01 -- route -n Kernel IPルーティングテーブル 宛先 ゲートウェイ ゲンマスク フラグ メトリック 参照 使用 Iface 0.0.0.0 169.254.1.1 0.0.0 UG 0 0 0 eth0 169.254.1.1 0.0.0.0 255.255.255.255 UH 0 0 00 eth0

default via 169.254.1.1 dev eth0 はタウトとして機能するデフォルトルートである。169.254.1.1 dev eth0 scope linkは直接接続ルートで、169.254.1.1とeth0が同じリンク上にあり、パケットが他のゲートウェイを経由せずにこのリンクで直接送信できることを示します。

キャリコでは、169.254.1.1がデフォルトゲートウェイとして動作する。ルーティングテーブルで明示的にマッチしていない外部アドレス(つまり宛先アドレスが0.0.0.0)を宛先とするパケットがコンテナ内で生成されると、これらのパケットはコンテナ内のeth0 NICを通過し、ノードのcali NICに到着した後、デフォルトゲートウェイの169.254.1.1に転送され、その後のパケットの転送を担当する。

先にも述べたように、ノード10-23-14-110上で稼働しているレプリカzlw-01には、ノード内のインデックス番号3120のvethペアであるコンテナeth0 NICがあるので、10-23-14-110上で以下のコマンドを実行することで、対応するcali NICを見つけることができる:

$ ip a | grep -A 3 3120 3120: calife4cf73bf2a@if3:  mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 2 inet6 fe80::ecee:eeff:feee:eee/64 scope link valid_lft forever preferred_lft永久に

出力から、インデックス3120のcali NICはcalife4cf73bf2aであることがわかる。 このNICはIPアドレスを持っておらず、そのMACアドレスはee:ee:ee:ee:ee:ee:eeである。

次に、tcpdumpコマンドを使って、NIC calife4cf73bf2aのトラフィックをリッスンする:

$ tcpdump -i calife4cf73bf2a -ne 03:24:05.122338 4a:8d:0e:93:6a:39 > ee:ee:ee:ee:ee:ee:ee, ethertype ARP (0x0806), length 42: Request who-has169.254.1.1 tell 10.233.133.2, length 28 03:24:05.122390 ee:ee:ee:ee:ee:ee > 4a:8d:0e:93:6a:39, ethertype ARP (0x0806), length 42: Reply 169.254.1.1 is-at ee:ee:ee:ee:ee:ee, length 28 03:24:05.122407 ee:ee:ee:ee:ee:ee > 4a:8d:0e:93:6a:39, ethertype ARP (0x0806), length 42: Request who-has10.233.133.2 tell 10.23.14.110, length 28 03:24:05.122416 4a:8d:0e:93:6a:39 > ee:ee:ee:ee:ee:ee, ethertype ARP (0x0806), length 42: Reply 10.233.133.2 is-at 4a:8d:0e:93:6a:39、長さ 28

このことは、リスニングのアウトプットからわかる:

1.レプリカzlw-01のeth0 NIC(IPアドレス10.233.133.2、MACアドレス4a:8d:0e:93:6a:39)が169.254.1.1のMACアドレスに対してARPリクエストを開始した。ノード10-23-14-110のcali NIC calife4cf73bf2a(MACアドレスee:ee:ee:ee:ee:ee:ee:ee:ee:ee:ee:ee:ee)がリクエストに応答し、169.254.1.1が以下のMACアドレスであることを確認した。ノード 10-23-14-110 の(MAC アドレス ee:ee:ee:ee:ee:ee:ee:ee:ee)がリクエストに応答し、169.254.1.1 の MAC アドレスが ee:ee:ee:ee:ee:ee であることを確認しました;

2.ノード10-23-14-110はcalife4cf73bf2a NIC経由でレプリカzlw-01のeth0 NICに10.233.133.2のMACアドレスのARPリクエストを開始した。レプリカzlw-01のeth0 NIC(MACアドレスは4a:8d:0e:93:6a:39)はリクエストに応答し、10.233.133.2のMACアドレスが4a:8d:0e:93:6a:39であることを確認しました。

キャリコのデフォルト・ゲートウェイである169.254.1.1が、なぜMACアドレスがee:ee:ee:ee:ee:ee:eeなのか?

実際には、169.254.1.1は、キャリコがコンテナ・ネットワーク用に仮想化したデフォルト・ゲートウェイIPであり、実際の物理デバイスIPではない。

zlw-01がデフォルトゲートウェイ169.254.1.1のMACアドレスを問い合わせるために、eth0 NICを介してARPリクエストを開始すると、ノードのeth0に対応するcali NIC calife4cf73bf2aは、プロキシARPを介してコンテナのARPリクエストに応答し、自身のMACアドレス、すなわちee:ee:ee:ee:ee:eeを返す。

Calico は cali NIC をコンテナとノード(つまり veth ペアの反対側)間の仮想ブリッジとして使用する。 Proxy ARP により、169.254.1.1 へのコンテナのトラフィックは、宛先 MAC アドレス ee:ee:ee:ee:ee を持つデータフレームとしてカプセル化され、コンテナの eth0 NIC からノードの cali NIC に移動する。データフレームはコンテナの eth0 NIC からノードの cali NIC に移動し、ノードのルーティングおよび転送機能を使用してネットワーク通信を実現する。

ノード10-23-14-110のcali NIC calife4cf73bf2aでプロキシARP機能が有効になっていることを確認するには、ノード上で以下のコマンドを実行します。

$ cat /proc/sys/net/ipv4/conf/calife4cf73bf2a/proxy_arp 1

戻り値1は、cali NIC calife4cf73bf2aがプロキシARP機能を有効にし、ARPリクエストに代わりに応答できることを意味する。

次に、tcpdumpコマンドを使ってレプリカzlw-01へのトラフィックをリッスンし続けながら、別の新しいターミナルで以下のコマンドを実行します。kubectl exec -it zlw-01 - ping -c 1 10.233.133.3:

10:20:32.661779 4a:8d:0e:93:6a:39 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 98: 10.233.133.2 > 10.233.133.3: ICMPechorequest, id 12, seq 1, length 64 10:20:32.661882 ee:ee:ee:ee:ee:ee > 4a:8d:0e:93:6a:39, length 64seq1、長さ64 10:20:32.661882 ee:ee:ee:ee:ee:ee > 4a:8d:0e:93:6a:39, ethertype IPv4 (0x0800), length 98: 10.233.133.3 > 10.233.133.2。ICMPechoreply, id 12, seq 1, length 64

レプリカ zlw-01 が zlw-02 に ICMP リクエストを送信するとき、トラフィックはコンテナの eth0 NIC から送信され、veth ペアを経由してノードの cali NIC calife4cf73bf2a に到着することがわかります。このとき、送信元 IP は 10.233.133.2(レプリカ zlw-01 の IP アドレス)、送信先 IP は 10.233.133.3(レプリカ zlw-02 の IP アドレス)、送信元 MAC アドレスは 4a.8d.0e:93:6a:39(レプリカ zlw-02 の eth0 NIC の MAC アドレス)です。133.3(レプリカzlw-02のIPアドレス)、送信元MACアドレスは4a:8d:0e:93:6a:39(レプリカzlw-01のeth0 NICのMACアドレス)、宛先MACアドレスはee:ee:ee:ee:ee:ee:ee:ee:ee(レプリカzlw-01のcali NIC calife4cf73bf2aのMACアドレス)である。アドレス)であり、最終的にトラフィックはノードに到達する。

次に、レプリカzlw-01からのトラフィックが、同じノードのレプリカzlw-02にどのように転送されるかを見てみましょう。

ホストからコンテナへ

まずはコピーzlw-02のネットワーク機器を見てみよう:

$ kubectlexec-it zlw-02 -- ip a 1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00:00 brd 00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: tunl0@NONE:  mtu 1480 qdisc noopstate DOWN group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 3: eth0@if3121:  mtu 1500 qdisc noqueue state UPgroup default qlen 1000 link/ether 7a:45:c9:63:d5:75 brd ff:ff:ff:ff:ff-netnsid 0 inet 10.233.133.3/32 scope global eth0 valid_lft foreverpreferred_lft forever

そして、ノード内のインデックス番号3121のNICデバイスを見つけることができる:

ip a | grep -A 3 3121 3121: cali957267df2c7@if3:  mtu 1500 qdisc noqueue state UP group default qlen 1000 link/etheree:ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff link-netnsid 3 inet6 fe80::ecee:eeff:feee:eeee/64 scope link valid_lft forever preferred_lft forever

従って、ノード10-23-14-110のcali NIC cali957267df2c7とレプリカzlw-02のeth0 NICはethペアであることが確認できる。

次にノード10-23-14-110のルーティングテーブルを見ると、以下のようになっている:

$ ip route 10.233.133.2 dev calife4cf73bf2a scope link src 10.23.14.110 10.233.133.3 dev cali957267df2c7 scope link src 10.23.14.110

10.233.133.2とcalife4cf73bf2aは、それぞれレプリカzlw-01のPodIPとcali NICであり、10.233.133.3とcali957267df2c7は、それぞれレプリカzlw-02のPodIPとcali NICである。zlw-01とzlw-02のcali NICが同じノード間リンク上にあることを意味します。

10.233.133.2が10.233.133.3にアクセスする場合、両者は同じリンクにあるため、ゲートウェイやNATの処理を追加することなく、MACアドレス経由でパケットをレイヤー2リンク経由で直接送信することができる。

10.233.133.3宛てのパケットはzlw-01のeth0 NICから送信され、反対側のcalife4cf73bf2a NICを通過してノードに入り、ノードのレイヤ2ネットワークでzlw-02のcali957267df2c7 NICに転送される。

最後に、トラフィックは cali957267df2c7 NIC を経由して、反対側にある zlw-02 の eth0 NIC に到達し、コンテナ zlw-02 に入る。レプリカzlw-02のeth0 NICで以下のデータをリッスンできる:

$ kubectlexec-it zlw-02 -- tcpdump -i eth0 -ne tcpdump: verbose output suppressed, use -v[v].....forfull protocol decode listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes 04:29:50.685440 ee:ee:ee:ee:ee:ee > 7a:45:c9:63:d5:75, ethertype IPv4 (0x0800), length 98: 10.233.133.2 > 10.233.133.3: ICMPechorequest, id 17, seq 1, length 64 04:29:50.685460 7a:45:c9:63:d575 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 98: 10.233.133.3 > 10.233.133.2: ICMPechoreply, id 17, seq 1, length 64

ご覧のように、トラフィックがレプリカ zlw-02 に入るとき、送信元 IP は 10.233.133.2(レプリカ zlw-01 の IP アドレス)、送信先 IP は 10.233.133.3(レプリカ zlw-02 の IP アドレス)、送信元 MAC アドレスは ee:ee:ee:ee:ee:ee:ee(レプリカ zlw-02 の cali カードの MAC アドレス)、送信先 MAC アドレスは 7a:45:c9:63:d5:75(レプリカ zlw-02 の cali カードの MAC アドレス)です。レプリカzlw-02のcali957267df2c7)、宛先MACアドレスは7a:45:c9:63:d5:75(レプリカzlw-02のeth0 NICのMACアドレス)です。

要約すると、同じノードPod上のネットワーク・トラフィックの場合、トラフィックはeth0 NICの1つのコピーから送信され、vethペア経由でノード上の反対側のcali NICに到着する。2つのキャリNICは同じノードの仮想リンク(vethペアを介して対応するコンテナに直接接続されている)に属しているため、データフレームはMACアドレスを介してレイヤ2リンク上で直接送信され、ノードカーネルは仮想リンク上のポイントツーポイント接続を介して、レイヤ2ネットワーク上のもう一方のレプリカのキャリNICにデータフレームを転送します。

その後、ターゲットキャリNICは、ethペアを通して、対応するコンテナのeth0 NICにデータフレームを転送し、最後に、レスポンスパケットが元のルートを通して返され、通信プロセス全体が完了する。

同一ノード上のPod間のネットワーク通信を紹介した後、異なるノード上のPod間の通信プロセスの共通点と相違点を見てみよう。

異なるノードのポッドネットワーク通信

ここで、zlw-03という新しいレプリカをクラスタに追加し、既存のレプリカzlw-01とは別のノードにデプロイします。

$ kubectl get pods -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES zlw-01 1/1 Running 0 1h 10.233.133.2 10-23-14-110   zlw-02 1/1 実行中 0 1h 10.233.133.3 10-23-14-110   zlw-03 1/1 実行中 0 1h 10.233.80.0 10-23-14-111   <none

次に、コピーzlw-03のネットワークデバイスとルーティングルールを見る:

$ kubectlexec-it zlw-03 -- ip a 1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00:00 brd 00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: tunl0@NONE:  mtu 1480 qdisc noopstate DOWN group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 3: eth0@if328463073:  mtu 1500 qdisc noqueuestate UP group default qlen 1000 link/ether ce:fd:7e:63:4c:ab brd ff:ff:ff:ff:ff link-netnsid 0 inet 10.233.80.0/32 scope global eth0 valid_lft$ kubectlexec-it zlw-03 -- ip r default via 169.254.1.1 dev eth0 169.254.1.1 dev eth0 scope link $ kubectlexec-it zlw-03 -- route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 169.254.1.1 0.0.0.0 UG 0 0 0 eth0 169.254.1.10.0.0.0 255.255.255.255 UH 0 0 0 0 eth0

その後、ノード10-23-14-111のレプリカzlw-03のcali NICを表示します:

$ ip a | grep -A 3 328463073 328463073: cali20e9b05e2d6@if3:  mtu 1500 qdisc noqueue state UP group default qlen1000 link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::ecee:eeff:feee:eee/64 scope link valid_lft foreverpreferred_lft 永遠に

つまり、レプリカzlw-03のPodIPは10.233.80.0であり、eth0 NICのMACアドレスはce:fd:7e:63:4c:abであることがわかる。 vethペアの端にあるcali NICの名前はcali20e9b05e2d6であり、そのMACアドレスはee:ee:ee:ee:ee:ee:ee:eeである。

コンテナからホストへ

レプリカzlw-01からレプリカzlw-03へのネットワークリクエストを開始する:

$ kubectlexec-it zlw-01 -- ping -c 1 10.233.80.0 PING 10.233.80.0 (10.233.80.0) 56(84) バイトのデータ 10.233.80.0 から 64 バイト: icmp_seq=1 ttl=62time=0.382 ms --- 10.233.80.0 ping 統計 --- 1 パケット送信, 1 パケット受信, 0% パケットロス, time 0ms rtt min/avg/max/mdev = 0.382/0.382/0.382/0.382/ 0.382/0.000 ms

トラフィックはレプリカzlw-01のeth0 NICから送信され、反対側のcalife4cf73bf2a NICを通過し、最終的にノード10-23-14-110に到着する。このプロセスは、コンテナからホストへのトラフィックについて先に説明した方法と変わらない。

次に、ホスト間でトラフィックがどのように転送されるかに注目する。

ホストからホストへ

まずノード10-23-14-110のルーティングルールを確認する:

$ ip route 10.233.133.2 dev calife4cf73bf2a scope link src 10.23.14.110 10.233.133.3 dev cali957267df2c7 scope link src 10.23.14.110 10.233.80.0/24 via 10.23.14.111 dev eth0 proto bird

10.23.14.111経由で10.233.80.0/24 dev eth0 proto bird. このルールの意味は、宛先アドレスが10.233.80.0/24セグメント内にあるパケットに対して、デバイスはeth0インターフェースを通してネクストホップ10.23.14.111に送るというものである。このルートはCalicoのBGPクライアントのBIRDコンポーネントによって取得されます。

次に、ノード 10-23-14-110eth0 の NIC 情報を見てみましょう:

ip a show eth0 2: eth0:  mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:50:56:a9:e1:02 brd ff:ff:ff:ff inet 10.23.14.110/24 brd 10.23.14.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe8080:ff:ff:ff inet 10.23.14.110/24 brd 10.23.14.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::250:56ff:fea9:e102/64スコープ link valid_lft forever preferred_lft forever

ノード10-23-14-110のMACアドレスが00:50:56:a9:e1:02であることがわかります。

次に、ノード 10-23-14-110 は ARP プロトコルでネクストホップ 10.23.14.111 の MAC アドレスを解決します。ここで、10.23.14.111 はノード 10-23-14-111eth0 NIC の IP アドレスなので、ノード 10-23-14-111 で以下のコマンドを実行します:

ip a show eth0 2: eth0:  mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:50:56:a9:85:40 brd ff:ff:ff:ff inet 10.23.14.111/24 brd 10.23.14.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80:ff:ff:ff:ff inet 10.23.14.111/24 brd 10.23.14.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::250:56ff:fea9:8540/64スコープ link valid_lft forever preferred_lft forever

ノード10-23-14-111のMACアドレスが00:50:56:a9:85:40であることがわかります。

kubectl exec -it zlw-01 - ping -c 1 10.233.80.0コマンドを実行すると、ノード10-23-14-111の以下のデータをtcpdumpコマンドで監視できる:

tcpdump -i eth0 -ne | grep "10.233.80.0" tcpdump: verbose output suppressed, use -v or -vvforful protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 02:19:54.751970 00:50:56:a9:e1:02 > 00:50:56:a9:85:40, ethertype IPv4 (0x0800), length 98: 10.233.133.2 > 10.233.80.0" tcpdump.10.233.80.0: ICMPechorequest, id 23, seq 1, length 64 02:19:54.752045 00:50:56:a9:85:40 > 00:50:56:a9:e1:02, ethertype IPv4 (0x0800), length 98.10.233.80.0 > 10.233.133.2: ICMPechoreply, id 23, seq 1, length 64

レプリカzlw-01からzlw-03にアクセスするトラフィックは、ノード10-23-14-110から10-23-14-111を経由して送信されていることがわかる:

  • 送信元IPはzlw-01のPodIP 10.233.133.2;
  • ソースMACアドレスは、ノード10-23-14-110のeth0 NICに対応するMACアドレス00:50:56:a9:e1:02です;
  • ターゲットIPはzlw-03のPodIP 10.233.80.0;
  • ターゲットMACアドレスは、ノード10-23-14-111のeth0 NICに対応するMACアドレス00:50:56:a9:85:40です;

トラフィックがノード10-23-14-111に入ると、対応するcali NICからレプリカzlw-03に転送される。

ホストからコンテナへ

レプリカzlw-03のノード10-23-14-111のルーティングルールを見てみましょう:

ip r | grep 10.233.80.0 10.233.80.0 dev cali20e9b05e2d6 scope link src 10.23.14.111 blackhole 10.233.80.0/24 proto bird

ご覧のように、10.233.80.0 セグメント宛のパケットは、ノード上のレプリカ zlw-03 の cali NIC であるデバイス cali20e9b05e2d6 を経由して送信され、後続のトラフィックはこの cali NIC を経由して、最近コンテナに入ったレプリカ zlw-03 の eth0 NIC に到達します。このプロセスは、先に説明したホストからコンテナへのトラフィックと変わりません。

概要

前回までの紹介で、キャリコBGPの役割についてはすでにご理解いただけたと思います。 フルメッシュモード各ノードは、BGPプロトコルによってピアツーピア接続を確立してルーティング情報の交換を実現し、Linux vethペアによってコンテナとホストネットワーク間の通信を実現し、ホストルーティングによってノード間のパケット転送を実現する。

フルメッシュモードでは、各ノードは他のノードとBGPピアツーピア接続を確立しますが、BGP接続数はノード数に応じてn*(n-1)/2のスケールで増加し、この増加はノード数が多いほどクラスタネットワークを圧迫するため、ルーティングアップデートの効率が著しく低下します。

そのため、フルメッシュモードは通常、ノードサイズが比較的小さい中小規模のクラスタに適しており、ノードサイズが100ノード以下の場合に適用することが公式に推奨されている。大規模なクラスタに展開する必要がある場合は、Route Reflectorモードを選択するか、トップ・オブ・ラック(ToR)ルータとピアツーピア接続を確立してローカル展開シナリオで展開します。

リフレクター・モードでは、一部のノードがルート・リフレクターとして設定され、これらのルート・リフレクターはノード間でメッシュ状に構築される一方、他のノードはルート・リフレクターの一部(通常は冗長性のために2つ)とピアツーピア接続を確立するだけでよい。

このアプローチでは、フルメッシュモードに比べてノードあたりのBGPピアリング接続数が大幅に減るため、リフレクターモードはフルメッシュモードよりも大規模なクラスタに適していますが、設定が比較的複雑になるというデメリットもあります。

今回はキャリコのBGPモードについて紹介しましたが,引き続きIPIPモードとVXLANモードでのキャリコのネットワーク通信処理,クラスタに適したネットワークモードの選択方法について紹介したいと思います.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です