ネットワークの概要

このページでは、Google Kubernetes Engine ネットワークの主な特徴について概説します。この情報は、Kubernetes を使い始めたばかりのユーザーだけでなく、アプリケーションを適切に設計するために、または Kubernetes ワークロードを適切に構成するために Kubernetes ネットワークに関する知識をさらに必要とする経験豊富なクラスタ オペレータやアプリケーション開発者にも役立ちます。

Kubernetes を使用すると、アプリケーションのデプロイ方法、アプリケーションの相互通信方法、アプリケーションと Kubernetes コントロール プレーンの通信方法、クライアントがアプリケーションにアクセスする方法を宣言型の方法で定義できます。また、このページでは、GKE が Google Cloud Platform サービスをどのように構成するかについても説明しており、これはネットワーキングとも関連します。

Kubernetes を使用してアプリケーションをオーケストレートする際は、アプリケーションとそのホストのネットワーク設計について考え方を変えることが重要です。Kubernetes では、ホストや VM がどのように接続されているかを考えるのではなく、ポッド、サービス、外部クライアントがどのように通信するかを考えます。

Kubernetes は、GCP とともに、Kubernetes デプロイの宣言モデルと GCP のクラスタ構成に基づき、各ノードの IP フィルタリング ルール、ルーティング テーブル、ファイアウォール ルールを動的に構成します。ノードは手動で変更しないでください。これらの変更は GKE によってオーバーライドされます。また変更により、クラスタが正しく機能しなくなる可能性があります。構成の問題をデバッグする場合にのみ、ノードに直接アクセスします。

前提条件

このページでは、HTTPDNS など、インターネット プロトコル スイートのトランスポート層、インターネット層、アプリケーション層に関連する用語を使用していますが、これらのトピックの専門家である必要はありません。

また、iptables のルールやルーティングなど、Linux のネットワーク管理のコンセプトやユーティリティについて基本的な知識があれば、内容を理解しやすくなります。

Kubernetes ネットワーク モデルは、IP アドレスに大きく依存しています。サービス、ポッド、コンテナ、ノードは、IP アドレスとポートを使用して通信します。Kubernetes は各種の負荷分散機能を提供しており、トラフィックを適切なポッドに振り分けます。これらの全メカニズムについては、このトピックの中で後ほど詳しく説明します。読み進めるとき、次の用語に注意してください。

  • ClusterIP: サービスに割り当てられた IP アドレス。他のドキュメントでは、「クラスタ IP」と呼ばれることもあります。このトピックのサービス セクションで説明しているように、このアドレスはサービスの存続期間中は不変です。
  • ポッド IP: 特定のポッドに割り当てられた IP アドレス。このトピックのポッド セクションで説明しているように、このアドレスは一時的です。
  • ノード IP: 特定のノードに割り当てられた IP アドレス。

クラスタ内のネットワーク

このセクションでは、Kubernetes クラスタ内のネットワークについて、IP 割り当てポッドサービスと関連付けて説明します。

IP 割り当て

Kubernetes はさまざまな IP 範囲を使用して、ノード、ポッド、サービスに IP アドレスを割り当てます。

  • 各ノードには、クラスタの Virtual Private Cloud(VPC)ネットワークから割り当てられた IP アドレスがあります。このノード IP により、kube-proxykubelet などの制御コンポーネントから Kubernetes API サーバーへの接続が実現します。
  • 各ポッドには、/24 CIDR ブロックの 256 個の IP アドレス範囲から割り当てられた IP アドレスがあります。この範囲は、クラスタの作成時にオプションで指定できます。
  • 各サービスには、クラスタの VPC ネットワークから割り当てられた、ClusterIP という IP アドレスがあります。オプションで、クラスタの作成時に VPC ネットワークをカスタマイズできます。

詳細については、エイリアス IP を使用した VPC ネイティブ クラスタの作成をご覧ください。

ポッド

Kubernetes では、ポッドは Kubernetes クラスタ内にデプロイできる最も基本的な単位です。1 つのポッドは 1 つ以上のコンテナを実行します。0 個以上のポッドがノードで実行されます。クラスタ内の各ノードはノードプールに属します。GKE では、これらのノードは仮想マシンであり、それぞれ Compute Engine でインスタンスとして実行されます。

ポッドは、外部ストレージ ボリュームやその他のカスタム リソースに接続することもできます。この図では、1 つのノードが 2 つのポッドを実行しており、各ポッドに 2 つのボリュームが接続されています。

上の段落で説明されている、2 つのポッドを実行する 1 つのノードを示す図

Kubernetes がポッドをノードで実行するようにスケジュールすると、ノードの Linux カーネルでポッドのネットワーク名前空間が作成されます。このネットワーク名前空間により、仮想ネットワーク インターフェースを使用して、ノードの物理ネットワーク インターフェース(eth0 など)とポッドが接続され、ポッドとの間でパケットをやり取りできるようになります。ノードのルート ネットワーク名前空間内の関連する仮想ネットワーク インターフェースは、同じノード上のポッド間の通信を可能にする Linux ブリッジに接続されます。ポッドは、同じ仮想インターフェースを使用して、ノード外にパケットを送信することもできます。

Kubernetes は、ノード上のポッド用に予約されたアドレスの範囲から、ポッドのネットワーク名前空間内の仮想ネットワーク インターフェースに IP アドレス(ポッド IP)を割り当てます。このアドレス範囲は、クラスタ作成時に構成できる、ポッドのクラスタに割り当てられる IP アドレス範囲のサブセットです。

ポッドで動作しているコンテナは、ポッドのネットワーク名前空間を使用します。コンテナの視点からは、ポッドは 1 つのネットワーク インターフェースを持つ物理マシンのように見えます。ポッド内のすべてのコンテナには、これと同じネットワーク インターフェースが見えます。各コンテナの localhost は、ポッドを介して、ノードの物理ネットワーク インターフェース(eth0 など)に接続されます。

この接続は、GKE のネイティブ CNI を使用するのか、クラスタ作成時にネットワーク ポリシーを有効にして Calico の実装を使用するのかによって、大きく異なります。

  • GKE の CNI を使用している場合、veth ペアの一方の端はその名前空間のポッドに接続され、もう一方は Linux ブリッジ デバイス cbr0 に接続されています。この場合、次のコマンドは cbr0 に接続されているさまざまなポッドの MAC アドレスを表示します。

    arp -n
    

    さらに、ツールボックス コンテナで次のコマンドを実行することによって、cbr0 に接続している veth ペアのそれぞれの端のルート名前空間が表示されます。

    brctl show cbr0
    
  • ネットワーク ポリシーが有効になっている場合、veth ペアの一方の端はポッドに、もう一方の端は eth0 に接続されています。この場合、次のコマンドは異なる veth デバイスに接続されているさまざまなポッドの MAC アドレスを表示します。

    arp -n
    

    さらに、ツールボックス コンテナで次のコマンドを実行することによって、cbr0 という名前の Linux ブリッジ デバイスがないことが表示されます。

    brctl show
    

クラスタ内での転送を容易にする iptables ルールは、シナリオごとに異なります。接続の問題の詳細なトラブルシューティングを行う際には、この違いを考慮することが重要です。

デフォルトでは、各ポッドはクラスタのすべてのノードで実行されている他のポッドに無制限にアクセスできます。しかし、ポッド間のアクセスを制限することは可能です。Kubernetes は定期的にポッドを破棄し、再作成します。この動作は、ノードプールがアップグレードされたとき、ポッドの宣言型の構成を変更したとき、コンテナのイメージを変更したとき、ノードが使用不可になったときに行われます。したがって、ポッドの IP アドレスは実装の詳細であるため、それらに依存しないようにしてください。Kubernetes は、サービスを使用して不変の IP アドレスを提供します。

サービス

Kubernetes では、任意の Kubernetes リソースにラベルと呼ばれる任意の Key-Value ペアを割り当てることができます。Kubernetes はラベルを使用し、関連する複数のポッドをサービスと呼ばれる論理単位にグループ化します。サービスは不変の IP アドレスとポートを持ち、サービス作成時にラベルセレクタで定義したすべてのラベルと一致するラベルを持つ一連のポッド間で負荷分散を行います。

次の図は、2 つの個別サービスを示しています。各サービスは複数のポッドで構成されています。図の各ポッドには app=demo というラベルが付いていますが、その他のラベルは異なります。サービス「frontend」は app=democomponent=frontend の両方を持つすべてのポッドに一致しており、サービス「users」は app=democomponent=users を持つすべてのポッドに一致しています。Client Pod はいずれのサービス セレクタとも正確には一致しないため、いずれのサービスにも含まれません。ただし、Client Pod も同じクラスタ内で実行されるため、いずれのサービスとも通信できます。

前の段落で説明されている 2 つの個別サービスを示す図

Kubernetes は新しく作成された各サービス(ClusterIP)に、クラスタの使用可能なサービス IP アドレスのプールから不変で信頼できる IP アドレスを割り当てます。また、Kubernetes は DNS エントリを追加することによって、ClusterIP にホスト名を割り当てます。ClusterIP とホスト名はクラスタ内で一意であり、サービスのライフサイクル全体で変更されません。Kubernetes は、クラスタの構成からサービスが削除された場合にのみ、ClusterIP とホスト名を解放します。ClusterIP またはサービスのホスト名のどちらを使用しても、アプリケーションを実行している正常なポッドにアクセスできます。

一見すると、サービスはアプリケーションにとって単一の障害点のように見えます。ただし、Kubernetes は、多数のノードで実行されているすべてのポッドにできるだけ均等にトラフィックを分散させます。このため、クラスタは、1 つ以上のノード(すべてではない)に影響する停止に耐えることができます。

Kubernetes は、各ノードで動作する kube-proxy コンポーネントを使用して、ポッドとサービス間の接続を管理します。kube-proxy はインライン プロキシではなく、下りトラフィック ベースの負荷分散コントローラです。Kubernetes API サーバーを監視し、ノードの iptables サブシステムに対して宛先 NAT(DNAT)ルールを追加および削除することで、正常なポッドに ClusterIP を継続的にマップします。ポッドで動作しているコンテナがサービスの ClusterIP にトラフィックを送信すると、ノードはランダムにポッドを選択し、トラフィックをそのポッドにルーティングします。

サービスを構成する場合、オプションで porttargetPort の値を定義することで、サービスのリスニング ポートを再マップできます。

  • port は、クライアントがアプリケーションにアクセスする場所です。
  • targetPort は、アプリケーションがポッド内のトラフィックを実際にリッスンするポートです。

kube-proxy は、ノードに対して iptables ルールを追加および削除することで、このポートの再マッピングを管理します。

次の図は、クライアント ポッドから別のノード上のサーバーポッドへのトラフィックの流れを示しています。クライアントは 172.16.12.100:80 でサービスに接続します。Kubernetes API サーバーは、アプリケーションを実行するポッドのリストを保持しています。各ノードの kube-proxy プロセスは、このリストを使用して、適切なポッド(10.255.255.202:8080 など)にトラフィックを送るための iptables ルールを作成します。クライアント ポッドは、クラスタのトポロジや、個々のポッドに関する詳細、それらのポッド内のコンテナに関する詳細を認知する必要ありません。

前の段落で説明されている、サービスに接続し、ポッドにルーティングされるクライアントを示す図

クラスタ外のネットワーク

このセクションでは、クラスタ外からのトラフィックが Kubernetes クラスタ内で実行されているアプリケーションにどのように到達するかについて説明します。この情報は、クラスタのアプリケーションとワークロードを設計する際に重要です。

ポッド内で実行されるアプリケーションに不変の IP アドレスを提供するために、Kubernetes がどのようにサービスを使用するかについては、すでにご紹介しました。デフォルトでは、ポッドは外部 IP アドレスを公開しません。これは、kube-proxy が各ノードのすべてのトラフィックを管理するためです。ポッドとそのコンテナは自由に通信できますが、クラスタ外の接続はサービスにアクセスできません。たとえば、前の図では、クラスタ外のクライアントは ClusterIP 経由でフロントエンド サービスにアクセスできません。

GKE には、アクセスを制御し、クラスタ全体に着信トラフィックをできるだけ均等に分散させるための 3 種類のロードバランサが用意されています。複数のタイプのロードバランサを同時に使用するように 1 つのサービスを構成できます。

  • 外部ロードバランサは、クラスタ外および GCP Virtual Private Cloud(VPC)ネットワーク外からのトラフィックを管理します。このロードバランサは、GCP ネットワークに関連付けられた転送ルールを使用して、Kubernetes ノードにトラフィックをルーティングします。
  • 内部ロードバランサは、同じ VPC ネットワーク内からのトラフィックを管理します。このロードバランサも、外部ロードバランサと同様に、GCP ネットワークに関連付けられた転送ルールを使用して、Kubernetes ノードにトラフィックをルーティングします。
  • HTTP(S) ロードバランサは、HTTP(S) トラフィックに使用される特別な外部ロードバランサです。このロードバランサは、転送ルールではなく Ingress リソースを使用して、Kubernetes ノードにトラフィックをルーティングします。

トラフィックが Kubernetes ノードに到達すると、ロードバランサのタイプに関係なく、同じ方法で処理されます。ロードバランサは、クラスタ内のどのノードがそのサービス用のポッドを実行しているか認識しません。代わりに、ノードが関連するポッドを実行していない場合でも、クラスタ内のすべてのノード間でトラフィックのバランスをとります。リージョン クラスタでは、クラスタのリージョンのすべてのゾーン内のすべてのノードに対して負荷が分散されます。トラフィックがノードにルーティングされると、ノードはそのトラフィックを同じノードまたは別のノードで実行されているポッドにルーティングします。ノードは、そのノード上で kube-proxy が管理する iptables ルールを使用して、トラフィックをランダムに選択されたポッドに転送します。

次の図では、ネットワーク ロードバランサはトラフィックを中央のノードに転送し、そのトラフィックは左側のノードのポッドにリダイレクトされます。

前の段落で説明されている、あるノードから別のノード上のポッドにルーティングされるトラフィックを示す図

ロードバランサがトラフィックをノードに送信した後、そのトラフィックは別のノード上のポッドに転送される可能性があります。その場合、ネットワーク ホップが余計に必要となります。この追加のホップを避けたい場合は、最初にトラフィックを受信したノードと同じノード上のポッドにトラフィックを送信するように指定できます。

トラフィックを同じノード上のポッドに送信するように指定するには、サービス マニフェストで externalTrafficPolicyLocal に設定します。

apiVersion: v1
kind: Service
metadata:
  name: my-lb-service
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  selector:
    app: demo
    component: users
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

externalTrafficPolicyLocal に設定すると、ロードバランサは、そのサービスに属するノードのうち正常なポッドを持つノードにのみトラフィックを送信します。ロードバランサは、ヘルスチェックを使用して、どのノードに適切なポッドがあるかを判断します。

外部ロードバランサ

クラスタ外および VPC ネットワーク外からサービスに到達できるようにする必要がある場合、サービスの定義時に、サービスの type フィールドを LoadBalancer に設定することで、サービスを LoadBalancer として構成できます。これにより、GKE は、サービスの前にネットワーク ロードバランサをプロビジョニングします。ネットワーク ロードバランサは、クラスタ内のすべてのノードを認識し、VPC ネットワークのファイアウォール ルールを構成することで、VPC ネットワーク外からサービスの外部 IP アドレスを使用してサービスに接続できるようにします。静的な外部 IP アドレスをサービスに割り当てることができます。詳細については、静的 IP アドレスを使用したドメイン名の構成をご覧ください。

技術的な詳細情報

外部ロードバランサを使用する場合、到着するトラフィックは、最初に GCP ネットワークに関連付けられている転送ルールを使用してノードにルーティングされます。トラフィックがノードに到達した後、ノードはその iptables NAT テーブルを使用してポッドを選択します。ノードの iptables ルールは kube-proxy が管理します。

内部ロードバランサ

同じ VPC ネットワーク内からクラスタに到達する必要のあるトラフィックのために、サービスを構成して内部ロードバランサをプロビジョニングできます。内部ロードバランサは、外部 IP アドレスは選択せず、クラスタの VPC サブネットから IP アドレスを選択します。VPC ネットワーク内のアプリケーションまたはサービスは、この IP アドレスを使用してクラスタ内のサービスと通信できます。

技術的な詳細情報

内部ロードバランサ機能は GCP によって提供されます。トラフィックが特定のノードに到達すると、ノードはその iptables NAT テーブルを使用してポッドを選択します。ポッドが別のノードにあっても該当するポッドを選択します。 ノードの iptables ルールは kube-proxy によって管理されます。

内部ロードバランサの詳細については、内部ロードバランサのドキュメントをご覧ください。

HTTP(S) ロードバランサ

RESTful ウェブサービス API などの多くのアプリケーションは、HTTP(S) を使用して通信します。Kubernetes Ingress リソースを使用することで、VPC ネットワークの外部のクライアントがこのタイプのアプリケーションにアクセスすることを可能にできます。Ingress リソースを使用すると、ホスト名と URL パスをクラスタ内のサービスにマップできます。HTTP(S) ロードバランサを使用する場合、ClusterIP だけでなく NodePort も使用するようにサービスを構成する必要があります。トラフィックが NodePort でノードの IP 上のサービスにアクセスすると、GKE はそのトラフィックをサービス内の正常なポッドにルーティングします。NodePort を指定することも、GKE で未使用のポートをランダムに割り当てることもできます。

Ingress リソースを作成すると、GKE は GCP プロジェクトに HTTP(S) ロードバランサをプロビジョニングします。ロードバランサは、NodePort でノードの IP アドレスにリクエストを送信します。リクエストがノードに到達した後、ノードはその iptables NAT テーブルを使用してポッドを選択します。ノードの iptables ルールは kube-proxy が管理します。

次の Ingress 定義では、demo.example.com へのトラフィックがポート 80 の frontend という名前のサービスにルーティングされ、demo-backend.example.com へのトラフィックがポート 8080 の users という名前のサービスにルーティングされます。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: demo
spec:
  rules:
  - host: demo.example.com
    http:
      paths:
      - backend:
          serviceName: frontend
          servicePort: 80
  - host: demo-backend.example.com
    http:
      paths:
      - backend:
          serviceName: users
          servicePort: 8080

詳細については、Google Cloud Platform での Ingress をご覧ください。

技術的な詳細情報

Ingress オブジェクトを作成すると、GKE Ingress コントローラは、Ingress マニフェストと関連するサービス マニフェストのルールに従って、GCP HTTP(S) ロードバランサを構成します。クライアントは HTTP(S) ロードバランサにリクエストを送信します。ロードバランサはプロキシとして機能し、ノードを選択すると、そのノードの NodeIP:NodePort の組み合わせにリクエストを転送します。ノードはその iptables NAT テーブルを使用してポッドを選択します。 ノードの iptables ルールは kube-proxy によって管理されます。

ポッドとサービスへの接続の制限

デフォルトでは、同じクラスタ内で実行されているすべてのポッドは自由に通信できます。ただし、必要に応じて、クラスタ内の接続をさまざまな方法で制限できます。

ポッド間のアクセスを制限する

ネットワーク ポリシーを使用して、ポッド間のアクセスを制限できます。ネットワーク ポリシー定義を使用すると、ラベル、IP 範囲、ポート番号の任意の組み合わせに基づいて、ポッドの上り下りを制限できます。デフォルトではネットワーク ポリシーはないため、クラスタ内のポッド間のすべてのトラフィックが許可されます。名前空間に最初のネットワーク ポリシーを作成すると、他のトラフィックはすべて拒否されます。

ポリシー自体を指定する方法について詳しくは、ネットワーク ポリシーをご覧ください。

ネットワーク ポリシーを作成した後、クラスタに対してそのポリシーを明示的に有効にする必要があります。詳細については、アプリケーションのネットワーク ポリシーの構成をご覧ください。

外部ロードバランサへのアクセスを制限する

サービスで外部ロードバランサが使用されている場合、外部 IP アドレスからのトラフィックはデフォルトでサービスにアクセスできます。サービス構成時に loadBalancerSourceRanges オプションを構成することで、クラスタ内のエンドポイントにアクセスできる IP アドレスの範囲を制限できます。複数の範囲を指定でき、またいつでも実行中のサービスの構成を更新できます。各ノードで動作している kube-proxy インスタンスは、指定された loadBalancerSourceRanges に一致しないトラフィックはすべて拒否するように、そのノードの iptables ルールを構成します。VPC ファイアウォール ルールは作成されません。

HTTP(S) ロードバランサへのアクセスを制限する

サービスで HTTP(S) ロードバランサが使用される場合、Cloud Armor セキュリティ ポリシーを使用して、サービスにアクセスできる外部 IP アドレスを制限でき、またセキュリティ ポリシーのためにアクセスが拒否された場合に返すレスポンスを制限できます。Stackdriver Logging を構成することで、これらの操作に関する情報を記録できます。

Cloud Armor セキュリティ ポリシーの詳細レベルでは不十分な場合は、エンドポイントで Cloud Identity-Aware Proxy を有効にして、アプリケーションのためにユーザー単位の認証と承認を実装できます。詳細については、Cloud IAP の構成に関する詳細なチュートリアルをご覧ください。

次のステップ

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Kubernetes Engine のドキュメント