Gateway API是Kubernetes官方專案,是下一代Kubernetes路由和負載平衡API,支援通過Gateway API配置流量規則。本文介紹Gateway with Inference Extension支援的一些Gateway API基礎能力配置方法。
工作原理
Gateway with Inference Extension組件基於Envoy Gateway專案構建,支援完整的Gateway API基礎能力及開源Envoy Gateway擴充資源。
Envoy Gateway架構包括:
控制面:由Envoy Gateway組件構成,主要負責監聽叢集中的流量規則,動態建立和管理Envoy代理執行個體,並即時更新其轉寄規則,但不直接參与業務流量的轉寄。
資料面:由實際啟動並執行Envoy Proxy執行個體組成,負責處理和轉寄業務流量,確保高效和可靠的通訊。
適用範圍
準備工作
建立測試應用backend和backend-2。將以下YAML內容儲存為backend.yaml,然後執行
kubectl apply -f backend.yaml命令。說明應用backend-2隻需要將backend的YAML中
backend全部替換為backend-2即可。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: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/envoygateway-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安裝Gateway with Inference Extension會預設建立GatewayClass,可參考以下方式進行查看。
kubectl get gatewayclass NAME CONTROLLER ACCEPTED AGE ack-gateway gateway.envoyproxy.io/gatewayclass-controller True 2m31s如未發現GatewayClass資源,需手動建立。
建立Gateway資源。將以下YAML內容儲存為gateway.yaml,然後執行
kubectl apply -f gateway.yaml命令。apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: ack-gateway spec: gatewayClassName: ack-gateway listeners: - name: http protocol: HTTP port: 80Gateway with Inference Extension組件控制面會根據當前Gateway資源建立出EnvoyProxy Deployment以及對應的LB類型的Service,並在指定連接埠開啟監聽。關於LB執行個體的計費標準,請參見負載平衡計費說明。
也可自訂EnvoyProxy的Deployment規格以及Service參數,或者開啟網關HPA。
擷取網關地址。
export GATEWAY_HOST=$(kubectl get gateway/ack-gateway -o jsonpath='{.status.addresses[0].value}')
基於路徑首碼匹配的HTTP路由
以下樣本配置HTTPRoute匹配/get首碼,並進行測實驗證。
建立HTTPRoute資源。將以下YAML內容儲存為httproute.yaml,然後執行
kubectl apply -f httproute.yaml命令。apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: backend spec: parentRefs: - name: ack-gateway hostnames: - "www.example.com" rules: - backendRefs: - group: "" kind: Service name: backend port: 3000 weight: 1 matches: - path: type: PathPrefix value: /get測試訪問。
curl -H "Host: www.example.com" http://$GATEWAY_HOST/get預期輸出:
{ "path": "/get", "host": "www.example.com", "method": "GET", "proto": "HTTP/1.1", "headers": { "Accept": [ "*/*" ], "User-Agent": [ "curl/8.9.1" ], "X-Envoy-External-Address": [ "115.XX.XXX.55" ], "X-Forwarded-For": [ "115.XX.XXX.55" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "953b2f8f-26d3-4ba9-93ba-a482b197b1ff" ] }, "namespace": "default", "ingress": "", "service": "", "pod": "backend-5bff7XXXXX-XXXXX" }
添加請求Header
更新HTTPRoute配置,為路由的請求添加Header。
更新HTTPRoute資源。將以下YAML內容儲存為httproute.yaml,然後執行
kubectl apply -f httproute.yaml命令。apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: backend spec: parentRefs: - name: ack-gateway hostnames: - "www.example.com" rules: - matches: - path: type: PathPrefix value: /get backendRefs: - group: "" kind: Service name: backend port: 3000 weight: 1 filters: - type: RequestHeaderModifier requestHeaderModifier: add: - name: "added-header" value: "foo"測試訪問。
curl -H "Host: www.example.com" http://$GATEWAY_HOST/get預期輸出:由於樣本應用會將請求資訊作為響應返回,因此可以在響應中看到已添加的
added-header,表明操作已成功。{ "path": "/get", "host": "www.example.com", "method": "GET", "proto": "HTTP/1.1", "headers": { "Accept": [ "*/*" ], "Added-Header": [ "foo" ], "User-Agent": [ "curl/8.9.1" ], "X-Envoy-External-Address": [ "115.XX.XXX.55" ], "X-Forwarded-For": [ "115.XX.XXX.55" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "d37f19e5-25c1-45cf-90e5-51453e7ae3ed" ] }, "namespace": "default", "ingress": "", "service": "", "pod": "backend-5bff7XXXXX-XXXXX" }
按比例分發請求
以下將再次更新HTTPRoute配置,增加backend-2的路由規則,並為backend和backend-2服務配置權重。
Gateway API並不要求所有backendRef的權重之和為100。單個服務比例計算規則為:
更新HTTPRoute資源。將以下YAML內容儲存為httproute.yaml,然後執行
kubectl apply -f httproute.yaml命令。apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: backend spec: parentRefs: - name: ack-gateway hostnames: - "www.example.com" rules: - matches: - path: type: PathPrefix value: /get backendRefs: - group: "" kind: Service name: backend port: 3000 weight: 8 - group: "" kind: Service name: backend-2 port: 3000 weight: 2測試連續訪問20次,查看兩個服務的比例。
以下命令進行了額外處理,使輸出僅顯示
backend和backend-2。for i in $(seq 1 20); do curl -sS -H "Host: www.example.com" http://$GATEWAY_HOST/get |grep backend; done | \ sed -E 's/".*"(backend(-2)?)-[0-9a-zA-Z]*-.*/\1/'預期輸出: 兩個服務接收到的流量比例大致為80%和20%。
backend-2 backend backend backend backend backend backend backend backend backend backend backend-2 backend-2 backend backend backend-2 backend backend backend backend
處理TLS流量
更新Gateway資源,配置認證並添加TLS監聽,以驗證對TLS流量處理的支援。
產生認證,並建立Secret。
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt openssl req -out www.example.com.csr -newkey rsa:2048 -nodes -keyout www.example.com.key -subj "/CN=www.example.com/O=example organization" openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 0 -in www.example.com.csr -out www.example.com.crt kubectl create secret tls example-cert --key=www.example.com.key --cert=www.example.com.crt更新Gateway資源。添加TLS監聽,並引用上一步建立的認證。
kubectl patch gateway ack-gateway --type=json --patch ' - op: add path: /spec/listeners/- value: name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - kind: Secret group: "" name: example-cert '查看更改是否生效。
kubectl get gateway/ack-gateway -o yaml | grep spec: -A 20預期輸出:
spec: gatewayClassName: ack-gateway listeners: - allowedRoutes: namespaces: from: Same name: http port: 80 protocol: HTTP - allowedRoutes: namespaces: from: Same name: https port: 443 protocol: HTTPS tls: certificateRefs: - group: "" kind: Secret name: example-cert mode: Terminate status:輸出結果表明,更改已經生效。
測試訪問。
curl -H Host: www.example.com --resolve "www.example.com:443:${GATEWAY_HOST}" \ --cacert example.com.crt https://www.example.com/get預期輸出:
{ "path": "/get", "host": "www.example.com", "method": "GET", "proto": "HTTP/1.1", "headers": { "Accept": [ "*/*" ], "User-Agent": [ "curl/8.9.1" ], "X-Envoy-External-Address": [ "115.XX.XXX.55" ], "X-Forwarded-For": [ "115.XX.XXX.55" ], "X-Forwarded-Proto": [ "https" ], "X-Request-Id": [ "ac539756-3826-474b-be2f-5e57fdd49dac" ] }, "namespace": "default", "ingress": "", "service": "", "pod": "backend-5bff7XXXXX-XXXXX" }