Ingress 繼任者 Gateway API 使用
Gateway API
(之前叫 Service API)是由 SIG-NETWORK 社區管理的開源項目,項目地址:https://gateway-api.sigs.k8s.io/。主要原因是 Ingress 資源對象不能很好的滿足網絡需求,很多場景下 Ingress 控制器都需要通過定義 annotations 或者 crd 來進行功能擴展,這對於使用標準和支持是非常不利的,新推出的 Gateway API 旨在通過可擴展的面向角色的接口來增強服務網絡。
Gateway API
是 Kubernetes 中的一個 API 資源集合,包括 GatewayClass、Gateway、HTTPRoute、TCPRoute、Service 等,這些資源共同爲各種網絡用例構建模型。
Gateway API 的價值與定位
-
提供跨 Namespace 的一種 Ingress 機制:讓多個跨 Namespace 的服務,可以分享一個 L7 LoadBalancer
-
可實現多租戶的一種 Ingress 機制:提供 HttpRoute 與 Gateway 分離的抽象組件,讓設計路由 (HttpRoute) 的人,可以共享一個 L7 LoadBalancer,
-
藍綠部署金絲雀部署時爲使用同一個命名空間下的部署,可以簡單的定義在 HttpRoute 中
-
基於 Hostname、Header、或 Subpath 的服務,使用 AB 測試等等。
Gateway API 介紹
網關 API 主要分爲以下幾個角色:
-
GatewayClass(由 Cloud 或 K8s 提供者提供),
-
Gateway(由網管平臺公司自建 GatewayClass),
-
HTTPRoute(由開發者團隊服務部署者選擇對應的網關對接)
目前 GKE 提供了四種網關類,分別是:
-
gke-l7-rilb
建立在內部 HTTP(S) 負載均衡上的區域內部 HTTP(S) 負載均衡器 (單叢集 Internal LoadBalancer) -
gke-l7-gxlb
建立在外部 HTTP(S) 負載均衡之上的全球外部 HTTP(S) 負載均衡器 (單叢集 External LoadBalancer) -
gke-l7-rilb-mc
基於 Internal HTTP(S) Load Balancing 的多集羣區域負載均衡器 (多叢集 Internal LoadBalancer) -
gke-l7-gxlb-mc
基於 External HTTP(S) Load Balancing 的多集羣全局負載均衡器 (多叢集 External LoadBalancer)
網關部署
目前 GKE 的 Gateway APIK8S 1.20 以上的版本,如果使用 GKE 發佈頻道需要捧油,現在需要使用 RAPID 區域,同時僅在以下提供公開 Beta 測試:
-
us-west1
-
us-east1
-
us-central1
-
europe-west4
-
europe-west3
-
europe-west2
-
europe-west1
-
asia-southeast1
下面的測試,我們選擇先測試 Interal-LoadBalancer 並嘗試下面的拓撲圖:
部署私有 GKE
我們先開發一個私人 GKE 集羣,可以參照我提供的 Terraform 腳本,請直接將 shawn.tfvars 改爲符合你集羣的參數,另外,由於我使用遠端 GCS 也請設置保存 tfstate,修改 config.tf 裏面的 bucket 名稱。其他經常設置和私有 GKE 類似,只需要使用內部 LB 而增加了一個 proxy-only 的子網給 Envoy 使用。
部署網關
根據上述的第三個階段,我們先部署 Gateway API 的 CRD 檔案:
kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.3.0" \
| kubectl apply -f -
# 部署成功後,可使用下方命令檢視單叢集internal/external GatewayClass
private-gke-tf % kubectl get gatewayclass
NAME CONTROLLER AGE
gke-l7-gxlb networking.gke.io/gateway 23h
gke-l7-rilb networking.gke.io/gateway 23h
下一步我們準備部署網關,使用 kubectl apply -f
部署底下 YAML:
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: internal-http
spec:
gatewayClassName: gke-l7-rilb
listeners:
- protocol: HTTP
port: 80
routes:
kind: HTTPRoute
selector:
matchLabels:
gateway: internal-http
namespaces:
from: "All"
因爲 Gateway 可以接受三個關聯模式,基於 kind,selector,以及 namespace。
-
kind:以下可選任一種 Route: HTTPRoute, TCPRoute, or customRoute
-
標籤:通過選擇或選擇對應的標籤
-
namespaces:貫穿
namespaces.from
選擇 Route 所在的 namespace,預設是跟 Gateway 在同一個 namespace 的 Route
因爲我們想創建一個跨命名空間的共享網關,所以我們將 namespaces.from
改成 All
。
部署成功後,可以通過以下命令來查看:
private-gke-tf % kubectl describe gateway internal-http
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SYNC 4m59s (x396 over 23h) sc-gateway-controller SYNC on default/internal-http was a success
部署服務 + HTTPRoute
接下來我們快速部署測試的兩個服務,其中 store 服務部署在默認命名空間,site 服務部署在 site 命名空間。部署對應的 HTTPRoute,其中 http-route.yaml
適用於 store 服務的:
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: store
labels:
gateway: internal-http
spec:
hostnames:
- "store.example.com"
rules:
- forwardTo:
- serviceName: store-v1
port: 8080
weight: 50
- serviceName: store-v2
port: 8080
weight: 50
- matches:
- headers:
type: Exact
values:
env: canary
forwardTo:
- serviceName: store-v2
port: 8080
- matches:
- path:
type: Prefix
value: /de
forwardTo:
- serviceName: store-german
port: 8080
我們針對 store 服務,故意開發了三個不同的後端服務,一次來測試 HTTPRoute 的不同能力
-
(1) 主機名匹配:通過不同的主機名(如 store.example.com or site.example.com)將用戶連接路由到指定的後臺服務
-
(2.1) header match: 如果請求 header 中包含
env: canary
這樣的信息,就會被路由到store-v2
服務 -
(2.2) 前綴匹配:若請求路徑前綴是
/de
,則會被路由到store-german
服務 -
(3) 默認路由:根據權重,自動均衡到指定的 store-v1 與 store-v2 的兩個後臺服務
而 http-service.yaml
是用於配置服務的,由於 HTTPRoute 與 Gateway 所在的命名空間不同,因此必須引入一個 gatewayRefs
參數:
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: site
namespace: site
labels:
gateway: internal-http
spec:
gateways:
allow: FromList
gatewayRefs:
- name: internal-http
namespace: default
hostnames:
- "site.example.com"
rules:
- forwardTo:
- serviceName: site-v1
port: 8080
由於我們使用的是 Internal LoadBalancer,所以我們需要開一臺 GCE VM 來進行測試,由於我們使用的是 private cluster,所以要記得 GCE VM 和 private GKE cluster 在同一個 VPC 中。
在 K8S client 上,獲取 Internal LoadBalancer 的 IP 地址:
kubectl get gateway internal-http -o jsonpath='{.status.addresses[0].value}'
10.81.68.140
在 GCE VM 上,我們來測試上面我們定義的 HttpRoute:
(1) 按照 Hostname 來路由服務:通過定義 hostname 爲 site.example.com
來路由到另一個 namespace 的 K8S 服務中:
shawnho@jumper2:~$ curl -H "host: site.example.com" 10.81.68.140
{
"cluster_name": "pgke-1",
"host_header": "site.example.com",
"metadata": "site-v1",
"node_name": "gke-pgke-1-cluster-runtime-425beb23-vx9j.c.shawn-demo-2021.internal",
"pod_name": "site-v1-86dc4b4fbc-4g6jr",
"pod_name_emoji": "🌾",
"project_id": "shawn-demo-2021",
"timestamp": "2021-07-18T15:26:15",
"zone": "asia-southeast1-a"
}
(2) 基於 Hostname: “store.example.com”,再分別測試 (2.1) Header 與 (2.2) Prefix 前綴機制:
# 測試header match
shawnho@jumper2:~$ curl -H "host: store.example.com" -H "env: canary" 10.81.68.140
{
"cluster_name": "pgke-1",
"host_header": "store.example.com",
"metadata": "store-v2",
"node_name": "gke-pgke-1-cluster-runtime-425beb23-vx9j.c.shawn-demo-2021.internal",
"pod_name": "store-v2-6856f59f7f-49fv8",
"pod_name_emoji": "🎹",
"project_id": "shawn-demo-2021",
"timestamp": "2021-07-18T15:33:04",
"zone": "asia-southeast1-a"
}
# 測試prefix match
shawnho@jumper2:~$ curl -H "host: store.example.com" 10.81.68.140/de
{
"cluster_name": "pgke-1",
"host_header": "store.example.com",
"metadata": "Gutentag!",
"node_name": "gke-pgke-1-cluster-runtime-425beb23-vx9j.c.shawn-demo-2021.internal",
"pod_name": "store-german-66dcb75977-ttngz",
"pod_name_emoji": "💇🏼♀",
"project_id": "shawn-demo-2021",
"timestamp": "2021-07-18T15:32:15",
"zone": "asia-southeast1-a"
}
(3) 通過基於 Host: store.example.com
下的 Default Route 按權重(1:1)路由服務:
# 測試default route
shawnho@jumper2:~$ curl -H "host: store.example.com" 10.81.68.140
{
"cluster_name": "pgke-1",
"host_header": "store.example.com",
"metadata ": "store-v1",
"node_name": "gke-pgke-1-cluster-runtime-425beb23-vx9j.c.shawn-demo-2021.internal",
"pod_name": "store-v1-65b47557df-rv65j ",
"pod_name_emoji": "🧘🏿♂️",
"project_id": "shawn-demo-2021",
"timestamp": "2021-07-18T15:32:09",
"zone": "asia-southeast1-a”
}
shawnho@jumper2:~$ curl -H "host: store.example.com" 10.81.68.140
{
"cluster_name": "pgke-2",
"host_header": "store.example.com",
"metadata": "store -v2",
"node_name": "gke-pgke-2-cluster-runtime-e7f1b4b7-wg5a.c.shawn-demo-2021.internal",
"pod_name": "store-v2-6856f59f7f-gkkct",
"pod_name_emoji ": "👈🏼",
"project_id": "shawn-demo-2021",
"timestamp": "2021-07-18T15:32:29",
"zone": "asia-southeast1-a"
}
到這裏可以看到測試成功了!
原文鏈接:https://medium.com/%E8%BC%95%E9%AC%86%E5%B0%8F%E5%93%81-pks%E8%88%87k8s%E7%9A%84%E9%BB%9E%E6%BB%B4/k8s-gateway-api-contour%E7%9A%84%E9%80%B2%E5%8C%96%E7%89%88-44476e59135e
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/3tOxlBgeisFgFhjGcK-lUA