Cilium Cilium

Cilium の Gateway API サポートで Service を公開する

GatewayClass、Gateway、HTTPRoute:ホストベースのルーティング、パスマッチング、URL リライト、TLS。専用のゲートウェイ Pod は不要です。

14 min learn.level.中級

Kubernetes Gateway API は Ingress の標準化された後継であり、Cilium は独自の eBPF データパスと、レイヤー 7 処理用の組み込み Envoy を使って、これを直接実装しています。このガイドでは、Gateway API が有効な状態で Cilium がすでにインストールされていることを前提に(前のガイドを参照)、中核となるリソースである GatewayClass、Gateway、HTTPRoute と、それらから構築されるルーティングパターンを説明します。

GatewayClass:Cilium を利用可能なコントローラーとして宣言する

GatewayClass は、クラスターに「このコントローラーを Gateway が使用できる」ことを伝えます。

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: cilium
spec:
  controllerName: io.cilium/gateway-controller

インストール時に gatewayAPI.gatewayClass.create: false を設定した場合(前のガイドで推奨)、このリソースが、そのギャップを埋めるために自分で作成するものです。

CiliumGatewayClassConfig でクラスをカスタマイズする

Cilium は、特定のクラスを使うすべての Gateway に適用すべき設定のために、独自の CRD CiliumGatewayClassConfig を提供しています。最も一般的なのは、Gateway を公開する Kubernetes Service のタイプです。

apiVersion: cilium.io/v2alpha1
kind: CiliumGatewayClassConfig
metadata:
  name: gateway-api-config
  namespace: default
spec:
  service:
    type: NodePort
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: cilium
spec:
  controllerName: io.cilium/gateway-controller
  parametersRef:
    group: cilium.io
    kind: CiliumGatewayClassConfig
    name: gateway-api-config
    namespace: default

ここでの NodePort は、後述する kind クラスター向けの特別な対応です。実際のクラウドロードバランサーが利用できるクラスターでは、LoadBalancer のほうが一般的な選択です。このシリーズの BGP ルートアドバタイズに関する後続のガイドでは、クラウドプロバイダーのロードバランサーなしでルーティング可能なアドレスを取得する方法を説明します。

Gateway を作成する

Gateway は実際のリスナー設定であり、上のクラスを参照します。

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: demo-gateway
  namespace: default
spec:
  gatewayClassName: cilium
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: All
    - name: https
      protocol: HTTPS
      port: 443
      allowedRoutes:
        namespaces:
          from: All
      tls:
        mode: Terminate
        certificateRefs:
          - name: demo-tls-secret

ゲートウェイ Pod は存在しない:ここが Cilium の違い

多くの Gateway API 実装では、Gateway を作成すると、そのゲートウェイインスタンス専用の Deployment と Pod が作成されます。Cilium では作成されません。トラフィックはノードレベルで eBPF によって傍受され、Gateway の設定に従ってルーティングされ、現れるのは Kubernetes の Service だけで、Gateway 専用の Pod はありません。

kubectl get gateway demo-gateway
kubectl get service -l gateway.networking.k8s.io/gateway-name=demo-gateway

特に kind クラスターでは、NodePort Service にはデフォルトでランダムなポートが割り当てられ、本来必要なポート(先の kind クラスター設定の 30080/30443)にはなりません。明示的にパッチを当てます。

kubectl patch service <gateway-service-name> --type='json' -p='[
  {"op": "replace", "path": "/spec/ports/0/nodePort", "value": 30080},
  {"op": "replace", "path": "/spec/ports/1/nodePort", "value": 30443}
]'

このパッチ適用の手順は、本物のロードバランサーがない kind 向けの単なる回避策であり、Cilium の一般的な制限ではありません。実際のクラウド LoadBalancer 実装がある場合や、Cilium 自身の L2 アナウンスまたは BGP ルートアドバタイズ(このシリーズの後続のガイド)がある場合は、手動でパッチを当てなくても、Gateway の Service にルーティング可能なアドレスが割り当てられます。

ホスト名でルーティングする

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: python-route
  namespace: default
spec:
  parentRefs:
    - name: demo-gateway
  hostnames:
    - "python.example.com"
  rules:
    - backendRefs:
        - name: python-service
          port: 5000

parentRefs はこのルートを Gateway に関連付けます(同じ namespace にある必要があります。そうでない場合、ルートには明示的なクロス namespace の参照ポリシーが必要です)。Host ヘッダーが python.example.com のリクエストは、python-service に送られます。

パスでルーティングする:完全一致とプレフィックス一致

  rules:
    - matches:
        - path:
            type: Exact
            value: /
      backendRefs:
        - name: python-service
          port: 5000

Exact はそのリテラルパスにのみ一致します。/status へのリクエストは、/ に限定されたルールには一致しません。単一の固定パス以外では、PathPrefix が指定したプレフィックスに一致し、パスの残りの部分をそのまま転送します。

  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /

この違いは実際に重要です。1 つのルートの背後に複数のエンドポイントを持つ API では、Exact ではなく PathPrefix が必要です。そうしないと、リテラルに一致するパス以外のすべてのエンドポイントが、バックエンドに到達せずルートが見つからないというエラーを返します。

URL リライト:外部向けはきれいなパス、内部は別のパス

よくあるパターンは、複数のバックエンドサービスを、整理されたパス体系を持つ 1 つの統合ホスト名の下で公開しつつ、各バックエンドは外部のプレフィックスを知らずに独自の内部ルートを維持するというものです。

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: python-route
  namespace: default
spec:
  parentRefs:
    - name: demo-gateway
  hostnames:
    - "example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api/python
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /
      backendRefs:
        - name: python-service
          port: 5000

example.com/api/python/status へのリクエストは、/api/python プレフィックスに一致し、python-service に届く前に /status に書き換えられます。そのため、バックエンド自身は外部から見える /api/python プレフィックスを知る必要がありません。バックエンドサービスごとに同様のルートを定義する(Go サービスには /api/go など)ことで、独立して開発された複数のバックエンドから、1 つの統合 API ゲートウェイを構築できます。各バックエンドは、ゲートウェイが外部に提示するパス構造を知らないままです。

TLS:2 つの設定が一致する必要がある

HTTPS トラフィックを処理するには、2 つの要素を一貫して設定する必要があります。

  1. Gateway の HTTPS リスナー(上記)が TLS Secret を参照し、mode: Terminate を設定します。
  2. HTTPS トラフィックを受け付けるすべての HTTPRoute の parentRefs エントリが、Gateway 全体だけでなく、HTTPS リスナーを名前で実際に指す必要があります。
  parentRefs:
    - name: demo-gateway
      sectionName: https

sectionName で HTTPS リスナーを明示的に指定しないと、ルートは一致条件にデフォルトで合致するリスナーにアタッチされますが、それが意図したものとは限りません。TLS Secret を参照する Gateway を適用する前に、Secret を作成してください。

kubectl create secret tls demo-tls-secret \
  --cert=path/to/cert.pem \
  --key=path/to/key.pem \
  -n default

リスナーが期待どおりにトラフィックを受け付けていない場合は、まず kubectl describe gateway demo-gateway を確認してください。TLS Secret がない、または不正な形式であることは、リスナーが accepted にならない一般的な原因です。

人気のガイド