Cilium の Gateway API サポートで Service を公開する
GatewayClass、Gateway、HTTPRoute:ホストベースのルーティング、パスマッチング、URL リライト、TLS。専用のゲートウェイ Pod は不要です。
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 つの要素を一貫して設定する必要があります。
- Gateway の HTTPS リスナー(上記)が TLS Secret を参照し、
mode: Terminateを設定します。 - 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 にならない一般的な原因です。
人気のガイド
-
Cilium が eBPF をどう使うか:アイデンティティ、ポリシー、ソケット Pod の起動、Pod 間の通信、パケットのポリシー判定のときにカーネル内で実際に何が起きているか、そしてなぜ高速なのか。 -
Cilium 用にクラスターを準備する:まずデフォルトの CNI を無効にする Cilium はクラスターのネットワーキングを完全に置き換えるため、ほとんどのアドオンよりも作業の順序が重要になります。 -
ネットワークポリシーを書く:L3/L4 から L7 ルールまで Kubernetes はすべての Pod が他のすべての Pod に到達できる状態から始まります。CiliumNetworkPolicy はそれを絞り込む手段で、必要なら HTTP メソッドまで制限できます。