この記事を読むには、読者がイーサネットの基本原理と Linux システムの基本的なネットワーク コマンド、および TCP/IP プロトコル ファミリに精通していること、および従来のネットワーク モデルとプロトコル パケットのフロー原理を理解していることが求められます。この記事が Linux カーネルの特定の実装に関係する場合、カーネル バージョン v4.19.215 が優先されます。 カーネルネットワークパケット受信プロセス1 ネットワークカードからカーネルプロトコルスタックまで図[1]に示すように、ネットワークパケットがNC(ネットワークコンピュータ、この記事では物理マシンを指します)に到達すると、NIC(ネットワークインターフェイスコントローラ、一般的にはネットワークカードと呼ばれる)デバイスによって処理され、NICは割り込みの形でカーネルにメッセージを渡します。 Linux カーネルの割り込み処理は、上位半分 (Top Half) と下位半分 (Bottom Half) に分かれています。上半分はハードウェア関連の作業をできるだけ早く処理して戻る必要があり、下半分は上半分によって起動されて、その後の時間のかかる作業を処理します。 NIC の具体的な処理フローは以下のとおりです。NIC はデータを受信すると、DMA モードでリング バッファー (受信キュー) 内の記述子が指すマップされたメモリ領域にデータをコピーします。コピーが完了すると、CPU に処理を通知する割り込みがトリガーされます。ここで、ethtool -g {デバイス名、eth0 など} コマンドを使用して、RX/TX (受信/送信) キューのサイズを表示できます。 CPU は割り込みを認識すると、NIC の割り込み処理関数にジャンプして実行を開始します。この時点で、NIC の動作モードを区別する必要があります。以前の非NAPI(新API)[2]モードでは、割り込みの上位半分は関連するレジスタ情報を更新し、受信キューをチェックして受信データを指すsk_buff構造体を割り当て、最後にnetif_rx()を呼び出してsk_buffをカーネルに渡して処理します。 netif_rx() 関数のプロセスでは、割り当てられた sk_buff 構造体が input_pkt_queue キューに配置された後、仮想デバイスが poll_list ポーリング キューに追加され、ソフト割り込み NET_RX_SOFTIRQ がトリガーされて割り込みの下位半分がアクティブになります。この時点で、割り込みの前半は終了します。詳細な処理フローは、net/core/dev.c の netif_rx() -> netif_rx_internal() -> enqueue_to_backlog() プロセスを参照してください。下半分の NET_RX_SOFTIRQ ソフト割り込みに対応する処理関数は net_rx_action() であり、デバイスによって登録された poll() 関数を呼び出して処理します。 NAPI 以外の場合、この仮想デバイスの poll() 関数は process_backlog() 関数を指すように固定されます。この関数は、sk_buff を input_pkt_queue から process_queue に移動し、__netif_receive_skb() 関数を呼び出してそれをプロトコル スタックに渡し、最後にプロトコル スタック関連コードがプロトコル タイプに応じて後続の処理のために対応するインターフェイスを呼び出します。特に、ここでの enqueue_to_backlog() 関数と process_backlog() 関数は、RPS メカニズムの有効化に関連するロジックにも使用されます。 非 NAPI (New API) モードでは、ネットワーク パケットの到着ごとに割り込み処理プロセスがトリガーされるため、全体的な処理能力が低下し、時代遅れになります。現在、ほとんどの NIC は NAPI モードをサポートしています。 NAPI モードでは、最初のパケットが NIC 割り込みをトリガーした後、効率を向上させるために、デバイスがポーリング操作のポーリング キューに追加されます。ポーリング プロセス中に新しい割り込みは生成されません。 NAPI をサポートするために、各 CPU は softnet_data と呼ばれる構造体を保持します。この構造体には、すべてのポーリング デバイスを配置するための poll_list フィールドがあります。このとき、割り込みの上半分は非常に単純です。 NIC 関連のレジスタ情報を更新し、デバイスを poll_list ポーリング キューに追加し、ソフト割り込み NET_RX_SOFTIRQ をトリガーするだけです。割り込みの下位半分は引き続き net_rx_action() によって処理され、デバイス ドライバーによって提供される poll() 関数が呼び出されます。ただし、poll() は、非 NAPI モードのカーネル関数 process_backlog() ではなく、デバイス ドライバーによって提供されるポーリング処理関数を指すようになりました。このデバイス ドライバーによって提供される poll() 関数は、最終的に __netif_receive_skb() 関数を呼び出して、sk_buff をプロトコル スタックに送信し、処理させます。 非 NAPI モードと NAPI モードでのプロセスの比較は次のとおりです (灰色の背景はデバイス ドライバーによって実装され、その他はカーネル自体によって実装されます)。 NAPIモードネットワークデバイスドライバの実装とNAPIモード処理フローの詳細については、[3]の記事とその翻訳が参考になります(強く推奨)。この記事では、Intel Ethernet Controller I350 NICデバイスのパケット受信と処理の詳細について詳しく説明します(姉妹記事はパケット送信プロセスと変換です[4])。さらに、パケット受信には、複数のネットワーク カードのボンディング モード (モードは /proc/net/bonding/bond0 で確認できます)、ネットワーク マルチキュー (イーサネット コントローラーの機能情報を表示するには、sudo lspci -vvv を使用します。MSI-X: Enable+ Count=10 がある場合は、NIC がそれをサポートしていることを示します。割り込みバインディングの状態は /proc/interrupts で確認できます) などのメカニズムも関係します。これらについてはこの記事では詳しく説明しません。ご興味のある方は関連資料[5]をご参照ください。 2 カーネルプロトコルスタックネットワークパケット処理フロー前述のように、ネットワーク パケットを受信するときに NIC によって構築される sk_buff 構造体は、最終的に __netif_receive_skb() によって解析するためにカーネル プロトコル スタックに送信されます。この関数は最初にRPS[5]関連の処理を実行し、データパケットはキュー内を循環し続けます(通常、RSSが有効になっているネットワークカードではRPSを有効にする必要はありません)。パケットを他の CPU に分散して処理する必要がある場合は、enqueue_to_backlog() を使用してパケットを他の CPU のキューに配信し、process_backlog() で IPI (プロセッサ間割り込み、IRQ 経由ではなく APIC バスで送信) をトリガーして他の CPU に通知を送信します (net_rps_send_ipi() 関数)。 最後に、パケットは次の処理段階のために __netif_receive_skb_core() に送信されます。この処理機能の主な機能は次のとおりです。
この時点では、パケットはまだデータリンク層の処理フローにあります。ここでは、OSI 7 層モデルと TCP/IP 5 層モデルについて説明します。 ネットワーク階層モデルでは、後者の層はペイロードと呼ばれる前の層のデータ部分です。完全なTCP/IPアプリケーション層データパケットの形式は次のとおりです[6]。 __netif_receive_skb_core() の処理ロジックで注意する必要があるのは、ブリッジとそれに続く IP 層および TCP/UDP 層の処理です。まず IP 層を見てみましょう。__netif_receive_skb_core() は deliver_skb() を呼び出し、deliver_skb() は特定のプロトコルの .func() インターフェイスを呼び出します。 IP プロトコルの場合、これは ip_rcv() 関数を指します。この関数は、いくつかの統計とチェックを行った後、パケットをNetfilter [7]フレームワークに転送し、後続の処理のためにip_rcv_finish()関数を指定します(パケットがNetfilterによって破棄されない場合)。ルーティング サブシステムがパケットをチェックして処理した後、パケットがローカル マシンに属している場合は、ip_local_deliver() が呼び出され、データ パケットが上位層プロトコルに転送されます。この関数は前のロジックに似ています。これは引き続き Netfilter フレームワークに提示され、後続の処理のために関数 ip_local_deliver_finish() を指定します。この関数は最終的に、処理する対応する上位層プロトコル インターフェイスをチェックして選択します。 TCP や UDP などの一般的な上位層プロトコルのプロセスは、この記事の範囲外です。 TCP プロセスに必要な長さだけでも、この記事の全内容を超えるほどです。ここでは、TCP プロトコル (v4) エントリ関数 tcp_v4_rcv() と UDP プロトコル エントリ関数 udp_rcv() を、独自の調査のためのガイドとして提供します。さらに理解を深めるために他の資料を読むこともできます[9]。 3 Netfilter/iptables と NAT (ネットワーク アドレス変換)後述するネットワーク ポリシーと多くのサービス公開実装では Netfilter によって提供されるメカニズムを使用する必要があるため、Netfilter フレームワークを少し強調する必要があります。 Netfilter は、カーネルのパケット フィルタリング フレームワークの実装です。簡単に言えば、多くのフック ポイントがプロトコル スタックの各レベルのパケット処理関数に組み込まれており、これらのポイントでのコールバック関数の登録をサポートします。 画像はウィキメディアから引用したものです。参照[8]をクリックすると、より大きな画像(SVGベクター画像、ウェブページ上の表示パーセンテージを増やして拡大表示を続けることができます)が表示されます。 Linux で最も一般的に使用されているファイアウォールである iptables は、Netfilter に基づいて実装されています (nftables は新しい世代のファイアウォールです)。 Iptables は、テーブルとチェーンの概念に基づいてルールを整理します。ここでの「ファイアウォール」という言葉に惑わされないように注意してください。 iptables は、パケットをフィルタリングする以上の機能を備えています (フィルタ テーブル)。また、ネットワーク アドレス変換 (NAT テーブル) とパケット フィールドの変更 (Mangle テーブル) もサポートします。ネットワーク仮想化において、最もよく使用される機能は NAT アドレス変換です。このタイプの機能は通常、ゲートウェイ ネットワーク デバイスまたは負荷分散デバイスでよく使用されます。 NC が内部でネットワーク関連の仮想化を実行する必要がある場合、ゲートウェイおよび負荷分散デバイスとしても機能します。 iptables の NAT ルールを設定する前に、カーネルのパケット転送機能 echo "1" > /proc/sys/net/ipv4/ip_forward も有効にする必要があります。また、echo "1" /proc/sys/net/bridge/bridge-nf-call-iptables スイッチをオンにすることも推奨されます (modprobe br_netfilter が必要になる場合があります)。 bridge-nf-call-iptables 上記のソースコード分析から、ブリッジの転送処理は Netfilter ルールの前にあることがわかります。したがって、デフォルトでは、レイヤー 2 ブリッジの転送はレイヤー 3 iptables によって制限されません。ただし、多くの仮想化ネットワーク実装では Netfilter ルールを有効にする必要があるため、カーネルはブリッジの転送ロジックが Netfilter ルールを呼び出すことを許可することもサポートしています。この機能はデフォルトでは有効になっていないため、スイッチを確認する必要があります。具体的なiptablesコマンドについては、この記事とその翻訳[10]を参照してください。この記事ではそれらについてこれ以上説明しません。 ここで強調しておきたいのは、Netfilter のロジックはカーネルのソフト割り込みコンテキストで実行されるということです。 Netfilter が多数のルールを追加すると、必然的に一定量の CPU オーバーヘッドが発生します。以下で仮想化ネットワークのパフォーマンス低下について説明する際、オーバーヘッドの大部分はここから発生します。 2つの仮想ネットワークデバイス従来のネットワーク認識では、ネットワークは、ハードウェアメディア、スイッチ、ルーターを使用した1つ以上のNICを備えたNCのグループで構成される通信セットです([11]の図、以下同じ)。 SDN (Software Defined Network) の実装としてのネットワーク仮想化は、vNIC (仮想ネットワーク カード)、vSwitch (仮想スイッチ)、vRouter (仮想ルーター) などのデバイスを仮想化し、対応するデータ パケット フロー ルールを構成することにすぎません。外部インターフェイスは、イーサネットや TCP/IP プロトコル スイートなど、それが配置されている物理ネットワークのプロトコル仕様にも準拠している必要があります。 Linux ネットワーク仮想化技術の進化に伴い、仮想マシンや仮想コンテナ ネットワークで広く使用される仮想化ネットワーク デバイスがいくつか登場しています。代表的なものとしては、Tap/Tun/Veth、Bridge などがあります。
仮想マシンとコンテナ ネットワーク間の転送プロセスにはいくつかの違いがあります。前者 (KVM など) では通常、Tap デバイスを使用して仮想マシンの vNIC とホストのブリッジを接続します。コンテナのブリッジ ネットワーク モードは、異なる名前空間内の Veth ペアをブリッジに接続して通信を実現します (他の方法については後述します)。 Linux Bridge は、ブリッジングまたは NAT モードを組み合わせることで、同一ホスト上またはホスト間での仮想マシン/コンテナ間の通信を簡単に実現できます。さらに、ブリッジ自体も VLAN 構成をサポートしており、レイヤー 3 スイッチの一部の機能を実現できます。しかし、多くのベンダーは、人気の高いCisco Nexus 1000V、VMware Virtual Switch、広く使用されているオープンソースのOpen vSwitch[12]など、より豊富な機能を備えた仮想スイッチを開発しています。 vSwitch を使用すると、より多くのカプセル化プロトコルをサポートする、より高度な仮想ネットワークを構築できます。 1 Linux ブリッジ + Veth ペア転送VRF (仮想ルーティングおよび転送) は、ネットワーク分野で非常に一般的な用語です。 1990 年代以降、多くのレイヤー 2 スイッチは 4K VLAN ブロードキャスト ドメインを作成できるようになりました。 4K である理由は、VLAN タグの形式が 802.1q 標準に準拠しており、VLAN ID が 12 ビットとして定義されているためです (802.1q の 802.1q は 4094*4094 で、0 と 4095 は予約されています)。 VRF の概念がレイヤー 3 に導入されたため、単一の物理デバイスに複数の仮想ルーティング/転送インスタンスを持たせることもできます。 Linux の VRF は 3 層のネットワーク プロトコル スタックの仮想化を実装し、ネットワーク ネームスペース (以下、netns と呼びます) はネットワーク スタック全体を仮想化します。 netns ネットワーク スタックには、ネットワーク インターフェイス、ループバック デバイス、ルーティング テーブル、iptables ルールが含まれます。この記事ではデモンストレーションにnetnsを使用します(結局のところ、コンテナについて説明しています)。以下ではip[14]コマンドを使用してnetnsとVeth Pairデバイスを作成および管理します。 ネットワーク名前空間の作成、表示、削除
実行結果は図のようになります(実行前に削除します)。 興味がある場合は、strace コマンドを使用して作成プロセスを追跡し、ip コマンドがどのように作成されるかを確認できます (strace ip netns add qianyi-test-1)。 netnsでコマンドを実行する
実行結果は次のとおりです。 新しく作成された netns は完全に空で、DOWN 状態の lo ネットワーク カードが 1 つだけあります。オンにしてみましょう:
ステータスは UNKOWN に変わりますが、これは正常です。このステータスはドライバーによって提供されますが、lo ドライバーはこれを実行しません。 Vethペアデバイスの作成
ip addr コマンドを使用して以下を表示します。 8-9、10-11 は、上記で作成した 2 組の Veth Pair デバイスです。現時点では、IP アドレスは割り当てられておらず、DOWN 状態になっています。 Veth Pairデバイスをnetnsに追加
この時点で、両方の netns で ip addr コマンドを実行すると、デバイスがすでに存在し、ルーティング テーブル (route または ip route コマンド) もデフォルトで作成されていることがわかります。 ここでは、デバイスの操作と表示の両方を ip netns exec {...} メソッドを使用して実行する必要があります。コマンドが多数ある場合は、実行コマンドを bash に置き換えることもできるので、このシェルで netns を便利に操作できます。 これで、qianyi-test-1 および qianyi-test-2 netns は veth ペア veth-1-a/veth-1-b を介して接続され、2 つの netns は 2 つの IP アドレスを介して相互にアクセスできるようになります。 ping 中に 101 でパケットをキャプチャした結果は次のとおりです。 eth-1-a (10.0.0.101) が最初に ARP (アドレス解決プロトコル) を介して 10.0.0.102 の MAC アドレスを照会していることが明確にわかります。応答を取得した後、ping でも使用されるプロトコルである ICMP (インターネット制御メッセージ プロトコル) 要求と応答を使用します。 ARP 解決のキャッシュ情報は、arp コマンドを使用して表示することもできます。 このときのネットワーク接続モードは次のとおりです。 この接続モードは、実際に NIC を備えた 2 つのデバイスをネットワーク ケーブルで接続し、同じネットワーク セグメント内で IP を構成して相互に通信できるようにすることに非常に似ています。複数のデバイスを相互接続する必要がある場合はどうなりますか?実際にはスイッチなどのネットワーク機器が必要になります。前の記事で触れた Linux の組み込みブリッジを覚えていますか?次に、ブリッジ メカニズムを使用してネットワークを確立します。 次のテストを実行する前に、qianyi-test-1 および qianyi-test-2 から Veth ペア veth-1-a/veth-1-b をホストの netns に戻して、初期環境を復元する必要があります。
Linuxブリッジを作成し、ネットワークを構成する
実行後、作成されたブリッジと設定された IP を表示できます。実際、brctl show コマンドで表示される結果は理解しやすいです。 veth-1-b と veth-2-b がブリッジ インターフェイスに接続されていることがはっきりとわかります。 Veth ペアの一方の端がブリッジに接続されると、「ネットワーク カード」から「クリスタル ヘッド」に退化します。 現在のモードでのパケット キャプチャの結果は変わりませんが、ネットワーク接続モードは異なります。 このモデルによれば、ネットワーク名前空間と Veth ペアがさらに存在する場合、同様の方法で追加することで水平方向に拡張できます。 ただし、ホストのネットワークにアクセスできるネットワーク ルールがないため、qianyi-test-1 からホストに ping を試行しても当然失敗します。 上記のスクリーンショットには、docker0 ブリッジがあります。マシンに Docker がインストールされると、このブリッジは Docker が使用できるように自動的に設定されます。 docker0 という名前のこのブリッジには、実際に IP アドレスがあることに気付いたかもしれません。実際のブリッジには当然 IP はありませんが、仮想デバイス Linux Bridge を設定できます。ブリッジに IP アドレスを設定したら、内部ネットワークのゲートウェイとして設定できます。ルーティング ルールと組み合わせることで、仮想ネットワーク内で最も単純なマシン間通信を実現できます (実際の 3 層スイッチと同様)。 次に、br0 ブリッジのアドレスを作成し、それを veth-1-a および veth-2-a のデフォルト ゲートウェイ アドレスとして設定します。
この時点で、ホスト アドレスに正常にアクセスできます (ホスト上のルーティング テーブルは、ip link set br0 up ステップで自動的に作成されます)。 ネットワーク モデルはさらに次のようになります。 この時点で、別のホスト上の別のネットワーク セグメントに別のブリッジと複数のネットワークがある場合、それらはどのように相互に通信できるでしょうか?両方のホストで宛先ホストへのルーティング ルールを構成するだけです。他のホストの IP アドレスが 10.97.212.160 で、サブネットが 10.0.1.0/24 であると仮定すると、現在のマシンに 10.97.212.160 経由の 10.0.1.0/24 のルールを追加し、10.97.212.160 に 10.97.212.159 経由の 10.0.0.0/24 のルールを追加する必要があります (または iptables で SNAT/DNAT ルールを構成します)。 N 個のステーションがある場合はどうなるでしょうか?そうすると、N * N のルールが存在し、非常に複雑になります。これはシンプルなアンダーレイ モード コンテナー通信ソリューションです。欠点も明らかです。ホスト マシンの基盤となるネットワークを変更する権限が必要であり、基盤となるネットワークから切り離すことは困難です。では、物理ネットワーク上のすべてのホストマシンに仮想ブリッジを構築し、関連するネットワーク内のすべてのデバイスを接続できれば、それらを分離することはできないでしょうか?これはオーバーレイ ネットワーク ソリューションであり、以下で説明します。このセクションの他の仮想ネットワーク デバイス (Open vSwitch など) のインストールと構成も同様であるため、ここでは説明しません。ご興味があれば、ドキュメントを確認してご自身でテストしてみてください。 2 オーバーレイネットワークソリューション: VXLANVLANの拡張プロトコルであるVXLAN(Virtual eXtensible Local Area Network、RFC7348)[16]は、IETFが定義するNVO3(Network Virtualization over Layer 3)標準技術の1つである(他の代表的な技術としてはNVGREやSTTなどがある)。ただし、VXLAN と VLAN が解決しようとする問題は異なります。 VXLAN は本質的には、データ リンク層 (L2) のイーサネット フレームをトランスポート層 (L4) の UDP データグラムにカプセル化し、ネットワーク層 (L3) で送信するトンネル カプセル化テクノロジです。その効果は、データリンク層 (L2) のイーサネット フレームがブロードキャスト ドメインで送信されるのとまったく同じです。つまり、3 層ネットワークを横断しますが、3 層の存在は認識されません。 UDP カプセル化をベースとしているため、IP ネットワーク ルートが到達可能であれば、巨大な仮想レイヤー 2 ネットワークを構築できます。また、高レベルプロトコルに基づいて再カプセル化されるため、従来のネットワークに比べてパフォーマンスが約 20% ~ 30% 低下します (パフォーマンスデータは技術の発展に応じて変化し、現在のレベルのみを表します)。 ここでは、VXLAN の 2 つの重要な概念について簡単に説明します。
VXLANメッセージのフォーマットを図[17]に示す。 Linux カーネル v3.7.0 では、VXLAN ネットワークのサポートが開始されます。ただし、安定性やその他の機能のために、カーネル v3.10.0 以降のバージョンを選択してください。次に、2 台のマシン 10.97.212.159 と 11.238.151.74 を使用してテスト VXLAN ネットワークを作成します。
この長いコマンド文字列は前の手順とまったく同じで、以下に示すようにネットワーク環境を構築します。 この環境では、10.0.0.101 と 10.0.0.102 は接続されており、10.0.0.103 と 10.0.0.104 も接続されていますが、当然ながら 10.0.0.101/10.0.0.102 と 10.0.0.103/10.0.0.104 は通信できません。 次に、次の 4 つの netns 環境を接続するように VXLAN 環境を構成します。
brctl show br0 コマンドを使用して、両方の VXLAN デバイスが接続されていることを確認します。 次に、10.0.0.101 から 10.0.0.103 に ping を送信します。 10.0.0.101 でキャプチャされたパケットからは、レイヤー 2 通信のように見えます。 ARP キャッシュを直接チェックすることは、レイヤー 2 相互通信とまったく同じです。 arp -d 10.0.0.103 を使用してキャッシュ項目を削除し、ホスト上でパケットを再キャプチャしてファイルを保存し、WireShark で開きます (上記の設定は VXLAN のデフォルト ポート 4789 ではないため、キャプチャした UDP を VXLAN プロトコルに解析するように WireShark を設定する必要もあります)。 期待通りの結果が得られました。この時点でのネットワーク アーキテクチャを図に示します。 そこで疑問なのは、ここで UDP プロトコルを使用して信頼性の高い通信を実現できるかどうかです。もちろんできます。信頼性はこの層で考慮されるものではなく、内部層にラップされたプロトコルによって考慮される必要があるものです。完全な通信原理は実際には複雑ではありません。 2 台のマシンにはそれぞれ VTEP (VXLAN トンネル エンドポイント) デバイスがあり、ポート 9527 で送信される UDP データ パケットをリッスンします。データ パケットは受信後、分解され、ブリッジを介して指定されたデバイスに渡されます。仮想デバイス VETP は、10.0.0.3 のようなアドレスをどのマシンの VETP デバイスに送信するかをどのように知るのでしょうか?これは仮想レイヤー 2 ネットワークであり、基盤となるネットワークはこのアドレスを認識しません。実際、Linux ブリッジでは FDB (転送データベース エントリ) と呼ばれるレイヤー 2 転送テーブルが維持されており、リモート仮想マシン/コンテナの MAC アドレス、リモート VTEP の IP アドレス、および VNI 間のマッピング関係を保存するために使用されます。 FDB テーブルは、bridge fdb コマンドを通じて操作できます。
上記の簡単な実験には 2 台のマシンが関係します。各マシンは、コマンドを使用して他のマシンのVTEPアドレスを直接指定します。 FDBテーブルが情報を見つけることができない場合、他のマシンに送信されます。これは、最も単純な相互接続モードです。大規模なVXLANネットワークでは、ネットワーク内の他のVETPアドレスを発見する方法を検討する必要があります。通常、この問題を解決するには2つの方法があります。1つは、マルチキャスト/マルチキャスト(IGMP、インターネットグループ管理プロトコル)を使用して、ノードを仮想全体に形成することです。パケットが送信される人に明確でない場合、グループ全体にブロードキャストされます(上記の実験でVETHデバイスを作成するコマンドは、224.1.1.1などのマルチキャスト/マルチキャストアドレスに変更され、リモートキーワードもグループに変更する必要があります。 2つ目は、外部分散コントロールセンターを介してFDB情報を収集し、同じVXLANネットワーク内のすべてのノードに配布することです。マルチキャスト/マルチキャストは、大規模な条件下での基礎となるネットワークおよびパフォーマンスの問題のサポートによって制限されます。たとえば、多くのクラウドネットワークはこれを許可しない場合があります。したがって、以下のK8Sネットワークソリューションについて議論して研究すると、多くのネットワークプラグインが後者と同様の方法で実装されていることがわかります。 これでこのセクションが終了します。もちろん、複数のオーバーレイネットワークソリューション、VXLANがありますが、現在、多くの主流のソリューションがこの方法を使用しています。他のオーバーレイモードはまばゆいばかりのように見えるかもしれませんが、それを率直に言うと、L4よりもL2、L3よりもL2、L3よりもL3などのさまざまなパッケージング方法にすぎません。基本原則を理解したら、大したことではありません。多くのネットワーク仮想化デバイスとメカニズム[18]があり、それらを詳細に説明するには1日以上かかります。ただし、基本的なネットワークの原則が習得されると、さまざまなプロトコルパケットのフローにすぎません。 3。K8Sネットワーク仮想化の実装1 K8Sネットワークモデル各PODには独自のIPアドレスがあります。つまり、各POD間にリンクを明示的に作成する必要はなく、ポートをホストするためにマッピングコンテナポートを扱う必要はほとんどありません。これにより、ポート割り当て、命名、サービスの発見、負荷分散、アプリケーション構成、および移行の観点から、ポッドがVMまたは物理ホストのように扱われることができるクリーンで後方互換性のあるモデルが作成されます。 すべてのネットワーク機能のKubernetes実装は、次の基本要件を満たす必要があります(特定のネットワークセグメンテーションポリシーが設定されていない限り): ノード上のポッドは、NATを通過せずに他のノードのポッドと通信できます ノード上のエージェント(システムデーモン、クベレットなど)は、ノード上のすべてのポッドと通信できます 注:ホストネットワークで実行されているポッドをサポートするプラットフォームのみ(例:Linux): ノードのホストネットワークで実行されているポッドは、NATを通過せずにすべてのノードのポッドと通信できます。 このモデルは単純なだけでなく、仮想マシンからコンテナへの安価な移行を可能にするKubernetesの当初の意図と互換性があります。あなたの作業が仮想マシンで実行され始めた場合、あなたの仮想マシンは他の仮想マシンと通信できるようにIPを持っていたので、これは基本的に同じモデルです。 KubernetesのIPアドレスは、ポッドの範囲内に存在します - コンテナは、IPアドレスやMacアドレスを含むネットワーク名空間を共有します。これは、ポッド内のすべてのコンテナがLocalHostを介してさまざまなポートに到達できることを意味します。これはまた、ポッド内のコンテナがポートの使用を互いに調整する必要があることを意味しますが、これは仮想マシンのプロセスと違いはないようです。これは、「1つのポッド、1つのIP」モデルとも呼ばれます。 これらの段落は、K8Sの公式文書から引用されています[19]。簡単に言えば、各ポッドには独立したIPアドレスがあり、すべてのポッドはNATを通過せずに互いに通信できます。このモデルは、ポッドのネットワーク環境をVMのネットワーク環境とほぼ同一視しています。 K8Sの主流ネットワークプラグインの2つの実装原則K8Sのネットワークは、プラグインを介して実装されます。ネットワークプラグインには2つのタイプがあります。
画像は[20]からです。この記事では、CNIインターフェイスプラグインのみに焦点を当てています。主流のK8Sネットワークプラグインは次のとおりです[21]。この記事では、分析のために1,000を超えるGitHub星を持ついくつかのプロジェクトを選択します。
フランネル CNIはCoreosによって提案されている仕様ですので、まずCoreos独自のフランネルプロジェクトの設計を見てみましょう。 Flannelは、各ホストマシンにFlanneldという名前のプロキシプロセスを展開し、ネットワークセグメント関連データはKubernetes API/etcdを使用して保存されます。フランネルプロジェクト自体はフレームワークであり、コンテナネットワーク機能を実際に提供するのは、フランネルのバックエンド実装です。 現在のフランネルには、Alibaba Cloudおよびその他の主要メーカー(クラウドメーカーがすべて実験的にサポートされている)がサポートするVXLAN、HOST-GW、UDP、およびバックエンドの次のバックエンドの実装があり、IPIPやIPSECなどのトンネル通信の実験的サポートがあります。公式文書によると、VXLANモードの使用が推奨されます。 Host-GWは、パフォーマンスをさらに向上させたい経験豊富なユーザーに推奨されます(通常、クラウド環境は利用できません。理由については後で説明します)。 UDPは、フランネルによるパフォーマンスが低い最も初期のサポートされたソリューションであり、基本的に非推奨です。 以下は、個別に分析された3つのモードです。 1)VXLAN 上記のように、Linuxカーネルvxlanを使用したパケットのカプセル化の方法と原則Flannelは、Flannel.1と呼ばれるVETHデバイスを作成します。フラネルプロセスが存在するため、新しいVethデバイスの関係を登録および更新するタスクは、このプロセスに依存します。したがって、言うことは何もないようです。つまり、新しいK8SノードはそれぞれFlamenNeld DeamonsetモードのDeamonモードを作成します。その後、新しいVethデバイスを登録および更新することが非常に自然になり、グローバルデータは自然にettdに保存されます。この方法は描画されていますが、デバイス名が異なるというだけです(VethはFlannel.1と呼ばれ、ブリッジはCNI0と呼ばれます)。 2)ホスト-GW 名前が示すように、ホスト-GWは、ホストホストをプロトコルパケットの流れを処理するためのゲートウェイゲートウェイとして扱うことです。この方法は実際に上記で実証されています。ノードの変更とルーティングテーブルの追加と削除については、Flanneldによっても行われます。このソリューションの利点と短所は明らかです。最大の利点は自然にパフォーマンスであり、これは実際の直接転送です(全体的なパフォーマンスはホストレベルでの通信よりも10%低く、VXLANは20%、または30%から始まります)。短所も明らかです。この方法では、ホストが互いのレイヤーに接続され、インフラストラクチャの制御も必要です(ルーティングテーブルの編集)。これは一般に、クラウドサービス環境で達成することが困難です。さらに、ルーティングテーブルのスケールも大きくなるにつれて増加します。この方法は原則として比較的単純で、写真を描くことはありません。 3)UDP 各ホストのFlanneldプロセスは、デフォルトでFlannel0という名前のTUNデバイスを作成します。 TUNデバイスの機能は、カーネルとユーザーアプリケーションの間にIPパケットを渡すのが非常に簡単です。カーネルがIPパケットをTunデバイスに送信した後、パケットはデバイスを作成したアプリケーションに引き渡されます。プロセスがIPパケットをTunデバイスに送信すると、IPパケットがホストのネットワークスタックに表示され、次のホップがルーティングテーブルに従って処理されます。フランネルで管理されているコンテナネットワークでは、ホストのすべてのコンテナがホストに割り当てられる「サブネット」に属します。このサブネットのスコープ情報とサブネットがすべてETTDに保存されているホストIPアドレス。 Flanneldプロセスは、ホストのUDP 8285ポートを監視し、IPパケットをUDPプロトコルを介して宛先ホストにラップして通信を完了します。このモードのパフォーマンスが低いことを前に述べました。違いは何ですか?このソリューションは、アプリケーションレイヤーシミュレーションに実装されたオーバーレイネットワークです(ユーザーモードで実装されたVETHデバイスなど)。パケットには、カーネル(フランネルプロセスパケット/アンパックプロセス)でネイティブにサポートされるVXLANプロトコルよりも、ユーザーモードのエントリと終了が1つあり、パフォーマンスの損失が大きくなります。 カリコ Calicoは非常に興味深いプロジェクトです。基本的なアイデアは、ホストをルーターとして扱い、トンネルやNATを使用して転送し、すべてのレイヤー2と3番目のトラフィックをレイヤー3トラフィックに変換し、ホストのルーティング構成を介してパケットの転送を完了することです。 CalicoとFlannelのHost-GWモードの違いは何ですか?まず第一に、Calicoはブリッジを使用しませんが、ルーティングルールを使用して異なるVNIC間でデータを転送します。さらに、ルーティングテーブルは、ETCDストレージや通知の更新に依存せず、BGP(Border Gateway Protocol)を直接使用して、実際の環境などのルーティングテーブルデータを交換します。 BGPは非常に複雑であり、このプロトコルを詳細に詳しく説明することは少し難しいです(そして、私はそれをよく理解していません)。この記事では、このプロトコルでは、ルーティングデバイスがお互いのルーティング情報を送信および学習して自分自身を豊かにすることを許可することを知る必要があります。興味がある場合は、他の資料をご覧ください。 Calicoに戻ると、Felixと呼ばれるデーモンとホストにBirdと呼ばれるBGPクライアントがまだあります。 上記のように、FlannelのHost-GWモードでは、ホスト層2が相互接続されている必要があります(サブネット上)、この要件はまだCalicoで利用可能です。ただし、Calicoは、同じサブネットにない環境にIPIPモードのサポートを提供します。このモードをオンにした後、IPトンネル(IPトンネル)で通信するためにホストにTUNデバイスが作成されます。もちろん、このモードを使用した後、パッケージはL3よりもL3のオーバーレイネットワークモードであり、パフォーマンスはVXLANモードのパフォーマンスにも匹敵します。 完全なルーティングテーブルの通信方法の追加コンポーネントはありません。 IPルーティング転送ルールを構成した後、カーネルルーティングモジュールのフローに完全に依存します。 IPIPのアーキテクチャ図は似ており、もう描かれません。 繊毛
この紹介から、Ciliumから放出されるユニークなオーラを見ることができます。このプロジェクトの現在のGithub Star番号は10,000をほぼ超えており、最初の2つを直接上回ります。 Ciliumが展開された後、Cilium-Agentという名前のデーモンプロセスがホストに作成されます。このプロセスの機能は、EBPFスクリプトを維持および展開して、すべてのトラフィック転送、フィルタリング、および診断を実装することです(NetFilterメカニズム、Kenel> V4.19バージョンへの依存性はありません)。概略図の観点から描かれたアーキテクチャ図は非常にシンプルです(添付の写真はGitHubホームページから来ています): 基本的なネットワークの接続、分離、およびサービスの透明性をサポートすることに加えて、CiliumはEBPFに依存して、ホストネットワークの観測性とトラブルシューティング機能を向上させます。このトピックも非常に大きいため、この記事は閉鎖されます。ここでは、2つのよく書かれた記事[22] [23]の彼の翻訳について詳しく知ることができます。 3 K8Sコンテナアクセス分離上記の記事では、ネットワークプラグインのメカニズムと実装の原則を紹介し、最後にレイヤー2/レイヤー3層接続された仮想ネットワークを構築できます。デフォルトでは、ポッド間のネットワークアクセスは無制限ですが、一部のアクセスルール(ファイアウォール)は、多くの場合、内部ネットワークで設定する必要があります。 この要件に対処するために、K8Sはこの機能をサポートするためにNetworkPolicyと呼ばれるメカニズムを抽象化します。ネットワークポリシーは、ネットワークプラグインを介して実装されます。ネットワークポリシーを使用するには、NetworkPolicyをサポートするネットワークソリューションを使用する必要があります。なぜそう言うのですか?すべてのネットワークプラグインがフランネルなどのネットワークポリシーメカニズムをサポートしているわけではないため、そうではありません。 NetworkPolicyの根本的な原則に関しては、IPTableを使用してNetFilterルールを構成してパッケージのフィルタリングを実現することです。 NetworkPolicyの構成方法とiPtables/NetFilterの原則の詳細は、この記事の範囲内ではありません。情報については、他の資料を参照してください[24] [25]。 4 K8Sコンテナサービスは透明ですK8Sクラスター内では、すべてのコンテナ/プロセスがネットワークプラグインの助けを借りて互いに通信できます。ただし、サービスのユーザーが同じK8Sクラスターにないことが多いため、サービスプロバイダーになるだけでは十分ではありません。次に、このクラスター内のサービスを外の世界に公開するためにメカニズムが必要です。 K8Sは、サービスオブジェクトを使用して、この機能の抽象化を完了します。サービスは、K8Sで非常に重要なオブジェクトです。 K8S内でアクセスしたとしても、多くの場合、サービスラッピングが必要です(最初に、PODアドレスは常に固定されているわけではなく、次に、常に負荷分散要件があります)。 1つの文でサービスを要約する原則は、service = kube-proxy + iptablesルールです。サービスが作成されると、K8SはクラスターIPアドレスを割り当てます。このアドレスは実際にはVIPであり、実際のネットワークオブジェクトはありません。このIPは、iPtablesルールにのみ存在します。このVIPへのアクセス:Vportは、iPtablesランダムパターンルールを使用して、1つ以上の実際のポッドアドレス(DNAT)を指します。これが最も基本的なサービスの原則です。では、Kube-Proxyは何をしますか? Kube-Proxyはポッドの変更を聴き、ホストにこれらのNATルールを生成する責任があります。このモードでは、Kube-Proxyはトラフィックを転送せず、Kube-Proxyはパイプラインのブロック解除のみを担当します。 公式K8Sドキュメントは、Kube-Proxy [26]によってサポートされるさまざまなモードと基本原則のより良い紹介を提供します。以前のユーザースペースモードは基本的に非推奨であり、上記のiPtablesランダムルールプラクティスは、大規模な使用には推奨されません(理由を考えてください)。現在最も推奨されるのはIPVSモードです。これは、最初の2つに比べて大規模なパフォーマンスが向上しています。 IPVという言葉が比較的なじみのない場合、LVSという言葉はおそらく私たちがよく知っているものです。このモードでは、Kube-ProxyはホストにKube-IPVS0という名前の仮想ネットワークカードを作成し、サービスVIPをIPアドレスとして割り当てます。最後に、Kube-ProxyはカーネルのIPVSモジュールを使用して、このアドレスのバックエンドポッドのアドレスを設定します(IPVSADMコマンドを表示できます)。実際、カーネルでのIPVの実装は、NetFilterのNATメカニズムも使用します。違いは、IPVが各アドレスのNATルールを設定するのではなく、代わりにこれらのルールの処理をカーネル状態に配置し、IPTablesルールの数が基本的に一定であることを保証し、以前の問題をより良く解決することです。 上記のことは、負荷分散の問題を解決するだけであり、サービスの透明性については言及していません。 K8Sサービスをエクスポートする主な方法には、NodePort、Loadbalancerサービス(パブリッククラウドでのロードバランシングサービスを作成できます)、および外部名(Kube-DNSにCNAMEを追加)が含まれます。 2番目のタイプの場合、多くのサービスがあるがトラフィックが非常に少ない場合、イングレスのサービスを使用して収束することもできます[27]。 Ingressは現在、7層HTTP(S)転送のみをサポートしています(現在、サービスは4層転送のみをサポートしています)。この観点からイングレスがどのように実装されると思いますか?写真[28]を見てみましょう(もちろん他の多くのコントローラー[29]があります): この記事はこの部分では詳しく説明されません。それはNATに過ぎません。 NATが多すぎる場合は、NATエントリを収束する方法を見つけてください。条約によれば、ここには、さらに理解するためのKube-Proxyの原則に関する特に良い記事があります[30]。 4つの要約ネットワーク仮想化は大きなトピックであり、1つの記事で完全に説明することは困難です。この記事は、著者自身のエネルギーと認知の制限の制限のために、重要な知識ノードを明確に織り込もうとしていますが、過失やエラーさえあるかもしれません。そのような質問がある場合は、コメントセクションで説明/修正してください。参考文献には、さらに学習する価値のある優れた資料がたくさんあります(一部のアドレスはネットワーク環境によって制限されており、それらにアクセスするための特定の方法が必要になる場合があります)。 参考文献 1。LinuxでのTCP実装:簡単なチュートリアル、Helali Bhuiyan、Mark McGinley、Tao Li、Malathi Veeraraghavan、バージニア大学: https://www.semanticscholar.org/paper/tcp-implementation-in-linux-%3a-a-brief-tutorial-bhuiyan-mcginley/f505e259fb0cd8cf3f75582d46cd209fd9cb1d1a 2。NAPI、LinuxFoundation、https://wiki.linuxfoundation.org/networking/napi 3. Linuxネットワークスタックの監視とチューニング:データの受信、Joe Damato、翻訳:Linuxネットワークスタックの監視とチューニング:データの受信(2016):http://arthurchiao.art/blog/tuning-rx-zh/ 4。Linuxネットワークスタックの監視とチューニング:データの送信、Joe Damato、翻訳:Linuxネットワークスタックの監視とチューニング:データの送信(2017):http://arthurchiao.art/blog/tuning-tx-zh/ 5. Linuxネットワークスタックのスケーリング、https://github.com/torvalds/linux/blob/master/documentation/networking/scaling.rst 6.ソフトウェアエンジニアとシステムデザイナーのためにTCP内部を段階的に理解する、Kousik Nath 7。NetFilter、https://www.netfilter.org/ 8。NetFilter-Packet-Flow、https://upload.wikimedia.org/wikipedia/commons/3/37/netfilter-packet-flow.svg 9。Linuxの分析TCP、https://github.com/fzyz999/analysis_tcp_in_linux 10。NAT-ネットワークアドレス変換、翻訳:NAT-ネットワークアドレス変換(2016):http://arthurchiao.art/blog/nat-zh/ 11. Linuxの仮想ネットワーキング、M。Jones、IBM開発者:https://developer.ibm.com/tutorials/l-virtual-networking/ 12。Openvswitch、http://www.openvswitch.org/ 13。LinuxNamespace、https://man7.org/linux/man-pages/man7/namespaces.7.html 14。IP、https://man7.org/linux/man-pages/man8/ip.8.html 15。Veth、https://man7.org/linux/man-pages/man4/veth.4.html 16。Vxlan、https://en.wikipedia.org/wiki/virtual_extensible_lan 17。QINQ対VLAN vs Vxlan、John、https://community.fs.com/blog/qinq-vs-vlan-vs-vxlan.htm 18.仮想ネットワーキング用のLinuxインターフェイスの紹介、ハングビンLiu:https://developers.redhat.com/blog/2018/10/22/introduction-to-linux-interfaces-for-virtual-networking# 19.クラスターネットワーキング、英語アドレスhttps://kubernetes.io/zh/docs/concepts/cluster-administration/networking/ 20。コンテナネットワーキングランドスケープ:CoreosのCNI、DockerのCNM、Lee Calcote:https://thenewstack.io/container-networking-landscape-coneos-cnm-docker/ 21。CNI -Container Network Interface、https://github.com/containernetworking/cni 22。EBPFを使用したKubernetesサービス抽象スケールの作成、[翻訳] EBPFを使用して大規模なK8Sサービスをサポートする(LPC、2019):https://linuxplumbersconf.org/event/4/contributions/458/ 23. BPF/XDP(LPC、2020)に基づくK8Sサービスロードバランシングの実装https://linuxplumbersconf.org/event/7/contributions/674/ 24. IptablesとNetFilter Architecture、Justin Ellingwood:https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture 25。Iptablesチュートリアル1.2.2、Oskar Andreasson:https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html 26。仮想IPSおよびサービスプロキシ、英語アドレス:https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies 27。Ingress、英語住所:https://kubernetes.io/docs/concepts/services-networking/ingress/ 28。NginxIngressコントローラー、https://www.nginx.com/products/nginx-ingress-controller/ 29。イングレスコントローラー、英語アドレス:https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/ 30。Kubernetesノードプロキシ(別名Kube-Proxy)、[翻訳] Kubernetesネットワークモデルの詳細な理解:https://cloudnative.to/blog/k8s-node-proxy/ |
<<: 世界の医療クラウドコンピューティング市場規模は2026年に768億ドルに達すると予想されている
>>: 世界の医療クラウドコンピューティング市場規模は2026年に768億ドルに達すると予想されている
[51CTO.com クイック翻訳] サービスプロバイダーと企業は、今日のクラウドベースのアプリケー...
SEO は戦争のようなものです。私たちの武器は何でしょうか? 人気のキーワードに直面したとき、権威の...
Racknerd は今年のイースター プロモーションを発表しました: 米国 VPS、選択可能な 6 ...
柔軟性からフェイルオーバー保護まで、企業がマルチクラウド戦略を選択する理由は数多くあります。 IDC...
月収10万元の起業の夢を実現するミニプログラム起業支援プラン起業家は企業ブランドの重要な大使であり、...
SEO を必要とする企業や事業所がますます増えているため、現在の SEO 業界は混乱状態にあります。...
Baidu 投稿バー「ウェブマスター クラブ」がオフラインになっていることを知り、最近、Baidu ...
クラウド コンピューティングは、効率性を高め、データのセキュリティを強化し、利益を増やす機会を提供し...
ウェブサイトのランキングはドメイン名の重みと密接に関係していることは誰もが知っています。ウェブマスタ...
オンラインで保険を販売することが、蛇年で最も人気のあるマーケティング手法の 1 つになりつつあること...
1. 百度と360は24時間以内に5回攻撃し、360は起訴される可能性がある昨日午後4時、奇虎360...
この記事はWeChatの公開アカウント「Programmer Sir」から転載したもので、著者はPr...
検索エンジン最適化技術が発達するにつれて、ページの価値がランキングにおいてますます決定的になり、ウェ...
[[409211]]この記事はWeChatの公開アカウント「Geek Rebirth」から転載したも...
1. はじめに前回の記事では、Kafka のアーキテクチャモデルについて詳しく紹介しました。クラスタ...