antony@notes:~/kubernetes$ cat "認識與實作-Kubernetes-Gateway-API.md"
認識與實作 Kubernetes Gateway API
認識與實作 Kubernetes Gateway API
Gateway API is an official Kubernetes project focused on L4 and L7 routing in Kubernetes. This project represents the next generation of Kubernetes Ingress, Load Balancing, and Service Mesh APIs. From the outset, it has been designed to be generic, expressive, and role-oriented.
關鍵角色與人物

背景
在 Kubernetes 最初的設計中,Ingress 與 Service 這兩種資源是基於一種使用模式:建立這些 Services 和 Ingresses 的 developers,擁有對定義和公開其應用程式給使用者的所有控制權。
然而,實際上叢集和基礎設施往往是共用的,這點在原本的 Ingress 模型中並沒有被很好地呈現。關鍵在於:當基礎設施被多個使用者共用時,每個使用者的關注點並不相同。要讓基礎設施專案成功,就必須同時滿足所有使用者的需求。
這就引出了核心挑戰:如何在滿足基礎設施使用者的彈性需求的同時,仍然保有基礎設施擁有者的控制權?
為了在可用性、彈性以及控制之間取得平衡,Gateway API 透過定義數個不同的角色和對應的人物,作為討論不同使用者需求的工具。Gateway API 的設計工作特別以這些人物為基礎。
需要注意的是,實際情況中(依照環境而異),同一個人可能同時扮演多個角色,下文將有詳細討論。
主要角色與人物
Gateway API 定義了三種角色及其對應的人物:
Ian (he/him)
- 是基礎設施提供者 ( Infrastructure Provider ),負責維護能讓多個隔離的叢集服務多個租戶的基礎設施。
- 他不受制於任何單一租戶,而是關心所有租戶的整體需求。
- Ian 通常在雲端提供商(AWS、Azure、GCP …)或平台即服務(PaaS)提供商工作。
Chihiro (they/them)
- 是叢集營運者(cluster operator),負責管理叢集並確保能滿足各類使用者的需求。
- 通常會關注政策(policy)、網路存取、應用程式權限等問題。
- 同樣地,Chihiro 不替叢集的任何單一用戶服務,而是確保叢集能符合所有用戶的需要。
Ana (she/her)
- 是應用程式開發者 ( Application developer ) ,負責在叢集內建立並管理應用程式。
- 就 Gateway API 而言,Ana 需要設定諸如逾時(timeout)、請求匹配/過濾,以及如何將服務組合(例如設定路徑將流量導向後端)等。
- Ana 與其他人物不同,她主要關注的是應用程式本身要達成的業務目標,而非 Kubernetes 或 Gateway API。事實上,她可能覺得 Gateway API 和 Kubernetes 只是阻礙她完成工作的「摩擦」。
根據實際環境,不同角色可能由同一個人擔任:
- 若將所有角色都賦予同一位使用者,這就複刻了所謂「自行服務(self-service)」的模式,小型新創公司在裸機(bare metal)上跑 Kubernetes 時,可能就會這麼做。
- 比較常見的狀況是小型新創公司使用雲端提供商的叢集。此時,Ana 與 Chihiro 的角色可能由同一個人擔任,而 Ian 則是雲端提供商的員工(或是一個自動化流程)。
- 在更大的組織裡,我們預期上述三個人物會分別由不同的人擔任(而且可能隸屬於不同部門,互相之間直接接觸並不多)。
Resource model
在資源模型中,有三種主要物件:
- GatewayClass:定義了擁有共同設定與行為的一組 Gateways。
- Gateway:提出一個「流量切入點」的需求,能將外部流量轉譯至叢集中的 Service。
- Routes:描述從 Gateway 進來的流量如何對應(映射)到各個 Service。
GatewayClass
GatewayClass 定義了一組具備共同設定與行為的 Gateway。每個 GatewayClass 都會由單一 controller 來處理,儘管一個 controller 也可以同時管理多個 GatewayClass。
GatewayClass 是一種叢集層級(cluster-scoped)的資源。要讓 Gateway 正常運作,系統中至少必須定義一個 GatewayClass。任何實作了 Gateway API 的 controller,都是透過提供對應的 GatewayClass 資源,讓使用者在其 Gateway 中引用。
這與 Ingress 的 IngressClass、以及 PersistentVolume 的 StorageClass 類似。在 Ingress v1beta1 中,與 GatewayClass 最相近的是 ingress-class annotation;而在 Ingress v1 中,最接近的則是 IngressClass 這個物件。
Gateway
Gateway 用來描述叢集中流量如何被轉譯到 Service。換句話說,它定義了一種要求,能把「外面不知道 Kubernetes 的地方」發過來的流量,轉譯到「能理解 Kubernetes 的地方」。例如,從雲端負載平衡器(cloud load balancer)、叢集內的代理(in-cluster proxy),或是外部硬體負載平衡器(external hardware load balancer)傳送到 Kubernetes Service 的流量。雖然很多情境中,客戶端的流量可能來自叢集「外部」,但這並不是必要條件。
Gateway 定義了一個對「特定負載平衡器設定」的請求,該設定實作了 GatewayClass 的設定與行為約定。這個資源可以由操作人員(operator)直接建立,或者由管理 GatewayClass 的 controller 來建立。
由於 Gateway 規範(spec)是為了捕捉使用者的意圖,因此它可能不包含所有屬性的完整規範。例如,使用者可能略過像是位址(addresses)、TLS 設定這類的欄位。如此一來,負責管理 GatewayClass 的控制器就能為使用者填入這些設定,讓整個規範更具可攜性。這項行為會透過 GatewayClass 的狀態(Status)物件來說明。
一個 Gateway 可以附加到一個或多個 Route references ,這些 Route 用於將部分流量導向至特定服務。
可以說成 GatewayClass 的具體實現,聲明後由 GatewayClass 的 Infrastructure Provider 提供一個具體存在的 Pod,充當了進入 Kubernetes 集群的流量的入口,負責流量接入以及往後轉發,同時還可以起到一個初步過濾的效果。
Route Resources
Route resources define protocol-specific rules for mapping requests from a Gateway to Kubernetes Services.
HTTPRoute
定義了與 HTTP 有關的規則,用於將來自 Gateway listener 的流量,對應到後端網路端點的表示方式。這些端點通常以 Service 的形式呈現。
Route summary table
| Object | OSI Layer | Routing Discriminator | TLS Support | Purpose |
|---|---|---|---|---|
| HTTPRoute | Layer 7 | Anything in the HTTP Protocol | Terminated only | HTTP and HTTPS Routing |
| TLSRoute | Somewhere between layer 4 and 7 | SNI or other TLS properties | Passthrough or Terminated | Routing of TLS protocols including HTTPS where inspection of the HTTP stream is not required. |
| TCPRoute | Layer 4 | destination port | Passthrough or Terminated | Allows for forwarding of a TCP stream from the Listener to the Backends |
| UDPRoute | Layer 4 | destination port | None | Allows for forwarding of a UDP stream from the Listener to the Backends. |
| GRPCRoute | Layer 7 | Anything in the gRPC Protocol | Terminated only | gRPC Routing over HTTP/2 and HTTP/2 cleartext |
Gateway API Quick Start
Step1: Install the Gateway API CRDs and Envoy Gateway
$ kubectl apply --server-side -f https://github.com/envoyproxy/gateway/releases/download/v1.2.4/install.yaml查看安装的 CRDs 資源
$ kubectl get crd | grep networking.k8s.io執行結果 :
backendlbpolicies.gateway.networking.k8s.io 2024-12-22T11:11:31Z
backendtlspolicies.gateway.networking.k8s.io 2024-12-22T11:11:31Z
gatewayclasses.gateway.networking.k8s.io 2024-12-22T11:11:31Z
gateways.gateway.networking.k8s.io 2024-12-22T11:11:31Z
grpcroutes.gateway.networking.k8s.io 2024-12-22T11:11:31Z
httproutes.gateway.networking.k8s.io 2024-12-22T11:11:31Z
referencegrants.gateway.networking.k8s.io 2024-12-22T11:11:31Z
tcproutes.gateway.networking.k8s.io 2024-12-22T11:11:31Z
tlsroutes.gateway.networking.k8s.io 2024-12-22T11:11:31Z
udproutes.gateway.networking.k8s.io 2024-12-22T11:11:31Z查看安装的 envoy controller 運作狀態是否正常
$ kubectl get pod -n envoy-gateway-system執行結果 :
NAME READY STATUS RESTARTS AGE
envoy-gateway-67469b6f59-n4js6 1/1 Running 0 73sStep2: Install the GatewayClass, Gateway, HTTPRoute and example app
1. 安裝 GatewayClass
$ cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
EOFGatewayClass 是 Cluster level 的資源, GatewayClass 規格定義如下:
spec: Spec 定義了GatewayClass期望的狀態controllerName: ControllerName is the name of the controller that is managing Gateways of this class. The value of this field MUST be a domain prefixed path. 此欄位不可變更,且不能為空。
- 更多有關
GatewayClass的定義請參考此連結

controllername 被定義在 envoy-gateway-system namespace 底下的 envoy-gateway-config configmap
kubectl -n envoy-gateway-system get cm envoy-gateway-config -o yaml執行結果 :
apiVersion: v1
data:
envoy-gateway.yaml: |
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyGateway
gateway:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
logging:
level:
default: info
provider:
kubernetes:
rateLimitDeployment:
container:
image: docker.io/envoyproxy/ratelimit:49af5cca
patch:
type: StrategicMerge
value:
spec:
template:
spec:
containers:
- imagePullPolicy: IfNotPresent
name: envoy-ratelimit
shutdownManager:
image: envoyproxy/gateway:v1.2.4
... 以下省略檢視 GatewayClass
$ kubectl get gatewayclass執行結果 :
NAME CONTROLLER ACCEPTED AGE
eg gateway.envoyproxy.io/gatewayclass-controller True 13m在本範例中,已實作 Gateway API 的 controller 被設定為管理 GatewayClasses,controller 名稱為 gateway.envoyproxy.io/gatewayclass-controller。 此類別的 Gateway 將由實作的 controller 管理。
2. 安裝範例 Application
依序建立:
- backend ServiceAccount:供權限管理使用。
- backend Service:監聽
3000tcp/port 並依據標籤app: backend對應到後端 Pod。 - backend Deployment:啟動一個網站,並自動設定
POD_NAME、NAMESPACE環境變數。

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: backend
---
apiVersion: v1
kind: Service
metadata:
name: backend
labels:
app: backend
service: backend
spec:
ports:
- name: http
port: 3000
targetPort: 3000
selector:
app: backend
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
version: v1
template:
metadata:
labels:
app: backend
version: v1
spec:
serviceAccountName: backend
containers:
- image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e
imagePullPolicy: IfNotPresent
name: backend
ports:
- containerPort: 3000
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
EOF檢視 Application 部署狀態
$ kubectl get pods,svc -l app=backend執行結果 :
NAME READY STATUS RESTARTS AGE
pod/backend-765694d47f-4rcr6 1/1 Running 0 28s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/backend ClusterIP 10.98.32.77 <none> 3000/TCP 28s3. 安裝 Gateway
$ cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: eg
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
EOFGateway 規格定義如下:
- Gateway represents an instance of a service-traffic handling infrastructure by binding Listeners to a set of IP addresses.
GatewayClassName: 定義此Gateway使用的GatewayClass物件的名稱。Listeners: 定義listener的hostnames、ports、protocol、termination、TLS settings,以及哪些routes可以附加到listener。- Listener 體現了
Gateway接受網路連線的邏輯端點概念。
- Listener 體現了
Addresses: 定義此Gateway所要求的 IP 位址,If no Addresses are specified, the implementation MAY schedule the Gateway in an implementation-specific manner, assigning an appropriate set of Addresses.
檢視 Gateway
$ kubectl get gateway執行結果 :
NAME CLASS ADDRESS PROGRAMMED AGE
eg eg False 16m檢查流量入口的 Pod
$ kubectl -n envoy-gateway-system get pods \
-o wide \
-l "app.kubernetes.io/component=proxy"執行結果 :
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES envoy-default-eg-e41e7b31-75c864f477-4drs5 2/2 Running 0 23s 10.244.33.16 tkdev-worker1
檢查流量入口 Pod 的 Service
$ kubectl -n envoy-gateway-system get svc,endpointslices \
-l "app.kubernetes.io/component=proxy"執行結果 :
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/envoy-default-eg-e41e7b31 LoadBalancer 10.98.32.2480:31375/TCP 65s NAME ADDRESSTYPE PORTS ENDPOINTS AGE endpointslice.discovery.k8s.io/envoy-default-eg-e41e7b31-qswvj IPv4 10080 10.244.33.16 65s
可以看到 Envoy 在使用者建立 Gateway 後,會自動建立接收外部流量的 pod 跟 Service

4. 設定與安裝 HttpRoute
HTTPRoute 提供一種路由 HTTP 請求的方式。 這包括根據 hostname、path、header 或 query param 來匹配請求的功能。Filters 可用於指定額外的處理步驟。Backends 指定匹配的請求應被路由到哪裡。
$ cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: backend
spec:
parentRefs:
- name: eg
hostnames:
- "www.example.com"
rules:
- backendRefs:
- group: ""
kind: Service
name: backend
port: 3000
weight: 1
matches:
- path:
type: PathPrefix
value: /
EOFspec: 定義HTTPRoute的期望狀態。parentRefs: 用來指定一個路由(Route)想要附加的資源(通常是 Gateways)。hostnames: Hostnames 是用來定義一組主機名稱,用來匹配 HTTP 請求中的 Host Header,以選擇適合的 HTTPRoute 處理該請求。- 在進行匹配時,實作(例如 Gateway 或控制器)必須忽略 HTTP Host 標頭中包含的埠號(Port Value)。
- 如果沒有進行任何與標頭修改相關的配置,實作必須原樣將 Host 標頭轉發給後端(Backend),不進行任何更改。
- 如果 Listener 和 HTTPRoute 都指定了主機名稱,則 HTTPRoute 必須至少有一個相交的主機名稱才能附加到 Listener。
rules: HTTPRouteRule 是用來定義如何處理 HTTP 請求的規則,主要分為以下三個部分:- 匹配條件 (
matches):
根據請求的特定條件(例如 URL 路徑、方法、標頭等)來判斷是否符合規則。path:根據 URL 路徑做為的匹配條件。type:匹配類型,這裡是PathPrefix,表示路徑前綴匹配。value:路徑值,這裡是/,表示所有以/開頭的路徑都會匹配此規則。
- 處理方式(
filters):
指定如何處理這些匹配的請求,比如添加、修改或刪除標頭,執行重新導向等操作。 - 轉發目標(
backendRefs):
將處理後的請求轉發給指定的 API 物件,例如後端服務或其他資源。group:API 群組,這裡是空字串,表示 Core API 群組。kind:資源類型,這裡是Service,表示 Kubernetes Service。name:Service 的名稱,這裡是backend。port:服務的 port number,這裡是3000。weight:權重,這裡是1,在多個後端之間進行流量分配時使用。
- 匹配條件 (

查看安装的 httproute 資源
$ kubectl get httproute執行結果 :
NAME HOSTNAMES AGE
backend ["www.example.com"] 9s5. 測試連線並檢視請求流程
如果 K8s 有安裝 MetalLB,則可跳過 5.1 和 5.2 步驟,直接執行以下命令
:::spoiler With External LoadBalancer Support
:::info
取得 Envoy Service 的 external IP,請執行:
$ export GATEWAY_HOST=$(kubectl get gateway/eg \
-o jsonpath='{.status.addresses[0].value}')透過 Envoy proxy 連線範例應用 Application
$ curl --verbose --header "Host: www.example.com" http://$GATEWAY_HOST/get:::
5.1. 取得範例 Gateway 所建立的 Envoy Service 的名稱:
就是 Envoy 在使用者建立 Gateway 後,會自動建立接收外部流量的 pod 跟 Service,先把這個 Service 的名稱設為變數
$ export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')5.2. 將 Envoy Service Port forward 出去:
$ kubectl -n envoy-gateway-system port-forward \
--address 192.168.61.128 \
service/${ENVOY_SERVICE} 8888:80 &
--address, Addresses to listen on (comma separated),192.168.61.128為 tkcdc 主機的 IP
執行結果 :
[1] 32937
Forwarding from 192.168.61.128:8888 -> 10080
Handling connection for 88885.3. 透過 Envoy proxy 連線範例應用 App:

在 Taroko K8s 叢集外部執行以下命令 :
$ curl --verbose --header "Host: www.example.com" http://192.168.61.128:8888/get執行結果 :
* Trying 192.168.61.128:8888...
* connect to 192.168.61.128 port 8888 from 0.0.0.0 port 9362 failed: Connection refused
* Failed to connect to 192.168.61.128 port 8888 after 2037 ms: Could not connect to server
* closing connection #0
curl: (7) Failed to connect to 192.168.61.128 port 8888 after 2037 ms: Could not connect to server
C:\Users\antony>curl --verbose --header "Host: www.example.com" http://192.168.61.128:8888/get
* Trying 192.168.61.128:8888...
* Connected to 192.168.61.128 (192.168.61.128) port 8888
* using HTTP/1.x
> GET /get HTTP/1.1
> Host: www.example.com
> User-Agent: curl/8.10.1
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/json
< x-content-type-options: nosniff
< date: Wed, 25 Dec 2024 02:17:01 GMT
< content-length: 456
<
{
"path": "/get",
"host": "www.example.com",
"method": "GET",
"proto": "HTTP/1.1",
"headers": {
"Accept": [
"*/*"
],
"User-Agent": [
"curl/8.10.1"
],
"X-Envoy-Internal": [
"true"
],
"X-Forwarded-For": [
"10.244.33.9"
],
"X-Forwarded-Proto": [
"http"
],
"X-Request-Id": [
"1788f941-4043-42b7-b7ea-893bf3f4a449"
]
},
"namespace": "default",
"ingress": "",
"service": "",
"pod": "backend-765694d47f-tv9ft"
}* Connection #0 to host 192.168.61.128 left intact5.4. 檢視請求流程

在此範例中,當 Gateway 作為反向代理時,請求流程如下:
- 客戶端開始準備一個指向
http://www.example.com的 HTTP 請求。 - 客戶端的 DNS 解析器查詢目標名稱,並獲取與 Gateway 關聯的一個或多個 IP 位址。
- 客戶端向 Gateway 的 IP 位址發送請求;反向代理接收該 HTTP 請求,並使用
Host:標頭來匹配從 Gateway 和附加的 HTTPRoute 衍生的配置。 - (可選)反向代理可以根據 HTTPRoute 的匹配規則,對請求的標頭和/或路徑進行匹配。
- (可選)反向代理可以修改該請求;例如,根據 HTTPRoute 的過濾規則添加或刪除標頭。
- 最後,反向代理將該請求轉發給一個或多個後端服務。
6. 清除環境
移除 Qucik Start 中的所有內容 :
$ kubectl delete -f \
https://github.com/envoyproxy/gateway/releases/download/v1.2.4/quickstart.yaml \
--ignore-not-found=true刪除 Gateway API CRD 和 Envoy Gateway:
$ kubectl delete -f \
https://github.com/envoyproxy/gateway/releases/download/v1.2.4/install.yaml \
--ignore-not-found=true