DUICUO

テストスキルの向上 - Kubernetes のコアネットワーク概念

Kubernetes (k8s) を初めて使う人の多くは、ネットワークの概念にすっかり混乱してしまいます。ノードIPやクラスターIPなど、様々なIPが混乱を招きます。ノードIPとは一体何でしょうか?インターネットはどのようにKubernetesにアクセスするのでしょうか?Kubernetes内の様々なポッドはどのように相互通信するのでしょうか?この記事では、これらの疑問にお答えします。

Kubernetes のコアネットワーク概念の紹介

ノードIP

ノードの IP アドレスは、その物理ネットワーク インターフェイス カード (NIC) の IP アドレスです。

NodePort は物理マシンの IP アドレス(または仮想マシンの IP アドレス)です。各 Service は Node ノード上でポートを開き、Service 内の Pod への外部アクセスは NodeIP:NodePort を介して行われます。これは、サーバー上にデプロイされたプロジェクトに IP:port/プロジェクト名 を使用してアクセスするのと同じです。

クラスターIP

サービスのIPアドレスは仮想IPアドレスです。外部ネットワークからpingすることはできず、Kubernetesクラスター内の内部アクセスにのみ使用されます。クラスターIPは仮想IPですが、以下の理由から、偽造IPネットワークに近いと言えます。

1. クラスター IP は k8s サービス オブジェクトにのみ適用され、k8s によって管理および割り当てられます。

2. クラスター IP に ping できません。応答する「物理ネットワーク オブジェクト」がありません。

3. クラスターIPはサービスポートと組み合わせてのみ、特定の通信ポートを形成できます。スタンドアロンのクラスターIPには通信基盤がなく、Kubernetesクラスターの閉じた空間に属します。

4. 異なるサービスに属するポッド ノードは、クラスター IP を介してクラスター全体で相互にアクセスできます。

ポッドIP

Pod IPは各PodのIPアドレスで、DockerブリッジのIPアドレス範囲に基づいてDocker Engineによって割り当てられます。通常は仮想レイヤー2ネットワークです。

  • 同じサービス下の Pod は、Pod IP に基づいて直接相互に通信できます。
  • 異なるサービスに属するポッドは、クラスター IP を使用してクラスター内で相互に通信する必要があります。
  • ポッドはノード IP を使用してクラスター外部のエンティティと通信します。

つまり、外部からアクセスする場合、リクエストは最初にノード ネットワークに送信され、次にサービス ネットワークに送信され、最後にポッド ネットワークにプロキシされます。

Kubernetes はネットワーク通信をどのように実装しますか?

3つの基本原則

  1. デフォルトでは、Linux はすべてのプロセスをルート ネットワーク名前空間に割り当て、プロセスが外部ネットワークにアクセスできるようにします。
  2. Kubernetes は各 Pod に対してネットワーク名前空間を作成します。
  3. Kubernetes (Kubernetes) において、Pod とはネットワーク名前空間を共有する Docker コンテナの集合です。Pod 内のすべてのコンテナは、このネットワーク名前空間によって提供される同じ IP アドレスとポート空間を使用します。すべてのコンテナは、localhost を介して同じ Pod 内の他のコンテナと直接通信できます。

コンテナ間ネットワーク通信

ポッド内の各Dockerコンテナは、ポッド自体とネットワーク名前空間を共有します。そのため、IPアドレスやポートなどのネットワーク設定は、ポッドと同一になります。これは主に、「コンテナ」と呼ばれるDockerネットワークモードによって実現されます。新規に作成されたDockerコンテナは、独自のネットワークインターフェースを作成したり、独自のIPアドレスを設定したりするのではなく、指定されたコンテナとIPアドレスとポート範囲を共有します。

ポッド間のネットワーク通信

Pod の観点から見ると、Pod は自身のネットワーク名前空間内の同じノード上の別のネットワーク名前空間のプロセスと通信します。Linux では、異なるネットワーク名前空間は、仮想イーサネット デバイス (新しいウィンドウが開きます) または veth ペア (複数の名前空間にまたがる 2 つの仮想ネットワーク インターフェイス カード) を使用して通信できます。Pod のネットワーク名前空間に接続するには、veth ペアの一方の端をルート ネットワーク名前空間に割り当て、もう一方の端を Pod のネットワーク名前空間に割り当てます。各 veth ペアはネットワーク ケーブルに似ており、2 つの端を接続してトラフィックを通過させます。veth ペアの数は、ノード上の Pod の数と等しくなります。次の図は、Pod をルート名前空間に接続する veth ペアを示しています。

ポッドがルートネットワーク名前空間を介して相互に通信できるようにするには、ネットワークブリッジを使用します。Linux Ethernet ブリッジは、2つ以上のネットワークセグメントを接続するために使用できる仮想レイヤー2ネットワークデバイスです。ブリッジは、送信元と宛先間の転送テーブルを維持することで機能します。ブリッジを通過するパケットの宛先アドレスとこの転送テーブルをチェックすることで、ブリッジに接続された別のネットワークセグメントにパケットを転送するかどうかを決定します。ブリッジコードは、ネットワークインターフェースカード (NIC) の固有の MAC アドレスを使用して、データをブリッジするかドロップするかを決定します。ブリッジは ARP プロトコルを実装し、リンク層で IP アドレスにバインドされた MAC アドレスを検出します。ブリッジはデータフレームを受信すると、接続されているすべてのデバイス (送信元を除く) にフレームをブロードキャストし、対応するデバイスをルックアップテーブルに記録します。その後、ブリッジは同じ IP アドレス宛てのトラフィックを受信すると、ルックアップテーブルを使用して対応する MAC アドレスを見つけ、パケットを転送します。下の図では、cbr0 がブリッジです。

異なるノード間の通信原理

通常、クラスタ内の各ノードにはCIDRネットワークセグメント(簡単に言うと、CIDRは複数の標準ネットワークを1つの大きなネットワークに統合します)が割り当てられ、そのノード上のPodが利用できるIPアドレスの範囲が指定されます。そのCIDRネットワークセグメント宛てのトラフィックがノードに到達すると、そのノードは対応するPodにトラフィックを転送する役割を担います。次の図は、2つのノード間のデータパケット転送プロセスを示しています。

ポッドとサービス間のネットワーク通信

Pod の IP アドレスは静的ではありません。Pod の再スケジュール (例: 水平スケーリング、アプリケーションのクラッシュ、ノードの再起動) により、Pod の IP アドレスは現れたり消えたりします。この間、Pod のクライアントはどの IP アドレスにアクセスすればよいかわかりません。Kubernetes では、この問題を解決するために Service の概念が使用されます。Service は複数の Pod を管理し、各 Service は仮想 IP アドレスを持ちます。Service によって管理される Pod 上のサービスにアクセスするには、この仮想 IP アドレスにアクセスするだけで済みます。この仮想 IP アドレスは固定です。Service 下の Pod のサイズが変更されたり、Pod に障害が発生して再起動したり、ノードが再起動したりしても、サービスのユーザーにはわかりません。これは、使用しているサービスの IP アドレスが変更されないからです。データ パケットが Service の仮想 IP アドレスに到着すると、Kubernetes によってそのサービス用に自動的に作成されたロード バランサーによって、パケットは基盤となる Pod コンテナにルーティングされます。

Service は Kubernetes におけるサービス検出メカニズムであり、そのコア機能は次のように要約できます。

  • 通常、ポッドはサービスに関連付けられ、外部アクセス インターフェースが提供されます。
  • サービスは負荷分散を実装し、選択したポッドのグループにリクエストを均等に分散できます。
  • サービスは、ラベルセレクターを使用してポッドのグループを選択します。

サービスIP割り当て戦略

Kubernetes の設計理念の一つは、人為的ミスの可能性を最小限に抑えることです。サービスを設計する際には、Kubernetes はユーザーが選択したポート番号を他のユーザーが選択したポート番号から分離する必要があります。そのために、Kubernetes は各サービスに一意の IP アドレスを割り当てます。各サービスが一意の IP アドレスを持つようにするために、Kubernetes はサービスを作成する前に etcd のグローバル割り当てテーブルを更新します。更新が失敗した場合(例:IP アドレスが既に別のサービスで使用されている場合)、サービスは正常に作成されません。Kubernetes はバックグラウンド コントローラーを使用して、このグローバル割り当てテーブル内の IP アドレス割り当てが有効かどうかを確認し、サービスで使用されなくなった IP アドレスを自動的にクリーンアップします。

サービスDNS解決

Kubernetes クラスターでは、対応するサービスが設定された DNS Pod のセットが実行されます。Kubernetes は、DNS 名を解決するために、各ノード上のコンテナに DNS Service の IP アドレスを割り当てます。クラスター内の各 Service(DNS Service 自体を含む)には DNS 名が割り当てられます。デフォルトでは、クライアント Pod の DNS ルックアップリストには、Pod が存在する名前空間とクラスターのデフォルトドメインが含まれます。例:

名前空間 A に foo という名前のサービスがあるとします。

  • 名前空間 A の Pod は、nslookup foo を使用して Service を見つけることができます。
  • 名前空間 B の Pod は、 nslookup foo.A を使用してサービスを見つけるために見つけることができます。

インターネットとKubernetesネットワーク通信

Kubernetes クラスターへのインターネット トラフィックの許可は、ネットワーク構成に固有であり、ネットワーク スタックのさまざまなレイヤーで実現できます。

  • ノードポート

NodePortサービスは、外部トラフィックをサービスにルーティングする最も基本的な方法です。名前の通り、NodePortはすべてのノード(仮想マシン)で特定のポートを開き、そのポートに送信されたトラフィックは対応するサービスに転送されます。

  • サービスロードバランサー

これは、サービスを直接公開する場合のデフォルトの方法です。指定したポート宛てのすべてのトラフィックは、対応するサービスに転送されます。フィルタリングとルーティング機能を備えています。Kubernetesをローカルの開発/テスト環境にセットアップする場合、通常はロードバランサーをサポートしていないため、NodePort経由のテストで十分なため、ロードバランサーは不要です。ただし、本番環境やパブリッククラウド上のKubernetesでは、ほとんどの場合、ロードバランサーの自動作成がサポートされています。

  • イングレスコントローラ

これは複数のサービスのフロントエンドに位置し、「スマートルーター」またはクラスタのエントリポイントとして機能します。本質的には、Kubernetesクラスタ内の特別なサービス(公開種類:Ingress)です。このサービスは、Nginxと同様に、主にレイヤー7リバースプロキシ機能を提供します(セキュリティ認証、監視、レート制限、SSL証明書などの高度な機能も提供できます)。IngressはHostPort(80/443)を介して外部に公開され、前述のロードバランサーとのインターフェースを可能にします。このIngressサービスを使用すると、1つのLB+IPアドレスのみを購入し、複数(またはすべて)の内部サービスをIngress経由で公開することで、プロキシと転送を処理できます。