Kubernetes Gateway API 新一代 Ingress

Kubernetes Gateway API Next Generation Ingress Controller

前言

隨著 Kubernetes 生態系統的不斷演進,傳統的 Ingress API 已逐漸無法滿足現代雲原生應用的複雜需求。Kubernetes Gateway API 作為新一代的流量管理標準,提供了更強大、更靈活且更具表達力的路由能力。本文將深入介紹 Gateway API 的設計理念、核心概念,以及如何在實際環境中部署和使用。

Gateway API 概述與設計理念

什麼是 Gateway API?

Gateway API 是 Kubernetes SIG-Network 社群開發的新一代流量管理 API,旨在取代並超越傳統的 Ingress API。它於 2023 年 10 月正式成為 GA(General Availability)穩定版本,標誌著 Kubernetes 網路層的重大進步。

設計理念

Gateway API 的設計遵循以下核心原則:

  1. 角色導向(Role-Oriented):明確區分基礎設施管理員、叢集操作員和應用開發者的職責
  2. 可移植性(Portable):提供跨不同實作的標準化介面
  3. 表達力(Expressive):支援更豐富的路由規則和流量管理功能
  4. 可擴展性(Extensible):透過 Policy Attachment 機制支援自訂擴展

角色分離模型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
┌─────────────────────────────────────────────────────────────────┐
│                    基礎設施提供者                                 │
│                   (Infrastructure Provider)                      │
│                         ↓                                        │
│                   GatewayClass                                   │
│                   (定義 Gateway 實作類型)                         │
├─────────────────────────────────────────────────────────────────┤
│                    叢集操作員                                     │
│                   (Cluster Operator)                             │
│                         ↓                                        │
│                     Gateway                                      │
│                   (定義監聽器和入口點)                            │
├─────────────────────────────────────────────────────────────────┤
│                    應用開發者                                     │
│                   (Application Developer)                        │
│                         ↓                                        │
│              HTTPRoute / TCPRoute / GRPCRoute                   │
│                   (定義路由規則)                                  │
└─────────────────────────────────────────────────────────────────┘

Gateway API vs Ingress 比較

功能對比

功能IngressGateway API
角色分離支援
跨命名空間路由有限完整支援
Header 匹配Annotation原生支援
流量分流Annotation原生支援
請求/回應修改Annotation原生支援
TCP/UDP 路由不支援支援
gRPC 路由不支援原生支援
可移植性低(依賴 Annotation)高(標準化 API)

Ingress 的限制

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 傳統 Ingress 需要依賴 Annotation 實現進階功能
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: legacy-ingress
  annotations:
    # 不同 Controller 有不同的 Annotation
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "20"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /api(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-service
            port:
              number: 80

Gateway API 的優勢

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Gateway API 提供標準化的原生功能
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: modern-route
spec:
  parentRefs:
  - name: my-gateway
  hostnames:
  - "example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api
    backendRefs:
    - name: api-v1
      port: 80
      weight: 80
    - name: api-v2
      port: 80
      weight: 20

核心資源類型

GatewayClass

GatewayClass 定義了 Gateway 的實作類型,類似於 StorageClass 之於 PersistentVolume。它由基礎設施提供者建立和管理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: istio-gateway
spec:
  controllerName: istio.io/gateway-controller
  description: "Istio Gateway Controller"
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: envoy-gateway
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
  description: "Envoy Gateway Controller"
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx-gateway
spec:
  controllerName: gateway.nginx.org/nginx-gateway-controller
  description: "NGINX Gateway Fabric Controller"

Gateway

Gateway 代表一個負載平衡器實例,定義了監聽器(Listener)和入口點。它由叢集操作員建立和管理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production-gateway
  namespace: gateway-system
spec:
  gatewayClassName: istio-gateway
  listeners:
  # HTTP 監聽器
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
  # HTTPS 監聽器
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: production-cert
        kind: Secret
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            gateway-access: "true"
  # 特定主機的監聽器
  - name: api-https
    protocol: HTTPS
    port: 443
    hostname: "api.example.com"
    tls:
      mode: Terminate
      certificateRefs:
      - name: api-cert
    allowedRoutes:
      namespaces:
        from: Same

HTTPRoute

HTTPRoute 定義了 HTTP/HTTPS 流量的路由規則,由應用開發者建立和管理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-routes
  namespace: production
spec:
  parentRefs:
  - name: production-gateway
    namespace: gateway-system
  hostnames:
  - "app.example.com"
  - "www.example.com"
  rules:
  # API 路由
  - matches:
    - path:
        type: PathPrefix
        value: /api/v1
    backendRefs:
    - name: api-v1-service
      port: 8080
  # 前端路由
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: frontend-service
      port: 3000

其他路由類型

Gateway API 還支援其他協定的路由:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# TCPRoute - TCP 流量路由
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
  name: database-route
spec:
  parentRefs:
  - name: tcp-gateway
    sectionName: mysql
  rules:
  - backendRefs:
    - name: mysql-service
      port: 3306
---
# GRPCRoute - gRPC 流量路由
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: grpc-route
spec:
  parentRefs:
  - name: grpc-gateway
  hostnames:
  - "grpc.example.com"
  rules:
  - matches:
    - method:
        service: myapp.UserService
        method: GetUser
    backendRefs:
    - name: user-service
      port: 50051

Gateway API 安裝與設定

安裝 Gateway API CRDs

首先需要安裝 Gateway API 的 Custom Resource Definitions:

1
2
3
4
5
# 安裝標準通道(穩定版功能)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml

# 或安裝實驗性通道(包含實驗性功能)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml

驗證安裝

1
2
3
4
5
6
7
8
# 檢查 CRDs 是否安裝成功
kubectl get crd | grep gateway

# 預期輸出:
# gatewayclasses.gateway.networking.k8s.io
# gateways.gateway.networking.k8s.io
# httproutes.gateway.networking.k8s.io
# referencegrants.gateway.networking.k8s.io

安裝 Gateway Controller

以下介紹幾個常見的 Gateway Controller 安裝方式:

Istio Gateway

1
2
3
4
5
6
7
8
9
# 使用 istioctl 安裝
istioctl install --set profile=minimal

# 或使用 Helm
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo update

helm install istio-base istio/base -n istio-system --create-namespace
helm install istiod istio/istiod -n istio-system --wait

Envoy Gateway

1
2
3
4
5
6
7
8
# 使用 Helm 安裝 Envoy Gateway
helm install eg oci://docker.io/envoyproxy/gateway-helm \
  --version v1.2.0 \
  -n envoy-gateway-system \
  --create-namespace

# 驗證安裝
kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available

NGINX Gateway Fabric

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 使用 Helm 安裝
helm install ngf oci://ghcr.io/nginxinc/charts/nginx-gateway-fabric \
  --create-namespace \
  -n nginx-gateway

# 建立 GatewayClass
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx
spec:
  controllerName: gateway.nginx.org/nginx-gateway-controller
EOF

建立基本 Gateway

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 建立 Gateway 命名空間
kubectl create namespace gateway-system

# 建立 Gateway
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: main-gateway
  namespace: gateway-system
spec:
  gatewayClassName: istio  # 或 nginx, envoy 等
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
EOF

# 檢查 Gateway 狀態
kubectl get gateway -n gateway-system
kubectl describe gateway main-gateway -n gateway-system

HTTPRoute 路由設定

基本路由

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: basic-route
  namespace: default
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "myapp.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: myapp-service
      port: 80

路徑匹配類型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: path-matching-route
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  rules:
  # 精確匹配
  - matches:
    - path:
        type: Exact
        value: /api/health
    backendRefs:
    - name: health-service
      port: 8080
  # 前綴匹配
  - matches:
    - path:
        type: PathPrefix
        value: /api/v1
    backendRefs:
    - name: api-v1-service
      port: 8080
  # 正則表達式匹配(實驗性功能)
  - matches:
    - path:
        type: RegularExpression
        value: "/users/[0-9]+"
    backendRefs:
    - name: user-service
      port: 8080

Header 匹配

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: header-matching-route
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "api.example.com"
  rules:
  # 根據 Header 路由到不同版本
  - matches:
    - headers:
      - name: X-API-Version
        value: v2
    backendRefs:
    - name: api-v2-service
      port: 8080
  # 預設路由
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: api-v1-service
      port: 8080

Query Parameter 匹配

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: query-matching-route
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  rules:
  - matches:
    - queryParams:
      - name: version
        value: beta
    backendRefs:
    - name: beta-service
      port: 8080
  - backendRefs:
    - name: stable-service
      port: 8080

Method 匹配

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: method-matching-route
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "api.example.com"
  rules:
  # 只允許 GET 和 POST
  - matches:
    - method: GET
      path:
        type: PathPrefix
        value: /api/resources
    - method: POST
      path:
        type: PathPrefix
        value: /api/resources
    backendRefs:
    - name: api-service
      port: 8080

請求修改(Request Modification)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: request-modification-route
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api
    filters:
    # 新增 Header
    - type: RequestHeaderModifier
      requestHeaderModifier:
        add:
        - name: X-Custom-Header
          value: "custom-value"
        - name: X-Request-ID
          value: "generated-id"
        set:
        - name: Host
          value: "backend.internal"
        remove:
        - X-Deprecated-Header
    # URL 重寫
    - type: URLRewrite
      urlRewrite:
        path:
          type: ReplacePrefixMatch
          replacePrefixMatch: /v1
    backendRefs:
    - name: api-service
      port: 8080

回應修改(Response Modification)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: response-modification-route
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    filters:
    - type: ResponseHeaderModifier
      responseHeaderModifier:
        add:
        - name: X-Frame-Options
          value: "DENY"
        - name: X-Content-Type-Options
          value: "nosniff"
        - name: Strict-Transport-Security
          value: "max-age=31536000; includeSubDomains"
    backendRefs:
    - name: web-service
      port: 80

重導向(Redirect)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: redirect-route
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "old.example.com"
  rules:
  # HTTP 重導向到 HTTPS
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301
  # 路徑重導向
  - matches:
    - path:
        type: Exact
        value: /old-page
    filters:
    - type: RequestRedirect
      requestRedirect:
        path:
          type: ReplaceFullPath
          replaceFullPath: /new-page
        statusCode: 301

TLS 終止與設定

建立 TLS Secret

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 使用現有憑證建立 Secret
kubectl create secret tls production-cert \
  --cert=./tls.crt \
  --key=./tls.key \
  -n gateway-system

# 或使用 YAML
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: production-cert
  namespace: gateway-system
type: kubernetes.io/tls
data:
  tls.crt: $(cat tls.crt | base64 -w0)
  tls.key: $(cat tls.key | base64 -w0)
EOF

Gateway TLS 設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: secure-gateway
  namespace: gateway-system
spec:
  gatewayClassName: istio
  listeners:
  # HTTP 監聽器(用於重導向到 HTTPS)
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
  # HTTPS 監聽器
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: production-cert
        kind: Secret
    allowedRoutes:
      namespaces:
        from: All
  # 特定域名的 HTTPS 監聽器
  - name: api-https
    protocol: HTTPS
    port: 443
    hostname: "api.example.com"
    tls:
      mode: Terminate
      certificateRefs:
      - name: api-cert
        kind: Secret
    allowedRoutes:
      namespaces:
        from: Same

TLS Passthrough

對於需要端到端加密的場景,可以使用 TLS Passthrough:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: passthrough-gateway
  namespace: gateway-system
spec:
  gatewayClassName: istio
  listeners:
  - name: tls-passthrough
    protocol: TLS
    port: 443
    hostname: "secure.example.com"
    tls:
      mode: Passthrough
    allowedRoutes:
      namespaces:
        from: All
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
  name: passthrough-route
spec:
  parentRefs:
  - name: passthrough-gateway
    namespace: gateway-system
  hostnames:
  - "secure.example.com"
  rules:
  - backendRefs:
    - name: secure-backend
      port: 443

使用 cert-manager 自動管理憑證

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 安裝 cert-manager
# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml

# 建立 ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
    - http01:
        gatewayHTTPRoute:
          parentRefs:
          - name: main-gateway
            namespace: gateway-system
---
# 建立 Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: app-certificate
  namespace: gateway-system
spec:
  secretName: app-tls-cert
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - "app.example.com"
  - "www.example.com"
---
# 在 Gateway 中使用憑證
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: auto-tls-gateway
  namespace: gateway-system
spec:
  gatewayClassName: istio
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: app-tls-cert
    allowedRoutes:
      namespaces:
        from: All

HTTP 到 HTTPS 重導向

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: https-redirect
  namespace: gateway-system
spec:
  parentRefs:
  - name: secure-gateway
    sectionName: http  # 指定 HTTP 監聽器
  hostnames:
  - "app.example.com"
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301

流量分流與金絲雀部署

基於權重的流量分流

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: canary-route
  namespace: production
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    # 80% 流量到穩定版本
    - name: app-stable
      port: 8080
      weight: 80
    # 20% 流量到金絲雀版本
    - name: app-canary
      port: 8080
      weight: 20

基於 Header 的金絲雀部署

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: header-based-canary
  namespace: production
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "app.example.com"
  rules:
  # 內部測試人員使用金絲雀版本
  - matches:
    - headers:
      - name: X-Canary
        value: "true"
    backendRefs:
    - name: app-canary
      port: 8080
  # Beta 用戶使用金絲雀版本
  - matches:
    - headers:
      - name: X-User-Group
        value: "beta"
    backendRefs:
    - name: app-canary
      port: 8080
  # 其他流量到穩定版本
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: app-stable
      port: 8080

藍綠部署

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 藍色環境(目前生產環境)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: blue-green-route
  namespace: production
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    # 切換時修改權重
    - name: app-blue
      port: 8080
      weight: 100
    - name: app-green
      port: 8080
      weight: 0

漸進式發布腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
# canary-rollout.sh - 漸進式金絲雀發布腳本

NAMESPACE="production"
ROUTE_NAME="canary-route"
STABLE_SERVICE="app-stable"
CANARY_SERVICE="app-canary"

# 逐步增加金絲雀流量
for weight in 10 25 50 75 100; do
  stable_weight=$((100 - weight))

  echo "Setting canary weight to ${weight}%..."

  kubectl patch httproute ${ROUTE_NAME} -n ${NAMESPACE} --type=json -p="[
    {\"op\": \"replace\", \"path\": \"/spec/rules/0/backendRefs/0/weight\", \"value\": ${stable_weight}},
    {\"op\": \"replace\", \"path\": \"/spec/rules/0/backendRefs/1/weight\", \"value\": ${weight}}
  ]"

  echo "Waiting 5 minutes for monitoring..."
  sleep 300

  # 這裡可以加入健康檢查邏輯
  # 如果失敗,回滾到 100% stable
done

echo "Canary rollout completed!"

A/B 測試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: ab-testing-route
  namespace: production
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "app.example.com"
  rules:
  # A 版本:新結帳流程
  - matches:
    - headers:
      - name: Cookie
        type: RegularExpression
        value: ".*ab_test=checkout_v2.*"
      path:
        type: PathPrefix
        value: /checkout
    backendRefs:
    - name: checkout-v2
      port: 8080
  # B 版本:原始結帳流程
  - matches:
    - path:
        type: PathPrefix
        value: /checkout
    backendRefs:
    - name: checkout-v1
      port: 8080

與服務網格整合

Istio 整合

Gateway API 與 Istio 的整合非常緊密。Istio 從 1.15 版本開始完整支援 Gateway API。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 使用 Istio 作為 Gateway Controller
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: istio
spec:
  controllerName: istio.io/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: istio-gateway
  namespace: istio-system
spec:
  gatewayClassName: istio
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
---
# HTTPRoute 搭配 Istio 服務網格功能
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: mesh-route
  namespace: production
spec:
  parentRefs:
  - name: istio-gateway
    namespace: istio-system
  hostnames:
  - "app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: frontend
      port: 80

搭配 Istio 的流量管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 結合 Gateway API 和 Istio VirtualService
# 用於更複雜的流量管理場景

# Gateway API 負責入口流量
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: entry-route
  namespace: production
spec:
  parentRefs:
  - name: istio-gateway
    namespace: istio-system
  hostnames:
  - "app.example.com"
  rules:
  - backendRefs:
    - name: frontend
      port: 80
---
# Istio DestinationRule 負責細粒度流量控制
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: frontend-dr
  namespace: production
spec:
  host: frontend
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        h2UpgradePolicy: UPGRADE
        http1MaxPendingRequests: 100
    loadBalancer:
      simple: LEAST_REQUEST
    outlierDetection:
      consecutive5xxErrors: 5
      interval: 30s
      baseEjectionTime: 30s

Linkerd 整合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Linkerd 也支援 Gateway API
apiVersion: gateway.networking.k8s.io/v1beta1
kind: GatewayClass
metadata:
  name: linkerd
spec:
  controllerName: linkerd.io/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: linkerd-gateway
  namespace: linkerd
  annotations:
    linkerd.io/inject: enabled
spec:
  gatewayClassName: linkerd
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All

跨服務網格的流量管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 使用 ReferenceGrant 允許跨命名空間引用
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-gateway-to-backend
  namespace: backend-system
spec:
  from:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespace: frontend-system
  to:
  - group: ""
    kind: Service
---
# 跨命名空間的路由
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: cross-namespace-route
  namespace: frontend-system
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api
    backendRefs:
    - name: api-service
      namespace: backend-system  # 跨命名空間引用
      port: 8080

最佳實務

1. 命名空間隔離策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 為不同環境建立獨立的 Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production-gateway
  namespace: gateway-production
spec:
  gatewayClassName: istio
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: prod-cert
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            environment: production
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: staging-gateway
  namespace: gateway-staging
spec:
  gatewayClassName: istio
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: staging-cert
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            environment: staging

2. 使用 ReferenceGrant 控制存取

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 明確授權跨命名空間存取
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-routes-from-apps
  namespace: gateway-system
spec:
  from:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespace: app-team-a
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespace: app-team-b
  to:
  - group: ""
    kind: Secret
    name: shared-tls-cert

3. 實作健康檢查路由

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: health-routes
  namespace: production
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  rules:
  # 健康檢查端點不需要認證
  - matches:
    - path:
        type: Exact
        value: /health
    - path:
        type: Exact
        value: /ready
    backendRefs:
    - name: health-service
      port: 8080

4. 設定適當的超時和重試

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 使用 BackendLBPolicy(實驗性功能)
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: BackendLBPolicy
metadata:
  name: api-backend-policy
  namespace: production
spec:
  targetRef:
    group: ""
    kind: Service
    name: api-service
  sessionPersistence:
    sessionName: session-cookie
    type: Cookie
---
# 或使用特定 Controller 的 Policy
# 以 Istio 為例
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: api-timeout
  namespace: production
spec:
  hosts:
  - api-service
  http:
  - timeout: 30s
    retries:
      attempts: 3
      perTryTimeout: 10s
      retryOn: connect-failure,refused-stream,503
    route:
    - destination:
        host: api-service

5. 監控與可觀測性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 檢查 Gateway 狀態
kubectl get gateway -A -o wide

# 檢查 HTTPRoute 狀態
kubectl get httproute -A

# 查看詳細狀態
kubectl describe gateway main-gateway -n gateway-system

# 檢查路由是否正確綁定
kubectl get httproute my-route -o jsonpath='{.status.parents}'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 設定 Prometheus 監控
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: gateway-metrics
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: istio-ingressgateway
  endpoints:
  - port: http-monitoring
    path: /stats/prometheus

6. GitOps 最佳實務

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 使用 Kustomize 管理不同環境的設定
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- gateway.yaml
- routes/

patches:
- path: patches/gateway-patch.yaml
  target:
    kind: Gateway
    name: main-gateway

configMapGenerator:
- name: gateway-config
  literals:
  - ENVIRONMENT=production

7. 安全性建議

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 實作 CORS 和安全 Header
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: secure-route
  namespace: production
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    filters:
    - type: ResponseHeaderModifier
      responseHeaderModifier:
        add:
        - name: X-Frame-Options
          value: "DENY"
        - name: X-Content-Type-Options
          value: "nosniff"
        - name: X-XSS-Protection
          value: "1; mode=block"
        - name: Referrer-Policy
          value: "strict-origin-when-cross-origin"
        - name: Content-Security-Policy
          value: "default-src 'self'"
    backendRefs:
    - name: web-service
      port: 80

8. 版本遷移策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 從 Ingress 遷移到 Gateway API 的過渡期設定
# 同時維護兩種路由,逐步切換流量

# 保留原有 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: legacy-ingress
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "50"  # 逐步減少
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80
---
# 新的 Gateway API 路由
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: new-route
spec:
  parentRefs:
  - name: main-gateway
    namespace: gateway-system
  hostnames:
  - "app.example.com"
  rules:
  - backendRefs:
    - name: app-service
      port: 80

故障排除

常見問題診斷

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 檢查 GatewayClass 是否被接受
kubectl get gatewayclass
kubectl describe gatewayclass <name>

# 檢查 Gateway 狀態
kubectl get gateway -n gateway-system
kubectl describe gateway <name> -n gateway-system

# 檢查 HTTPRoute 是否正確綁定到 Gateway
kubectl get httproute -A
kubectl describe httproute <name> -n <namespace>

# 查看 Gateway Controller 日誌
kubectl logs -n istio-system -l app=istiod
kubectl logs -n envoy-gateway-system -l app=envoy-gateway

# 檢查 Gateway Pod 狀態
kubectl get pods -n gateway-system
kubectl describe pod <gateway-pod> -n gateway-system

常見錯誤及解決方案

錯誤可能原因解決方案
Gateway 不被接受GatewayClass 不存在確認 Controller 已安裝並建立 GatewayClass
HTTPRoute 未綁定parentRef 設定錯誤檢查 Gateway 名稱和命名空間是否正確
跨命名空間路由失敗缺少 ReferenceGrant建立適當的 ReferenceGrant 資源
TLS 憑證錯誤Secret 不存在或格式錯誤確認 Secret 存在且為 kubernetes.io/tls 類型
503 錯誤後端服務不可用檢查 Service 和 Pod 狀態

總結

Kubernetes Gateway API 代表了 Kubernetes 網路層的重大進步。相比傳統的 Ingress API,它提供了:

  1. 更清晰的角色分離:基礎設施管理員、叢集操作員和應用開發者各司其職
  2. 更強大的表達能力:原生支援 Header 匹配、流量分流、請求修改等進階功能
  3. 更好的可移植性:標準化的 API 減少了對特定 Controller 的依賴
  4. 更靈活的擴展機制:透過 Policy Attachment 支援自訂擴展

隨著 Gateway API 正式成為 GA 版本,越來越多的 Gateway Controller 實作開始支援這個新標準。建議在新專案中優先考慮使用 Gateway API,並逐步將現有的 Ingress 遷移到 Gateway API。

參考資源

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy