Kubernetes Gateway API

除了自身的流量管理 API 之外,Istio 也支援 Kubernetes 的 Gateway API,並計劃將其作為未來流量管理的預設 API。本文將說明 Istio 和 Kubernetes API 之間的差異,並提供一個簡單的範例,展示如何設定 Istio,使用 Gateway API 將服務暴露在服務網格叢集之外。請注意,這些 API 是 Kubernetes ServiceIngress API 的積極開發演進。

設定

  1. 大多數 Kubernetes 叢集預設並未安裝 Gateway API。如果它們不存在,請安裝 Gateway API CRD。

    $ kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
      { kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.2.0" | kubectl apply -f -; }
    
  2. 使用 minimal 設定檔安裝 Istio。

    $ istioctl install --set profile=minimal -y
    

與 Istio API 的差異

Gateway API 與 Istio API 有許多相似之處,例如 Gateway 和 VirtualService。主要資源共享相同的名稱 Gateway,並且這些資源具有相似的目標。

新的 Gateway API 旨在吸收各種 Kubernetes Ingress 實作(包括 Istio)的經驗,以建立標準化的、供應商中立的 API。這些 API 的目的通常與 Istio Gateway 和 VirtualService 相同,但有一些關鍵差異。

  • 在 Istio API 中,Gateway 設定一個已部署的現有閘道 Deployment/Service。在 Gateway API 中,Gateway 資源既設定也部署閘道。有關更多資訊,請參閱部署方法
  • 在 Istio VirtualService 中,所有協定都在單一資源內設定。在 Gateway API 中,每種協定類型都有自己的資源,例如 HTTPRouteTCPRoute
  • 雖然 Gateway API 提供了豐富的路由功能,但它尚未涵蓋 Istio 100% 的功能集。目前正在努力擴展 API 以涵蓋這些使用案例,並利用 API 的可擴展性,以便更好地公開 Istio 的功能。

設定閘道

有關 API 的資訊,請參閱Gateway API 文件。

在此範例中,我們將部署一個簡單的應用程式,並使用 Gateway 將其對外公開。

  1. 首先,部署 httpbin 測試應用程式。

    Zip
    $ kubectl apply -f @samples/httpbin/httpbin.yaml@
    
  2. 部署 Gateway API 設定,包括單一公開路由(即 /get)。

    $ kubectl create namespace istio-ingress
    $ kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: gateway
      namespace: istio-ingress
    spec:
      gatewayClassName: istio
      listeners:
      - name: default
        hostname: "*.example.com"
        port: 80
        protocol: HTTP
        allowedRoutes:
          namespaces:
            from: All
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: http
      namespace: default
    spec:
      parentRefs:
      - name: gateway
        namespace: istio-ingress
      hostnames: ["httpbin.example.com"]
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /get
        backendRefs:
        - name: httpbin
          port: 8000
    EOF
    
  3. 設定 Ingress Host 環境變數。

    $ kubectl wait -n istio-ingress --for=condition=programmed gateways.gateway.networking.k8s.io gateway
    $ export INGRESS_HOST=$(kubectl get gateways.gateway.networking.k8s.io gateway -n istio-ingress -ojsonpath='{.status.addresses[0].value}')
    
  4. 使用 curl 存取 httpbin 服務。

    $ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST/get"
    ...
    HTTP/1.1 200 OK
    ...
    server: istio-envoy
    ...
    

    請注意,使用 -H 標誌是為了將 Host HTTP 標頭設定為 “httpbin.example.com”。這是必要的,因為 HTTPRoute 設定為處理 “httpbin.example.com”,但在您的測試環境中,您沒有該主機的 DNS 綁定,而只是將請求傳送到入口 IP。

  5. 存取任何其他未明確公開的 URL。您應該看到 HTTP 404 錯誤。

    $ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST/headers"
    HTTP/1.1 404 Not Found
    ...
    
  6. 更新路由規則以同時公開 /headers,並在請求中新增標頭。

    $ kubectl apply -f - <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: http
      namespace: default
    spec:
      parentRefs:
      - name: gateway
        namespace: istio-ingress
      hostnames: ["httpbin.example.com"]
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /get
        - path:
            type: PathPrefix
            value: /headers
        filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            add:
            - name: my-added-header
              value: added-value
        backendRefs:
        - name: httpbin
          port: 8000
    EOF
    
  7. 再次存取 /headers,並注意標頭 My-Added-Header 已新增至請求。

    $ curl -s -HHost:httpbin.example.com "http://$INGRESS_HOST/headers" | jq '.headers["My-Added-Header"][0]'
    ...
    "added-value"
    ...
    

部署方法

在上面的範例中,您無需在設定 Gateway 之前安裝入口閘道 Deployment。在預設設定中,會根據 Gateway 設定自動佈建閘道 DeploymentService。對於進階使用案例,仍然允許手動部署。

自動化部署

預設情況下,每個 Gateway 都會自動佈建一個同名的 ServiceDeployment。如果 Gateway 發生變更(例如,新增了新連接埠),這些設定將會自動更新。

可以使用幾種方式自訂這些資源。

  • Gateway 上的註解和標籤將會複製到 ServiceDeployment。這允許設定諸如從這些欄位讀取的內部負載平衡器之類的功能。

  • Istio 提供額外的註解來設定產生的資源。

    註解目的
    networking.istio.io/service-type控制 Service.spec.type 欄位。例如,設定為 ClusterIP 以不對外公開服務。預設值為 LoadBalancer
  • 可以透過設定 addresses 欄位來明確設定 Service.spec.loadBalancerIP 欄位。

    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: gateway
    spec:
      addresses:
      - value: 192.0.2.0
        type: IPAddress
    ...
    

注意:只能指定一個位址。

資源附加和擴展

可以將資源附加Gateway 以進行自訂。但是,大多數 Kubernetes 資源目前不支援直接附加到 Gateway,但可以附加到對應產生的 DeploymentService。這很容易完成,因為這兩個資源都是以名稱 <gateway name>-<gateway class name> 和標籤 gateway.networking.k8s.io/gateway-name: <gateway name> 產生。

例如,要部署具有 HorizontalPodAutoscalerPodDisruptionBudgetGateway

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
spec:
  gatewayClassName: istio
  listeners:
  - name: default
    hostname: "*.example.com"
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: All
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: gateway
spec:
  # Match the generated Deployment by reference
  # Note: Do not use `kind: Gateway`.
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: gateway-istio
  minReplicas: 2
  maxReplicas: 5
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: gateway
spec:
  minAvailable: 1
  selector:
    # Match the generated Deployment by label
    matchLabels:
      gateway.networking.k8s.io/gateway-name: gateway

手動部署

如果您不想要自動化部署,可以手動設定 DeploymentService

完成此選項後,您需要手動將 Gateway 連結到 Service,並保持它們的連接埠設定同步。

為了支援原則附加,例如當您在 AuthorizationPolicy 上使用 targetRef 欄位時,您還需要透過將以下標籤新增至您的閘道 Pod 來參照您的 Gateway 名稱:gateway.networking.k8s.io/gateway-name: <gateway name>

若要將 Gateway 連結到 Service,請設定 addresses 欄位以指向單一 Hostname

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway
spec:
  addresses:
  - value: ingress.istio-gateways.svc.cluster.local
    type: Hostname
...

網格流量

Gateway API 也可用於設定網格流量。這是透過將 parentRef 設定為指向服務而不是閘道來完成的。

例如,要將標頭新增至對叢集中名為 exampleService 的所有呼叫。

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: mesh
spec:
  parentRefs:
  - group: ""
    kind: Service
    name: example
  rules:
  - filters:
    - type: RequestHeaderModifier
      requestHeaderModifier:
        add:
        - name: my-added-header
          value: added-value
    backendRefs:
    - name: example
      port: 80

更多詳細資訊和範例可在其他流量管理任務中找到。

清理

  1. 移除 httpbin 範例和閘道。

    Zip
    $ kubectl delete -f @samples/httpbin/httpbin.yaml@
    $ kubectl delete httproute http
    $ kubectl delete gateways.gateway.networking.k8s.io gateway -n istio-ingress
    $ kubectl delete ns istio-ingress
    
  2. 解除安裝 Istio。

    $ istioctl uninstall -y --purge
    $ kubectl delete ns istio-system
    
  3. 如果不再需要,請移除 Gateway API CRD。

    $ kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.2.0" | kubectl delete -f -
    
此資訊是否有用?
您是否有任何改進建議?

感謝您的回饋!