Gateway、HTTPRoute、および TLS リソースを構成して、Application Load Balancer (ALB) インスタンス経由で外部トラフィックを Container Service for Kubernetes (ACK) サービスにルーティングします。
リソースモデル
Gateway API では、3 つのリソースタイプが定義されており、それぞれに異なる役割が割り当てられています。
| リソース | 所有者 | 目的 |
|---|---|---|
| [GatewayClass] | インフラストラクチャプロバイダー (Alibaba Cloud) | コントローラー (ここでは ALB Ingress コントローラー) がサポートする GatewayClass を定義します。 |
| Gateway | クラスターオペレーター | ALB インスタンスをプロビジョニングし、リスナー (ポート、プロトコル、ホスト名) を構成します。 |
| HTTPRoute | アプリケーション開発者 | 受信リクエストをバックエンド Service にマッピングするルーティングルールを定義します。 |
プラットフォームチームがインフラストラクチャを管理し、アプリケーションチームがルーティングルールを独立して管理します。
ALB Ingress コントローラーは、バージョン 2.17.0 以降で Gateway API をサポートしています。
前提条件
次の条件を満たしていることを確認してください。
-
Kubernetes 1.24 以降を実行するACK マネージドクラスター
-
クラスターにALB Ingress コントローラーバージョン 2.17.0 以降がインストールされていること
-
クラスターにGateway API バージョン 1.1.0 以降がインストールされていること
-
クラスターがデプロイされている VPC 内に、ALB をサポートする 2 つの vSwitch があること
環境の検証
ALB Ingress コントローラーは、alb という名前の GatewayClass リソースを自動的に作成します。作業を続ける前に、このリソースが存在することを確認してください。
kubectl
GatewayClass を確認します。
kubectl get gatewayclass
出力例:
NAME CONTROLLER ACCEPTED AGE
alb gateways.alibabacloud.com/alb/v1 True 1m
ACCEPTED: True は、GatewayClass が準備完了であることを示します。
サンプルアプリケーションのデプロイ
httpbin.yaml ファイルを作成します。
Service はデフォルトでClusterIPを使用します。クラスターが Flannel ネットワークプラグインを使用している場合は、spec.typeをNodePortに変更してください。
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-httpbin
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: go-httpbin
template:
metadata:
labels:
app: go-httpbin
version: v1
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/mse/go-httpbin
args:
- "--port=8090"
- "--version=v1"
imagePullPolicy: Always
name: go-httpbin
ports:
- containerPort: 8090
---
apiVersion: v1
kind: Service
metadata:
name: go-httpbin
namespace: default
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8090
protocol: TCP
selector:
app: go-httpbin
マニフェストを適用します。
kubectl apply -f httpbin.yaml
Gateway とルーティングルールのデプロイ
Gateway を作成すると ALB インスタンスがプロビジョニングされ、料金が発生します。Gateway が作成した ALB インスタンスは、クラスターを削除しても自動的には削除されません。意図しない料金の発生を避けるため、クラスターを削除する前に Gateway リソースを削除してください。
ステップ1:Gateway と HTTPRoute を作成する
gateway.yaml ファイルを作成します。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: alb
namespace: default
spec:
gatewayClassName: alb
listeners:
- name: http
protocol: HTTP
port: 80
hostname: "*.ingress.top"
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: demo-route
spec:
parentRefs: # このルートを上記の Gateway にアタッチします
- group: gateway.networking.k8s.io
kind: Gateway
name: alb
hostnames:
- demo.ingress.top
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs: # 一致したトラフィックをポート 80 の go-httpbin に転送します
- kind: Service
name: go-httpbin
port: 80
Gateway は、*.ingress.top 用にポート 80 で HTTP リスナーを設定した ALB インスタンスをプロビジョニングします。HTTPRoute は、demo.ingress.top のトラフィックを go-httpbin Service に転送します。
マニフェストを適用します。
kubectl apply -f gateway.yaml
ステップ2:Gateway が準備完了になるまで待機する
kubectl wait --for=condition=programmed gateway/alb --timeout=120s
Gateway のアドレスを確認します。
kubectl get gateway alb
出力例:
NAME CLASS ADDRESS PROGRAMMED AGE
alb alb alb-0mwhq4ck6xxxxxxxxx.cn-hangzhou.alb.aliyuncsslb.com True 2m12s
ステップ3:HTTPRoute のステータスを確認する
kubectl describe httproute demo-route | grep Status -A 20
出力例:
Status:
Parents:
Conditions:
Last Transition Time: 2024-05-23T08:21:25Z
Message: Route is accepted.
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2024-05-23T08:21:25Z
Message: Route is resolved.
Observed Generation: 1
Reason: ResolvedRefs
Status: True
Type: ResolvedRefs
Controller Name: gateways.alibabacloud.com/alb/v1
Parent Ref:
Group: gateway.networking.k8s.io
Kind: Gateway
Name: alb
Accepted: True と ResolvedRefs: True は、ルートがアクティブであることを示します。
ステップ4:アクセスをテストする
Gateway のアドレスを取得し、テストリクエストを送信します。
export ALB_DOMAIN=$(kubectl get gateway alb -n default -o jsonpath='{.status.addresses[?(@.type=="Hostname")].value}')
curl -H "Host: demo.ingress.top" http://${ALB_DOMAIN}/version
出力例:
version: v1
hostname: go-httpbin-547xxxxxf6-xxxxx
ユースケース
フィルターを使用したリクエストヘッダーの変更
HTTPRoute フィルターを使用すると、転送中のリクエストまたはレスポンスを書き換えることができます。この例では、カスタムリクエストヘッダーを追加します。
httproute-filter.yaml ファイルを作成します。
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: demo-filter
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: alb
hostnames:
- filter.ingress.top
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: my-header
value: foo
backendRefs:
- kind: Service
name: go-httpbin
port: 80
RequestHeaderModifier フィルターは、リクエストがバックエンドに到達する前にリクエストを変更します。
-
一致するリクエストに
my-header: fooを追加します。 -
addアクションは、同じ名前の既存のヘッダーを置き換えるのではなく、ヘッダーを追加します。
ルーティングルールを適用します。
kubectl apply -f httproute-filter.yaml
リクエストヘッダーを返す /header エンドポイントでテストします。
curl -H "Host: filter.ingress.top" http://${ALB_DOMAIN}/header
出力例:
headers: {
"Accept": [
"*/*"
],
"Connection": [
"close"
],
"Host": [
"filter.ingress.top"
],
"My-Header": [
"foo"
],
"Path": [
"/header"
],
"Protocol": [
"HTTP/1.1"
],
"Remoteip": [
"118.xx.xx.91"
],
"URL": [
"/header"
],
"User-Agent": [
"curl/8.9.1"
]
}
query param:
, hostname: go-httpbin-547xxxxxf6-xxxxx
出力に My-Header: foo が含まれていることで、フィルターが機能していることを確認できます。
重みによるトラフィックの分割
複数のバックエンド Service に重みを割り当てて、カナリアデプロイメントなどのためにトラフィックを比例的に分散させます。
2 つの NGINX Deployment を含む nginx.yaml ファイルを作成します。
old-nginx は old を返し、new-nginx は new を返します。両方とも default 名前空間にデプロイされます。
httproute-weight.yaml ファイルを作成します。
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: demo-weight
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: alb
hostnames:
- weight.ingress.top
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
# 重みはパーセンテージではなく相対値のため、合計が 100 になる必要はありません。
- kind: Service
name: old-nginx
port: 80
weight: 100
- kind: Service
name: new-nginx
port: 80
weight: 100
両方のバックエンドの重みが等しい (100:100) ため、トラフィックは 1:1 で分割されます。
マニフェストを適用します。
kubectl apply -f nginx.yaml
kubectl apply -f httproute-weight.yaml
10 件のリクエストを送信して分散を確認します。
for i in {1..10}; do curl -H "Host: weight.ingress.top" http://${ALB_DOMAIN}/; done
出力例:
old
new
new
old
new
old
old
new
new
old
トラフィックは 2 つのバックエンド間でほぼ 1:1 に分割されます。
TLS 証明書の構成
TLS 証明書を含む Kubernetes Secret を参照して、Gateway に HTTPS 終端を追加します。
ステップ1:自己署名証明書を作成する
openssl req -subj '/CN=ingress.top' -new -newkey rsa:2048 -sha256 \
-days 365 -nodes -x509 -keyout server.key -out server.crt \
-addext "subjectAltName = DNS:ingress.top" \
-addext "keyUsage = digitalSignature" \
-addext "extendedKeyUsage = serverAuth" 2> /dev/null; \
openssl x509 -in server.crt -subject -noout
ステップ2:TLS Secret を作成する
kubectl create secret tls ingress.top --key server.key --cert server.crt
ステップ3:Gateway を更新して HTTPS リスナーを追加する
gateway-tls.yaml ファイルを作成します。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: alb
namespace: default
spec:
gatewayClassName: alb
listeners:
- name: http
protocol: HTTP
port: 80
hostname: "*.ingress.top"
allowedRoutes:
namespaces:
from: Same
- name: https
protocol: HTTPS
port: 443
hostname: "*.ingress.top"
allowedRoutes:
namespaces:
from: Same
tls:
mode: Terminate # ALB が TLS を終端し、平文の HTTP をバックエンドに転送します
certificateRefs:
- kind: Secret
name: ingress.top # 前のステップで作成した Secret
Terminate モードでは、ALB が HTTPS トラフィックを復号化し、平文の HTTP をバックエンドに転送します。certificateRefs フィールドは、証明書とプライベートキーが格納された Secret を参照します。
更新を適用します。
kubectl apply -f gateway-tls.yaml
ステップ4:証明書を検証する
Gateway の PROGRAMMED ステータスが True に戻るまで待機します。
kubectl wait --for=condition=programmed gateway/alb --timeout=120s
証明書を検証します。
openssl s_client -servername ingress.top -connect ${ALB_DOMAIN}:443
出力例:
CONNECTED(00000003)
depth=0 CN = ingress.top
verify error:num=18:self-signed certificate
verify return:1
depth=0 CN = ingress.top
verify return:1
---
Certificate chain
0 s:CN = ingress.top
i:CN = ingress.top
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Jun 24 10:49:39 2024 GMT; NotAfter: Jun 24 10:49:39 2025 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=CN = ingress.top
issuer=CN = ingress.top
---
...
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
...
Verify return code: 18 (self-signed certificate)
CN = ingress.top と TLSv1.2 暗号は、TLS 終端が機能していることを示します。self-signed certificate エラーは想定内の動作です。本番環境では CA 署名証明書を使用してください。
自己署名証明書の検証をスキップする -k フラグを使用して、HTTPS アクセスをテストします。
curl -H "Host: demo.ingress.top" -k https://${ALB_DOMAIN}/version
出力例:
version: v1
hostname: go-httpbin-547xxxxxf6-xxxxx
次のステップ
-
Gateway API:ヘッダーベースのマッチングやトラフィックミラーリングなどの高度なルーティングを含む完全な仕様。
-
ALB Ingress コントローラー:本番ワークロード向けの ALB 固有のアノテーションと構成。