KubernetesのService・Ingressの関係とPodへの通信経路

Kubernetesでアプリを動かせても、「外からどうやってPodにアクセスするのか」でつまずくことは多いです。ServiceとIngressはどちらも通信に関わりますが、守備範囲が違い、混ざると通信経路を説明できなくなります。

この記事は、『Kubernetesのデプロイ概要まとめ』で見たとおり「Podは作り直されるたびにIPが変わる」という前提から出発し、なぜPodに直接アクセスしないのか、Serviceが何を安定させ、Ingressが何を担うのかを、通信経路として一本につなぎます。

この記事でわかること
  • Podに直接アクセスしない理由
  • ServiceとIngressの役割の違い
  • 外部リクエストがPodに届くまでの通信経路
  • GKEでIngressがGCPのLoad Balancerに対応する話

前提知識:Kubernetesの通信リソースとは

『Kubernetesの概要・全体像まとめ』では、KubernetesをCluster・Control Plane・Node・Pod・Containerの関係で整理しました。そこで出てきたPodは、コンテナを動かす最小単位です。

ただし、Podはアプリケーションを動かす場所であって、安定した通信先そのものではありません。『Kubernetesのデプロイ概要まとめ』で見たように、Podは落ちたり更新されたりすると新しいPodとして作り直されます。

そこでKubernetesでは、Podへ通信を届けるために、Podとは別のリソースを使います。この記事で扱うServiceとIngressは、その通信経路を作るためのリソースです。

flowchart TB
  Service["Service(Podの安定した宛先)"]
  Ingress["Ingress(外部からの入口)"]
  subgraph Cluster["Cluster"]
    subgraph Node["Node"]
      Pod["Pod(コンテナが動く場所)"]
    end
  end
  Ingress --> Service --> Pod

ServiceはPodの前に立つ安定した宛先で、Ingressはクラスタ外からのリクエストを受ける入口です。つまり、ServiceはKubernetesの「どこかの機械」を指す名前ではなく、変わりやすいPodに通信を届けるためのKubernetesリソースです。

Service: Podへの安定した宛先

Serviceは、変わりやすいPodに直接アクセスしなくてよいように、Podの前に置く安定した宛先です。まず、なぜPodを直接宛先にしないのかを押さえます。

Podに直接アクセスしない理由

Podは使い捨ての単位です。落ちれば新しいPodとして作り直され、そのときIPアドレスが変わります。ローリングアップデートでも、Podは新しいものに入れ替わります。

つまりPodのIPは、いつ変わってもおかしくない一時的なものです。もし呼び出す側がPodのIPを直接指定していたら、Podが作り直されるたびに宛先が無効になり、通信が切れます。さらにPodが複数あるとき、どのPodに振り分けるかも自分で管理しなければなりません。

この「宛先が安定しない」「複数Podへの振り分けを自分でやる必要がある」という問題を解くのがServiceです。

ServiceがPodをまとめて振り分ける

Serviceは、複数のPodをまとめて1つの安定した宛先として見せるリソースです。個々のPodのIPは変わっても、Serviceには変わらない名前とアドレスが割り当てられます。

flowchart TB
  Client["呼び出す側"]
  SVC["Service(安定した宛先)"]
  P1["Pod"]
  P2["Pod"]
  P3["Pod"]
  Client -->|"Service名でアクセス"| SVC
  SVC -->|"振り分け"| P1
  SVC -->|"振り分け"| P2
  SVC -->|"振り分け"| P3

呼び出す側はService名にアクセスするだけでよく、Serviceが背後の生きているPodへ振り分けます。Podが増減しても、落ちてIPが変わっても、Serviceを見ている側は影響を受けません。

Serviceは主にクラスタ内の通信で使われます。「注文サービスからユーザーサービスを呼ぶ」とき、相手のPodではなくユーザーサービスのServiceを宛先にする、という使い方です。振り分けはIPやポート単位(L4)で行われます。

一方で、Serviceだけでは「外部から特定のパスのリクエストを、このサービスに送る」といったWeb向けのルーティングは扱えません。ここでIngressが登場します。

Ingress: 外部からの入口

Ingressは、クラスタの外から来るHTTP/HTTPSリクエストの入口をまとめ、URLのパスやホスト名に応じて適切なServiceへ振り分けるリソースです。

たとえば次のようなルーティングを1か所で定義できます。

  • /api/users へのリクエストはユーザーサービスのServiceへ
  • /api/orders へのリクエストは注文サービスのServiceへ
  • HTTPSの証明書もIngressでまとめて扱う

Serviceがクラスタ内の安定した宛先とL4の振り分けを担うのに対し、Ingressは外部公開とURLベース(L7)のルーティングを担います。両者は競合せず、Ingressの振り分け先がServiceになる、という積み重ねの関係です。

外部リクエストがPodに届くまでの通信経路

ここまでの登場人物を通信の順につなぐと、外部リクエストがPodに届くまでは次の経路になります。

flowchart LR
  User["User"]
  Ing["Ingress"]
  UserSvc["users Service"]
  OrderSvc["orders Service"]
  UserPod1["users Pod"]
  UserPod2["users Pod"]
  OrderPod1["orders Pod"]
  OrderPod2["orders Pod"]
  User --> Ing
  Ing -->|"/api/users"| UserSvc
  Ing -->|"/api/orders"| OrderSvc
  UserSvc --> UserPod1
  UserSvc --> UserPod2
  OrderSvc --> OrderPod1
  OrderSvc --> OrderPod2
  • User
    • 外部の利用者からのリクエスト
  • Ingress
    • 入口としてリクエストを受け、URLに応じてServiceを選ぶ。HTTPのパスやホスト名を見て振り分けるので、L7ルーティングと呼ばれる
  • Service
    • 選ばれたサービスの安定した宛先として、同じ役割を持つ複数のPodへ振り分ける。HTTPのパスではなく、宛先IPやポートをもとにPodへ渡すので、L4の振り分けと呼ばれる
  • Pod
    • 実際に処理するコンテナ

この経路が分かると、「Podが入れ替わってもUserは同じURLでアクセスし続けられる」理由が説明できます。変わりやすいPodを、ServiceとIngressという安定した層で包んでいるためです。

参考: GKEではIngressがGCPのLoad Balancerに対応する

Ingressは「こうルーティングしたい」という宣言で、それを実現する実体は環境によって変わります。GKE(GCPのマネージドKubernetes)では、Ingressを作ると実体としてGCPのLoad Balancerが自動的に構成されます。

  • Ingressを作ると、GCP側にApplication Load Balancerが用意される
  • ServiceはLoad Balancerそのものではなく、Ingressの振り分け先として使われる

これにより、Kubernetesの世界で「Ingressで公開する」と書いた内容が、GCPのネットワーク層で実際のトラフィック分散として動きます。GCPのLoad Balancerそのものの種類や構成は『GCPのLoad Balancer・Backend Service・MIG・VMの関係を整理する』で扱っています。

なお、Ingressの後継として、より柔軟なルーティングを宣言できるGateway APIも使われるようになっていますが、「外部からの入口をServiceへ振り分ける」という役割の位置づけは同じです。

まとめ

ServiceとIngressは、変わりやすいPodを安定した層で包み、外部からの通信を届けるための仕組みです。要点は以下です。

  • Podは作り直されるたびにIPが変わるため、直接名指しでアクセスしない
  • Serviceは複数のPodをまとめた安定した宛先で、クラスタ内通信とL4の振り分けを担う
  • Ingressは外部からの入口で、URLに応じてServiceへ振り分けるL7ルーティングを担う
  • 通信経路は User → Ingress → Service → Pod で、変わりやすいPodを安定層が包む構造
  • GKEではIngress/GatewayがGCPのLoad Balancerに対応し、宣言がGCPのトラフィック分散として実現される

参考

タグ: マイクロサービス, システム設計