本文說明如何在 Google Distributed Cloud 的使用者叢集中,建立 Kubernetes Ingress 物件。Ingress 會與一或多個服務建立關聯,而每個服務都會與一組 Pod 建立關聯。
事前準備
取得管理工作站的 SSH 連線:
可建立部署作業
以下是部署的資訊清單。
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。如要查看- hello-app環境變數的效果,請查看 hello-app 原始碼。- PORT
將資訊清單複製到名為「hello-deployment.yaml」的檔案,然後建立 Deployment:
kubectl apply --kubeconfig USER_CLUSTER_KUBECONFIG -f hello-deployment.yaml
其中 USER_CLUSTER_KUBECONFIG 是指使用者叢集的 kubeconfig 檔案路徑。
使用 Service 公開 Deployment
如要為用戶端提供穩定的方式,將要求傳送至 Deployment 的 Pod,請建立 Service。
以下是 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
將資訊清單儲存到名為「hello-service.yaml」的檔案,然後建立 Service:
kubectl apply --kubeconfig USER_CLUSTER_KUBECONFIG -f hello-service.yaml
查看 Service:
kubectl --kubeconfig USER_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 欄位是 Kubernetes ServicePort 物件的陣列:一個名為 world-port,另一個名為 kubernetes-port。
用戶端呼叫服務的方式如下:
- 使用 - world-port:在其中一個叢集節點上執行的用戶端會將要求傳送至- port上的- clusterIP。在本範例中,為 10.96.14.249:60000。 要求會轉送至- targetPort上的成員 Pod。在本範例中,POD_IP_ADDRESS:50000。
- 使用 - kubernetes-port:在其中一個叢集節點上執行的用戶端會將要求傳送至- port上的- clusterIP。在本範例中,靜態位址為 10.96.14.249:60001。要求會轉送至- targetPort上的成員 Pod。在本範例中,POD_IP_ADDRESS:8080。
輸入元件
以下是與 Ingress 相關的叢集元件:
- istio-ingress部署作業。這是連入 Proxy。Ingress Proxy 會根據 Ingress 物件中指定的規則,將流量轉送至內部服務。
- istio-ingress服務。這項 Service 會公開- istio-ingressDeployment。
- istiod部署作業。這是 Ingress 控制器。輸入控制器會監控 Ingress 物件的建立作業,並據此設定輸入 Proxy。
建立 Ingress
以下是 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
將資訊清單複製到名為「my-ingress.yaml」的檔案,然後建立 Ingress:
kubectl apply --kubeconfig USER_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-world 與 serviceName: hello-service 和 servicePort: 60000 相關聯。請注意,60000 是服務 hello-service 的 world-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-kubernetes 與 serviceName: hello-service 和 servicePort: 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
使用 /greet-the-world 路徑測試 Ingress:
curl USER_CLUSTER_INGRESS_VIP/greet-the-world
將 USER_CLUSTER_INGRESS_VIP 替換為 Ingress 的外部 IP 位址。
輸出結果會顯示一則 Hello, world! 訊息:
Hello, world! Version: 2.0.0 Hostname: ...
使用 /greet-kubernetes 路徑測試 Ingress:
curl USER_CLUSTER_INGRESS_VIP/greet-kubernetes
輸出結果會顯示一則 Hello, Kubernetes! 訊息:
Hello Kubernetes!
為 Ingress 設定 HTTPS
如果要接受來自用戶端的 HTTPS 要求,Ingress Proxy 必須要有憑證,以向用戶端證明其身分。這個 Proxy 也必須要有私密金鑰才能完成 HTTPS 握手。
以下範例使用這些實體:
- Ingress Proxy:參與 HTTPS 交握,然後將封包轉送至 - hello-serviceService 的成員 Pod。
- hello-service服務的網域:Example Org 中的 altostrat.com
步驟如下:
- 建立根憑證和私密金鑰。本範例在 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 
- 建立憑證簽署要求: - openssl req -out server.csr -newkey rsa:2048 -nodes -keyout server.key -subj "/CN=altostrat.com/O=Example Org" 
- 為 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 代理伺服器的服務憑證
- server.key:Ingress 代理伺服器的私密金鑰
 
- 建立包含服務憑證和金鑰的 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 類型的服務,將流量路由至後端服務。
如果您先前在 HTTP 部分建立了 Ingress,請先刪除該 Ingress 再繼續操作。
刪除 Ingress:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete ingress my-ingress
如要處理先前建立的 Service 流量,請建立具有 tls 區段的新 Ingress。這樣一來,用戶端與 Ingress Proxy 之間就會啟用 HTTPS。
以下是 Ingress 的資訊清單:
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
將資訊清單儲存到名為 my-ingress-2.yaml 的檔案,然後建立 Ingress:
kubectl apply --kubeconfig USER_CLUSTER_KUBECONFIG -f my-ingress-2.yaml
測試以確認。
- 測試 /greet-the-world 路徑: - curl -v --resolve altostrat.com:443:USER_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:USER_CLUSTER_INGRESS_VIP https://altostrat.com/greet-kubernetes --cacert root-ca.crt - 輸出: - Hello Kubernetes! 
正在清除所用資源
刪除 Ingress:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete ingress INGRESS_NAME
將 INGRESS_NAME 替換為 Ingress 的名稱,例如 my-ingress 或 my-ingress-2。
刪除服務:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete service hello-service
刪除部署作業:
kubectl --kubeconfig USER_CLUSTER_KUBECONFIG delete deployment hello-deployment