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 的價值與定位

Gateway API 介紹

網關 API 主要分爲以下幾個角色:

目前 GKE 提供了四種網關類,分別是:

網關部署

目前 GKE 的 Gateway APIK8S 1.20 以上的版本,如果使用 GKE 發佈頻道需要捧油,現在需要使用 RAPID 區域,同時僅在以下提供公開 Beta 測試:

下面的測試,我們選擇先測試 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。

因爲我們想創建一個跨命名空間的共享網關,所以我們將 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 的不同能力

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