建立 Service 和 Ingress

本文說明如何在 Google Distributed Cloud 的使用者、混合或獨立叢集中,建立 Kubernetes Ingress 物件。Ingress 會與一或多個服務建立關聯,而每個服務都會與一組 Pod 建立關聯。

可建立部署作業

如要建立 Deployment,請按照下列步驟操作:

  1. 建立 Deployment 資訊清單:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-deployment
    spec:
      selector:
        matchLabels:
          greeting: hello
      replicas: 3
      template:
        metadata:
          labels:
            greeting: hello
        spec:
          containers:
          - name: hello-world
            image: "gcr.io/google-samples/hello-app:2.0"
            env:
            - name: "PORT"
              value: "50000"
          - name: hello-kubernetes
            image: "gcr.io/google-samples/node-hello:1.0"
            env:
            - name: "PORT"
              value: "8080"
    

    針對本練習的目的,請特別注意下列幾點關於 Deployment 資訊清單的事項:

    • 屬於 Deployment 的每個 Pod 都有 greeting: hello 標籤。

    • 每個 Pod 都有兩個容器。

    • env 欄位指定 hello-app 容器監聽 TCP 通訊埠 50000,而 node-hello 容器監聽 TCP 通訊埠 8080。如要查看 PORT 環境變數的效果,請查看 hello-app原始碼

  2. 將資訊清單複製到名為 hello-deployment.yaml 的檔案。

  3. 建立 Deployment:

    kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-deployment.yaml
    

    CLUSTER_KUBECONFIG 替換為叢集的 kubeconfig 檔案名稱。

使用 Service 公開 Deployment

如要為用戶端提供穩定的方式,將要求傳送至 Deployment 的 Pod,請建立 Service:

  1. 建立 Service 資訊清單,向叢集內的用戶端公開 Deployment:

    apiVersion: v1
    kind: Service
    metadata:
      name: hello-service
    spec:
      type: ClusterIP
      selector:
        greeting: hello
      ports:
      - name: world-port
        protocol: TCP
        port: 60000
        targetPort: 50000
      - name: kubernetes-port
        protocol: TCP
        port: 60001
        targetPort: 8080
    
  2. 將資訊清單複製到名為 hello-service.yaml 的檔案。

  3. 建立 Service:

    kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-service.yaml
    

    CLUSTER_KUBECONFIG 替換為叢集的 kubeconfig 檔案名稱。

  4. 查看 Service:

    kubectl --kubeconfig CLUSTER_KUBECONFIG get service hello-service --output yaml
    

    輸出內容會顯示已指派給 Service 的 clusterIP 值。 例如:

    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        ...
    spec:
      clusterIP: 10.96.14.249
      clusterIPs:
      - 10.96.14.249
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - name: world-port
        port: 60000
        protocol: TCP
        targetPort: 50000
      - name: kubernetes-port
        port: 60001
        protocol: TCP
        targetPort: 8080
      selector:
        greeting: hello
      sessionAffinity: None
      type: ClusterIP
    status:
      loadBalancer: {}
    

    在上述輸出內容中,ports 欄位是 ServicePort 物件的陣列:一個名為 world-port,另一個名為 kubernetes-port。如要進一步瞭解 Service 欄位,請參閱 Kubernetes 說明文件中的 ServiceSpec

    用戶端呼叫服務的方式如下:

    • 使用 world-port在其中一個叢集節點上執行的用戶端會將要求傳送至 port 上的 clusterIP (例如 10.96.14.249:60000)。Ingress 控制器會將要求轉送至 targetPort 上的成員 Pod (例如 POD_IP_ADDRESS:50000,其中 POD_IP_ADDRESS 是成員 Pod 的 IP 位址)。

    • 使用 kubernetes-port:在其中一個叢集節點上執行的用戶端,會將要求傳送至 port 上的 clusterIP (10.96.14.249:60001)。Ingress 控制器會將要求轉送至 targetPort 上的成員 Pod (POD_IP_ADDRESS:8080)。

輸入元件

以下是與 Ingress 相關的叢集元件:

  • istio-ingress Deployment。這是連入 Proxy。Ingress Proxy 會根據 Ingress 物件中指定的規則,將流量轉送至內部服務。

  • istio-ingress 服務。這項 Service 會公開 istio-ingress Deployment。

  • istiod Deployment。這是 Ingress 控制器。輸入控制器會監控 Ingress 物件的建立作業,並據此設定輸入 Proxy。

所有這些叢內 Istio 元件都會安裝在 gke-system 命名空間中。這個命名空間不會與完整的 Istio/Cloud Service Mesh 安裝作業發生衝突。

建立 Ingress

請按照下列步驟建立 Ingress:

  1. 建立 Ingress 資訊清單:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-ingress
    spec:
      rules:
      - http:
          paths:
          - path: /greet-the-world
            pathType: Exact
            backend:
              service:
                name: hello-service
                port:
                  number: 60000
          - path: /greet-kubernetes
            pathType: Exact
            backend:
              service:
                name: hello-service
                port:
                  number: 60001
    
  2. 將資訊清單複製到名為 my-ingress.yaml 的檔案。

  3. 建立 Ingress:

    kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress.yaml
    

建立使用者叢集時,請在叢集設定檔中指定 loadbalancer.ingressVIP 的值。這個 IP 位址是在叢集負載平衡器上設定。建立 Ingress 時,系統會將這個 VIP 做為 Ingress 的外部 IP 位址。

當用戶端將要求傳送至使用者叢集 Ingress VIP 時,要求會轉送至負載平衡器。負載平衡器會使用 istio-ingress 服務將要求轉送至 Ingress Proxy,該 Proxy 會在使用者叢集中執行。Ingress Proxy 會根據要求網址中的路徑,將要求轉送至不同的後端。

/greet-the-world 路徑

在 Ingress 資訊清單中,您會看到路徑 /greet-the-worldserviceName: hello-serviceservicePort: 60000 相關聯的規則。請注意,60000 是服務 hello-serviceworld-port 區段中 port 的值。

- name: world-port
    port: 60000
    protocol: TCP
    targetPort: 50000

Ingress 服務會將要求轉送至 clusterIP:50000。要求接著會傳送至 hello-service Service 的其中一個成員 Pod。該 Pod 中監聽通訊埠 50000 的容器會顯示 Hello World! 訊息。

/greet-kubernetes 路徑

在 Ingress 資訊清單中,您會看到路徑 /greet-kubernetesserviceName: hello-serviceservicePort: 60001 相關聯的規則。請注意,60001 是 hello-service 服務的 kubernetes-port 區段中 port 的值。

- name: kubernetes-port
    port: 60001
    protocol: TCP
    targetPort: 8080

Ingress 服務會將要求轉送至 clusterIP: 8080。要求接著會傳送至 hello-service Service 的其中一個成員 Pod。該 Pod 中的容器會監聽通訊埠 8080,並顯示 Hello Kubernetes! 訊息。

測試 Ingress

  1. 使用 /greet-the-world 路徑測試 Ingress:

    curl CLUSTER_INGRESS_VIP/greet-the-world
    

    CLUSTER_INGRESS_VIP 替換為 Ingress 的外部 IP 位址。

    輸出結果會顯示一則 Hello, world! 訊息:

    Hello, world!
    Version: 2.0.0
    Hostname: ...
    
  2. 使用 /greet-kubernetes 路徑測試 Ingress:

    curl CLUSTER_INGRESS_VIP/greet-kubernetes
    

    輸出結果會顯示一則 Hello, Kubernetes! 訊息:

    Hello Kubernetes!
    

停用隨附 Ingress

Google Distributed Cloud 隨附的 Ingress 功能僅支援 Ingress 功能。您可以選擇與 IstioCloud Service Mesh 整合。這些產品提供功能齊全的服務網格,可帶來更多優勢,例如相互傳輸層安全 (mTLS)、管理服務間驗證的能力,以及工作負載可觀測性。如果您整合 Istio 或 Cloud Service Mesh,建議停用套裝組合的 Ingress 功能。

您可以使用叢集設定檔中的 spec.clusterNetwork.bundledIngress 欄位,啟用或停用套裝 Ingress。這個欄位僅適用於 1.13.0 以上版本的叢集。bundledIngress 欄位預設為 true,且不會出現在產生的叢集設定檔中。這個欄位可變動,您可以在建立或更新 1.13.0 以上版本的叢集時變更。

  • 如要停用隨附的 Ingress 功能,請將 bundledIngress 欄位新增至叢集設定檔的 clusterNetwork 區段,並將值設為 false,如下例所示:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: cluster-hybrid-basic
    ---
    apiVersion: baremetal.cluster.gke.io/v1
    kind: Cluster
    metadata:
      name: hybrid-basic
      namespace: cluster-hybrid-basic
    spec:
      type: hybrid
      profile: default
      anthosBareMetalVersion: 1.13.0
      gkeConnect:
        projectID: project-fleet
      controlPlane:
        nodePoolSpec:
          nodes:
          - address: 10.200.0.2
      clusterNetwork:
        bundledIngress: false
        pods:
          cidrBlocks:
          - 192.168.0.0/16
        services:
          cidrBlocks:
          - 10.96.0.0/20
    ...
    

為 Ingress 設定 HTTPS

如果要接受來自用戶端的 HTTPS 要求,Ingress Proxy 必須要有憑證,以向用戶端證明其身分。這個 Proxy 也必須要有私密金鑰才能完成 HTTPS 握手。

以下範例使用這些實體:

  • Ingress Proxy:參與 HTTPS 交握,然後將封包轉送至 hello-service 服務的成員 Pod。

  • hello-service 服務的網域:Example Org 中的 altostrat.com

步驟如下:

  1. 建立根憑證和私密金鑰。本範例在 Root CA Example Org 中使用 root.ca.example.com 的根憑證授權單位。

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj \
        '/O=Root CA Example Inc./CN=root.ca.example.com' -keyout root-ca.key \
        -out root-ca.crt
    
  2. 建立憑證簽署要求:

     openssl req -out server.csr -newkey rsa:2048 -nodes -keyout server.key -subj \
         "/CN=altostrat.com/O=Example Org"
    
  3. 為 Ingress Proxy 建立服務憑證。

    openssl x509 -req -days 365 -CA root-ca.crt -CAkey root-ca.key -set_serial 0 \
        -in server.csr -out server.crt
    

    您現在已建立下列憑證和金鑰:

    • root-ca.crt:根 CA 的憑證
    • root-ca.key:根 CA 的私密金鑰
    • server.crt:Ingress Proxy 的服務憑證
    • server.key:Ingress 代理伺服器的私密金鑰
  4. 建立包含服務憑證和金鑰的 Kubernetes 密鑰。

    kubectl create secret tls example-server-creds --key=server.key --cert=server.crt \
        --namespace gke-system
    

    產生的 Secret 名為 example-server-creds

建立 Deployment 和 Service

如果您在本指南的 HTTP 部分中建立部署和服務,請保留這些項目。如果沒有,請按照 HTTP 的步驟建立。

建立 Ingress

為 HTTPS 建立 Ingress 的方式與為 HTTP 建立 Ingress 類似,但 HTTPS 的 Ingress 規格包含 tls 區段,用於指定主機和密鑰。tls 部分的 hosts 必須與 rules 部分的 host 完全相符。

如果後端服務位於不同的命名空間,您需要在與 Ingress 相同的命名空間中,建立 ExternalName 類型的服務,將流量路由至後端服務。

建立 HTTPS 或 HTTP 輸入資源的整體步驟相同,但資訊清單檔案中的設定有所不同:

  1. 如果您先前在本文件的 HTTP 部分建立 Ingress,請先刪除該 Ingress 再繼續操作。

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress my-ingress
    
  2. 如要處理先前建立的服務流量,請建立含有 tls 區段的新 Ingress 資訊清單:

    tls 設定可啟用用戶端與 Ingress Proxy 之間的 HTTPS。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-ingress-2
    spec:
      tls:
      - hosts:
        - altostrat.com
        secretName: example-server-creds
      rules:
      - host: altostrat.com
        http:
          paths:
          - path: /greet-the-world
            pathType: Exact
            backend:
              service:
                name: hello-service
                port:
                  number: 60000
          - path: /greet-kubernetes
            pathType: Exact
            backend:
              service:
                name: hello-service
                port:
                  number: 60001
    
  3. 將資訊清單儲存到名為 my-ingress-2.yaml 的檔案,然後建立 Ingress:

    kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress-2.yaml
    
  4. 測試並確認 Ingress 已建立且正常運作:

    • 測試 /greet-the-world 路徑:

      curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP \
          https://altostrat.com/greet-the-world \
          --cacert root-ca.crt
      

      輸出:

      Hello, world!
      Version: 2.0.0
      Hostname: hello-deployment-5ff7f68854-wqzp7
      
    • 測試 /greet-kubernetes 路徑:

      curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP \
          https://altostrat.com/greet-kubernetes --cacert root-ca.crt
      

      輸出:

      Hello Kubernetes!
      

建立 LoadBalancer 服務

類型為 LoadBalancer 的 Service 是另一種將工作負載公開發布至叢集外部的方式。如需建立 LoadBalancer 類型服務的操作說明和範例,請參閱「在部署應用程式中建立 LoadBalancer 類型的服務」。

正在清除所用資源

  1. 刪除 Ingress:

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress INGRESS_NAME
    

    INGRESS_NAME 替換為 Ingress 的名稱,例如 my-ingressmy-ingress-2

  2. 刪除服務:

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete service hello-service
    
  3. 刪除部署作業:

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete deployment hello-deployment
    
  4. 刪除 LoadBalancer 服務:

    kubectl --kubeconfig CLUSTER_KUBECONFIG delete service service-does-not-use-nodeports