用於出口流量的 Kubernetes 服務

Kubernetes 的 ExternalName 服務以及具有 端點 (Endpoints) 的 Kubernetes 服務,可讓您建立指向外部服務的本機 DNS別名。此 DNS 別名與本機服務的 DNS 條目形式相同,即 <服務名稱>.<命名空間名稱>.svc.cluster.local。DNS 別名為您的工作負載提供位置透明性:工作負載可以相同的方式呼叫本機和外部服務。如果您在某個時間點決定在叢集內部署外部服務,您可以直接更新其 Kubernetes 服務以參考本機版本。工作負載將繼續運行,而無需進行任何更改。

此任務顯示這些用於存取外部服務的 Kubernetes 機制在 Istio 中仍然有效。您必須執行的唯一配置步驟是使用 Istio 的 雙向 TLS 以外的 TLS 模式。外部服務不屬於 Istio 服務網格,因此它們無法執行 Istio 的雙向 TLS。您必須根據外部服務的 TLS 要求以及工作負載存取外部服務的方式來設定 TLS 模式。如果您的工作負載發出普通的 HTTP 請求,而外部服務需要 TLS,您可能希望由 Istio 執行 TLS 發起 (origination)。如果您的工作負載已經使用 TLS,則流量已經加密,您可以直接停用 Istio 的雙向 TLS。

雖然此任務中的範例使用 HTTP 協定,但用於出口流量的 Kubernetes 服務也適用於其他協定。

開始之前

  • 請依照安裝指南中的指示設定 Istio。

  • 部署 curl 範例應用程式,作為發送請求的測試來源。如果您已啟用自動 Sidecar 注入,請執行以下命令來部署範例應用程式

    Zip
    $ kubectl apply -f @samples/curl/curl.yaml@
    

    否則,請在部署 curl 應用程式之前,使用以下命令手動注入 Sidecar

    Zip
    $ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@)
    
  • SOURCE_POD 環境變數設定為您的來源 Pod 的名稱

    $ export SOURCE_POD=$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})
    
  • 建立一個不使用 Istio 控制的來源 Pod 的命名空間

    $ kubectl create namespace without-istio
    
  • without-istio 命名空間中啟動 curl 範例。

    Zip
    $ kubectl apply -f @samples/curl/curl.yaml@ -n without-istio
    
  • 若要發送請求,請建立 SOURCE_POD_WITHOUT_ISTIO 環境變數以儲存來源 Pod 的名稱

    $ export SOURCE_POD_WITHOUT_ISTIO="$(kubectl get pod -n without-istio -l app=curl -o jsonpath={.items..metadata.name})"
    
  • 確認 Istio Sidecar 未被注入,也就是說,該 Pod 只有一個容器

    $ kubectl get pod "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio
    NAME                     READY   STATUS    RESTARTS   AGE
    curl-66c8d79ff5-8tqrl    1/1     Running   0          32s
    

Kubernetes ExternalName 服務以存取外部服務

  1. 在預設命名空間中為 httpbin.org 建立 Kubernetes ExternalName 服務

    $ kubectl apply -f - <<EOF
    kind: Service
    apiVersion: v1
    metadata:
      name: my-httpbin
    spec:
      type: ExternalName
      externalName: httpbin.org
      ports:
      - name: http
        protocol: TCP
        port: 80
    EOF
    
  2. 觀察您的服務。請注意,它沒有叢集 IP。

    $ kubectl get svc my-httpbin
    NAME         TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    my-httpbin   ExternalName   <none>       httpbin.org   80/TCP    4s
    
  3. 從沒有 Istio Sidecar 的來源 Pod,透過 Kubernetes 服務的主機名稱存取 httpbin.org。請注意,下面的 curl 命令使用服務的 Kubernetes DNS 格式<服務名稱>.<命名空間>.svc.cluster.local

    $ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers
    {
      "headers": {
        "Accept": "*/*",
        "Host": "my-httpbin.default.svc.cluster.local",
        "User-Agent": "curl/7.55.0"
      }
    }
    
  4. 在此範例中,未加密的 HTTP 請求會傳送至 httpbin.org。為了方便說明範例,您停用 TLS 模式,並允許未加密的流量傳送至外部服務。在真實場景中,我們建議由 Istio 執行出口 TLS 發起 (origination)

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: DestinationRule
    metadata:
      name: my-httpbin
    spec:
      host: my-httpbin.default.svc.cluster.local
      trafficPolicy:
        tls:
          mode: DISABLE
    EOF
    
  5. 從具有 Istio Sidecar 的來源 Pod,透過 Kubernetes 服務的主機名稱存取 httpbin.org。請注意由 Istio Sidecar 新增的標頭,例如 X-Envoy-Peer-Metadata。另請注意,Host 標頭等於您服務的主機名稱。

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers
    {
      "headers": {
        "Accept": "*/*",
        "Content-Length": "0",
        "Host": "my-httpbin.default.svc.cluster.local",
        "User-Agent": "curl/7.64.0",
        "X-B3-Sampled": "0",
        "X-B3-Spanid": "5795fab599dca0b8",
        "X-B3-Traceid": "5079ad3a4af418915795fab599dca0b8",
        "X-Envoy-Peer-Metadata": "...",
        "X-Envoy-Peer-Metadata-Id": "sidecar~10.28.1.74~curl-6bdb595bcb-drr45.default~default.svc.cluster.local"
      }
    }
    

清理 Kubernetes ExternalName 服務

$ kubectl delete destinationrule my-httpbin
$ kubectl delete service my-httpbin

使用具有端點的 Kubernetes 服務以存取外部服務

  1. 為 Wikipedia 建立不帶選取器的 Kubernetes 服務

    $ kubectl apply -f - <<EOF
    kind: Service
    apiVersion: v1
    metadata:
      name: my-wikipedia
    spec:
      ports:
      - protocol: TCP
        port: 443
        name: tls
    EOF
    
  2. 為您的服務建立端點。從Wikipedia 範圍列表中選取幾個 IP。

    $ kubectl apply -f - <<EOF
    kind: Endpoints
    apiVersion: v1
    metadata:
      name: my-wikipedia
    subsets:
      - addresses:
          - ip: 198.35.26.96
          - ip: 208.80.153.224
        ports:
          - port: 443
            name: tls
    EOF
    
  3. 觀察您的服務。請注意,它有一個叢集 IP,您可以使用該 IP 存取 wikipedia.org

    $ kubectl get svc my-wikipedia
    NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
    my-wikipedia   ClusterIP   172.21.156.230   <none>        443/TCP   21h
    
  4. 從沒有 Istio Sidecar 的來源 Pod,透過 Kubernetes 服務的叢集 IP 發送 HTTPS 請求至 wikipedia.org。使用 curl--resolve 選項,透過叢集 IP 存取 wikipedia.org

    $ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"
    <title>Wikipedia, the free encyclopedia</title>
    
  5. 在此案例中,工作負載會傳送 HTTPS 請求(開啟 TLS 連線)至 wikipedia.org。流量已由工作負載加密,因此您可以安全地停用 Istio 的雙向 TLS

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: DestinationRule
    metadata:
      name: my-wikipedia
    spec:
      host: my-wikipedia.default.svc.cluster.local
      trafficPolicy:
        tls:
          mode: DISABLE
    EOF
    
  6. 從具有 Istio Sidecar 的來源 Pod,透過 Kubernetes 服務的叢集 IP 存取 wikipedia.org

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"
    <title>Wikipedia, the free encyclopedia</title>
    
  7. 檢查存取是否確實由叢集 IP 執行。請注意 curl -v 輸出中的句子 Connected to en.wikipedia.org (172.21.156.230),其中提到了在您的服務輸出中印出的叢集 IP。

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS -v --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page -o /dev/null
    * Added en.wikipedia.org:443:172.21.156.230 to DNS cache
    * Hostname en.wikipedia.org was found in DNS cache
    *   Trying 172.21.156.230...
    * TCP_NODELAY set
    * Connected to en.wikipedia.org (172.21.156.230) port 443 (#0)
    ...
    

清理具有端點的 Kubernetes 服務

$ kubectl delete destinationrule my-wikipedia
$ kubectl delete endpoints my-wikipedia
$ kubectl delete service my-wikipedia

清理

  1. 關閉 curl 服務

    Zip
    $ kubectl delete -f @samples/curl/curl.yaml@
    
  2. 關閉 without-istio 命名空間中的 curl 服務

    Zip
    $ kubectl delete -f @samples/curl/curl.yaml@ -n without-istio
    
  3. 刪除 without-istio 命名空間

    $ kubectl delete namespace without-istio
    
  4. 取消設定環境變數

    $ unset SOURCE_POD SOURCE_POD_WITHOUT_ISTIO
    
此資訊是否有用?
您有任何改進建議嗎?

感謝您的回饋!