iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
Kubernetes

從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作系列 第 26

Day 26|Gateway API — Kubernetes 的下一代流量入口管理

  • 分享至 

  • xImage
  •  

前言

Day6 中,我們學會了用 Ingress 統一管理微服務的入口流量,透過 Path 與 Host 將請求導向不同的 Service。

但隨著流量管理需求越來越複雜,Ingress 的一些限制也逐漸浮現:

大量依賴 annotations、不同 Controller 的設定方式不一致、進階路由缺乏統一標準、角色與權限不容易拆分……

雖然不同 Ingress Controller 可以透過 annotations 或自訂功能實現 Header Routing、權重分流等能力,但寫法往往各不相同。

為了解決這些問題,Kubernetes 社群推出了 Gateway API —— 一套更具擴充性與角色分工能力的流量管理 API,也被視為 Ingress 的下一代方案。

今天內容包含:

  1. 為什麼需要 Gateway API?
  2. Gateway API 核心資源
  3. 安裝 Gateway API CRD 與 Controller
  4. 實戰:部署 Gateway 並設定 HTTPRoute
  5. 進階路由功能 —— Header Routing、權重分流
  6. Gateway API vs Ingress

以下操作皆在 master 節點執行。


一、為什麼需要 Gateway API?

Ingress 的痛點

回顧 Day6,Ingress 可以處理基本的 Host 與 Path Routing,但當需求變複雜後,就會遇到一些限制:

問題 說明
高度依賴 Annotations Rewrite、限流、CORS 等進階功能常需要 Controller 自訂 Annotations,不同 Controller 的寫法可能不同
角色職責不容易拆分 基礎設施入口與應用路由通常集中在 Ingress Resource 中,平台團隊與應用團隊較難分工管理
進階路由缺乏統一標準 Header Matching、權重分流等功能,過去常依賴不同 Controller 的自訂能力
跨 Namespace 管理較受限 Ingress Backend 通常位於同一個 Namespace,跨 Namespace 能力往往依賴 Controller 額外實作
不同實作存在差異 雖然 Ingress API 相同,但部分進階功能與行為仍可能因 Controller 而不同

Gateway API 的設計,就是希望把這些需求變成更標準化、可擴充的 Kubernetes API。

Gateway API 的設計理念

Gateway API 很重要的一個設計概念就是 角色分離(Role-Oriented Design)

不同角色負責不同層級的資源,讓基礎設施與應用路由可以分開管理。

https://ithelp.ithome.com.tw/upload/images/20260821/20181928d6wZQN5DT4.png

角色 負責的資源 職責
基礎設施供應者 GatewayClass 定義 Gateway 類型,並指定由哪個 Gateway Controller 管理
叢集管理員 Gateway 建立實際的流量入口,設定 Listener、Port、Protocol、TLS,以及允許哪些 Route 掛載
應用開發者 HTTPRoute 定義應用程式的 Host、Path、Header 與 Backend 等路由規則

💡 Ingress vs Gateway API 的本質差異

Ingress 通常把入口與路由設定集中在同一種 Resource 中。

Gateway API 則把 基礎設施入口(Gateway)應用路由(Route) 拆開,讓不同角色可以各自管理自己負責的部分。

這種設計在多人團隊與多租戶環境中特別有用。


二、Gateway API 核心資源

三層架構

Gateway API 的核心架構可以先理解成:

https://ithelp.ithome.com.tw/upload/images/20260821/20181928uOcsUWMFJW.png

其中 HTTPRoute 透過 parentRefs 附加到 Gateway,再依照 Host、Path、Header 等規則,將符合條件的流量轉送到對應的 Backend(通常是 Service)。

資源 作用 對比 Ingress
GatewayClass 定義 Gateway 類型,並指定由哪個 Controller 管理 類似 IngressClass
Gateway 定義 Listener、Port、Protocol、TLS 等入口設定 Ingress 沒有完全對應的獨立資源
HTTPRoute 定義 Host、Path、Header 等路由規則,並指定 Backend 類似 Ingress 的 rules,但能力更完整

除了 HTTPRoute 還有其他 Route 類型

Route 類型 用途 狀態
HTTPRoute HTTP / HTTPS 路由 GA
GRPCRoute gRPC 路由 GA
TLSRoute 基於 SNI 等 TLS 資訊進行路由 GA
TCPRoute TCP 流量路由 🧪 Experimental
UDPRoute UDP 流量路由 🧪 Experimental

💡 Gateway API 的穩定度

GatewayClassGatewayHTTPRouteGRPCRouteTLSRoute 都已進入 Standard Channel。

TCPRouteUDPRoute 目前仍屬 Experimental Channel。


三、安裝 Gateway API CRD 與 Controller

Gateway API 本身是透過 CRD(CustomResourceDefinition) 提供 API,再由對應的 Gateway Controller 實際處理這些資源。

安裝方式會依 Controller 而不同:

  • 有些 Controller 會自動安裝 Gateway API CRD
  • 有些則需要先自行安裝 CRD,再安裝 Controller

因此安裝前應先確認所使用 Controller 的官方文件。

⚠️ 注意 CRD 與 Controller 的版本相容性

Gateway Controller 必須支援叢集中安裝的 Gateway API CRD 版本。

如果 Controller 啟動時 CRD 尚未存在,可能暫時無法監看或處理 Gateway API 資源;CRD 安裝完成後,通常應再確認 Controller 是否正常 reconcile。

Step 1:安裝 Gateway API CRD

Gateway API 的 CRD 由 Kubernetes SIG Network 統一定義,提供 GatewayClassGatewayHTTPRoute 等標準 Resource。

本篇實作統一使用 Gateway API v1.2.1

kubectl apply --server-side -f \
  https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml

安裝完成後確認 CRD:

kubectl get crd | grep gateway

應該可以看到類似:

https://ithelp.ithome.com.tw/upload/images/20260821/20181928uvuaBgJxRk.png

💡 版本提醒

本篇截圖與實作皆以 Gateway API v1.2.1 為基準。

Gateway API 後續版本仍持續更新,實際使用時請再確認 Gateway Controller 支援的版本。

Step 2:選擇並安裝 Gateway Controller

Gateway API 只定義 API 規格,本身不會實際處理流量,因此還需要安裝對應的 Gateway Controller

常見實作包括:

Controller 底層技術 特色 適合環境
Envoy Gateway Envoy Proxy 專注於 Gateway API,安裝與使用方式相對直接 通用環境
Cilium eBPF + Envoy 同時提供 CNI、網路安全與 Gateway API 已使用 Cilium 的叢集
NGINX Gateway Fabric NGINX NGINX 官方的 Gateway API 實作 熟悉 NGINX 的團隊
Istio Envoy 可與 Service Mesh 整合 已使用 Istio 的叢集

本篇使用 Envoy Gateway

為了和後續實作與截圖保持一致,本篇固定使用 Envoy Gateway v1.3.0

helm install eg oci://docker.io/envoyproxy/gateway-helm \
  --version v1.3.0 \
  -n envoy-gateway-system \
  --create-namespace

安裝完成後確認 Controller 是否正常:

kubectl get pods -n envoy-gateway-system

💡 版本提醒

本篇使用 Gateway API v1.2.1 與 Envoy Gateway v1.3.0 進行實作。

這些版本並非目前最新版本,實際部署時應確認 Gateway API 與 Controller 的版本相容性。

Step 3:建立 GatewayClass

安裝 Envoy Gateway Controller 後,還需要建立一個 GatewayClass,告訴 Kubernetes 這類 Gateway 要由哪個 Controller 管理。

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

建立 GatewayClass:

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
EOF

確認狀態:

kubectl get gatewayclass

正常情況下,可以看到:

https://ithelp.ithome.com.tw/upload/images/20260821/20181928XGfYxco4O1.png

⚠️ controllerName 必須對應到正確的 Controller

Envoy Gateway v1.3 預設使用:

gateway.envoyproxy.io/gatewayclass-controller

如果 controllerName 填錯,Envoy Gateway 就不會管理這個 GatewayClass,狀態也不會正常進入 Accepted=True

可以查看 Envoy Gateway 的設定確認實際使用的 Controller Name。


四、實戰:部署 Gateway 並設定 HTTPRoute

Step 1:建立測試應用

先建立兩個簡單的後端服務(延用 Day6 的概念):

vim gateway-test-apps.yaml
# App A
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-a
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-a
  template:
    metadata:
      labels:
        app: app-a
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          lifecycle:
            postStart:
              exec:
                command: ["/bin/sh", "-c", "echo 'Hello from App A (via Gateway API)' > /usr/share/nginx/html/index.html"]
---
apiVersion: v1
kind: Service
metadata:
  name: app-a
  namespace: default
spec:
  selector:
    app: app-a
  ports:
    - port: 80
---
# App B
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-b
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-b
  template:
    metadata:
      labels:
        app: app-b
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          lifecycle:
            postStart:
              exec:
                command: ["/bin/sh", "-c", "echo 'Hello from App B (via Gateway API)' > /usr/share/nginx/html/index.html"]
---
apiVersion: v1
kind: Service
metadata:
  name: app-b
  namespace: default
spec:
  selector:
    app: app-b
  ports:
    - port: 80
kubectl apply -f gateway-test-apps.yaml
# 確認 Pod 和 Service 都正常
kubectl get pods -l 'app in (app-a, app-b)'
kubectl get svc app-a app-b

https://ithelp.ithome.com.tw/upload/images/20260821/20181928HVTAPydSKv.png

Step 2:建立 Gateway

這是叢集管理員的工作 — 定義流量入口的監聽設定:

vim my-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
  namespace: default
spec:
  gatewayClassName: eg        # 使用 Envoy Gateway 提供的 GatewayClass
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: Same            # 只允許同 Namespace 的 Route 掛載
kubectl apply -f my-gateway.yaml
# 確認 Gateway 狀態
kubectl get gateway my-gateway

在沒有 LoadBalancer 實作的裸機環境中,可能會看到:

https://ithelp.ithome.com.tw/upload/images/20260821/20181928eufQ93XrvG.png

⚠️ 裸機環境可能出現 PROGRAMMED=False

Envoy Gateway 預設會建立 LoadBalancer 類型的 Envoy Proxy Service。

如果裸機叢集沒有 MetalLB 等 LoadBalancer 實作,就可能因為無法取得 Address,而讓 Gateway 顯示:

Programmed: False
Reason: AddressNotAssigned

可以使用:

kubectl describe gateway my-gateway

查看 AcceptedProgrammed、Listener 等 Condition,確認實際狀態。

如果需要在裸機環境取得 LoadBalancer IP,可以搭配 MetalLB;也可以依環境改用 NodePort 或 Port Forward 進行測試。

💡 Gateway 建立後發生了什麼?

Envoy Gateway 會根據 Gateway 設定建立 Envoy Proxy 的資料面資源,實際負責接收與轉送流量。

可以查看:

kubectl get pods -n envoy-gateway-system
kubectl get svc -n envoy-gateway-system

Step 3:建立 HTTPRoute(路徑分流)

這是應用開發者的工作 — 只需要關心路由規則:

vim my-httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-route
  namespace: default
spec:
  parentRefs:
    - name: my-gateway          # 掛載到哪個 Gateway
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /app-a
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /
      backendRefs:
        - name: app-a
          port: 80
    - matches:
        - path:
            type: PathPrefix
            value: /app-b
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /
      backendRefs:
        - name: app-b
          port: 80
kubectl apply -f my-httproute.yaml
# 確認 HTTPRoute 狀態
kubectl get httproute my-route

https://ithelp.ithome.com.tw/upload/images/20260821/20181928erpdFjXEWA.png

Step 4:測試路由

先取得 Gateway 的存取方式:

# 取得 Envoy Gateway 的 Service
kubectl get svc -n envoy-gateway-system

# 如果是 NodePort 類型,取得 NodePort
GATEWAY_PORT=$(kubectl get svc -n envoy-gateway-system \
  -l gateway.envoyproxy.io/owning-gateway-name=my-gateway \
  -o jsonpath='{.items[0].spec.ports[?(@.name=="http")].nodePort}')
echo "Gateway NodePort: ${GATEWAY_PORT}"

測試路由

先查看 Envoy Gateway 建立的 Service:

kubectl get svc -n envoy-gateway-system

在這個 Lab 環境中,可以直接使用 Envoy Proxy Service 的 ClusterIP 測試:

# App A
curl http://10.103.239.156/app-a
# → Hello from App A (via Gateway API)

# App B
curl http://10.103.239.156/app-b
# → Hello from App B (via Gateway API)

https://ithelp.ithome.com.tw/upload/images/20260821/20181928xikMuKSWjo.png

💡 跟 Ingress 比較一下

這裡的 Path Rewrite 不需要使用 Controller 專屬 Annotation,而是透過 Gateway API 標準定義的 URLRewrite Filter。

不過 URLRewrite 屬於 Extended Feature,實際使用前仍要確認 Gateway Controller 是否支援。


五、進階路由功能

Gateway API 原生支援許多 Ingress 做不到(或需要靠 annotation 才能做)的功能。

1. Header-based 路由

根據請求的 HTTP Header 來決定路由:

vim header-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: header-route
  namespace: default
spec:
  parentRefs:
    - name: my-gateway
  rules:
    - matches:
        - headers:
            - name: x-version
              value: v2
      backendRefs:
        - name: app-b          # Header 帶 x-version: v2 → 導到 app-b
          port: 80
    - backendRefs:
        - name: app-a          # 其他流量 → 導到 app-a(預設)
          port: 80
kubectl apply -f header-route.yaml
# 不帶 Header → app-a
curl http://<NODE_IP>:${GATEWAY_PORT}/
# → Hello from App A

# 帶 Header → app-b
curl -H "x-version: v2" http://<NODE_IP>:${GATEWAY_PORT}/
# → Hello from App B

https://ithelp.ithome.com.tw/upload/images/20260821/201819283VXlbRLjQM.png

2. 權重分流(Traffic Splitting / Canary)

將流量按比例分配到不同後端 — 這是金絲雀發布的基礎:

vim weight-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: weight-route
  namespace: default
spec:
  parentRefs:
    - name: my-gateway
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /canary
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /
      backendRefs:
        - name: app-a
          port: 80
          weight: 90            # 90% 流量給 app-a(穩定版)
        - name: app-b
          port: 80
          weight: 10            # 10% 流量給 app-b(金絲雀版)
kubectl apply -f weight-route.yaml
# 多打幾次,觀察回應比例
for i in $(seq 1 20); do
  curl -s http://<NODE_IP>:${GATEWAY_PORT}/canary
done

https://ithelp.ithome.com.tw/upload/images/20260821/20181928B8JXFp5ZTR.png

會發現大約 90% 的回應來自 App A,10% 來自 App B。

⚠️ 在 Ingress 中做權重分流

以 NGINX Ingress Controller 為例,通常需要搭配 nginx.ingress.kubernetes.io/canary 等 annotations,並建立額外的 Ingress 資源。

Gateway API 則可以直接在同一個 HTTPRoute 裡透過 backendRefs.weight 設定流量比例,寫法更集中,也更標準化。

3. 跨 Namespace 路由(ReferenceGrant)

Gateway API 支援跨 Namespace 引用 Backend,但需要由目標 Namespace 明確授權

例如:

https://ithelp.ithome.com.tw/upload/images/20260821/20181928t5rEgf9jYK.png

因為 HTTPRoute 和 Service 位於不同 Namespace,所以需要在 backend-ns 建立 ReferenceGrant

以下是概念範例:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-default-routes
  namespace: backend-ns
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: default
  to:
    - group: ""
      kind: Service

💡 ReferenceGrant 的安全設計

跨 Namespace 的 Backend Reference 必須由目標 Namespace 主動授權。

沒有對應的 ReferenceGrant,HTTPRoute 對另一個 Namespace Service 的引用就是無效的。


六、Gateway API vs Ingress 完整比較

比較項目 Ingress Gateway API
設計理念 以單一 Ingress Resource 管理入口與路由 角色分離:GatewayClass → Gateway → Route
路由能力 標準 API 主要支援 Host + Path 支援 Host、Path、Header、QueryParam、Method 等更完整的匹配能力
權重分流 通常依賴 Controller 自訂功能或 annotations 標準支援 backendRefs.weight
TLS 設定 TLS 與路由設定集中在 Ingress 中 Listener / TLS 主要由 Gateway 管理
跨 Namespace 標準 Ingress Backend 主要位於同 Namespace 支援跨 Namespace Reference,並透過 ReferenceGrant 授權
進階功能 常依賴 Controller-specific annotations / CRD 更多能力直接由 Gateway API 標準欄位定義
協定支援 主要針對 HTTP / HTTPS HTTP、gRPC、TLS、TCP、UDP 等
角色分工 平台與應用設定較容易混在一起 Gateway 與 Route 可以由不同角色管理
API 狀態 GA,但 API 已 Frozen,不再新增功能 Standard API 持續演進,功能仍在擴充

💡 該用哪個?

  • 新專案:可以優先評估 Gateway API
  • 現有 Ingress 運作良好:不需要為了更換而立即遷移
  • 需要 Header Routing、權重分流、跨 Namespace 或角色分工:Gateway API 通常更適合

Kubernetes 官方目前推薦使用 Gateway,而不是在新設計中繼續擴充 Ingress;不過 Ingress API 本身沒有移除計畫。


小結

今天我們學會了 Kubernetes 更現代的流量入口管理方式 —— Gateway API。

相比 Ingress,Gateway API 把基礎設施入口與應用路由拆開,提供更清楚的角色分工,以及更標準化的進階路由能力。

學到的東西 一句話總結
設計理念 角色分離 —— GatewayClass、Gateway、Route 由不同角色負責
核心資源 GatewayClass 定義類型、Gateway 定義入口、HTTPRoute 定義路由
路由能力 支援 Path、Host、Header 等匹配方式,也能做權重分流
跨 Namespace 透過 ReferenceGrant 控制跨 Namespace Backend Reference
標準化 更多能力直接由 Gateway API 欄位定義,減少對 Controller-specific annotations 的依賴
與 Ingress 的關係 Gateway API 是更現代的下一代方案,現有 Ingress 仍可繼續使用

一路從 Service → Ingress → Gateway API,我們已經從單純暴露服務,逐步學到如何集中管理入口流量、拆分平台與應用職責,並處理更進階的路由需求。

下一篇我們將進入 CRD 與 Operator —— 學習 Kubernetes 如何擴展自己的 API,建立自訂資源與控制邏輯!


參考資源


上一篇
Day 25|NetworkPolicy — Kubernetes 的網路策略與零信任隔離
系列文
從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言