存取外部服務

因為預設情況下,所有來自啟用 Istio 的 Pod 的出站流量都會被重新導向到其 Sidecar 代理,因此叢集外部 URL 的可存取性取決於代理的設定。預設情況下,Istio 會將 Envoy 代理設定為將對未知服務的請求直通。雖然這提供了一種方便的方式來開始使用 Istio,但通常最好設定更嚴格的控制。

此任務將向您展示如何透過三種不同的方式存取外部服務

  1. 允許 Envoy 代理將請求直通到網格內部未設定的服務。
  2. 設定 服務條目,以提供對外部服務的受控存取。
  3. 完全繞過特定 IP 範圍的 Envoy 代理。

開始之前

  • 依照安裝指南中的說明設定 Istio。使用 demo 設定檔,或以其他方式啟用 Envoy 的存取日誌

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

    壓縮
    $ kubectl apply -f @samples/curl/curl.yaml@
    

    否則,請先手動注入 Sidecar,然後使用以下命令部署 curl 應用程式

    壓縮
    $ 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}')
    

Envoy 直通外部服務

Istio 有一個安裝選項 meshConfig.outboundTrafficPolicy.mode,可設定 Sidecar 如何處理外部服務,也就是 Istio 內部服務註冊表中未定義的服務。如果此選項設定為 ALLOW_ANY,則 Istio 代理會允許對未知服務的呼叫直通。如果此選項設定為 REGISTRY_ONLY,則 Istio 代理會封鎖任何在網格中沒有定義 HTTP 服務或服務條目的主機。ALLOW_ANY 是預設值,可讓您快速開始評估 Istio,而無需控制對外部服務的存取。然後,您可以決定稍後設定對外部服務的存取

  1. 若要查看此方法的實際運作方式,您需要確保 Istio 安裝設定為將 meshConfig.outboundTrafficPolicy.mode 選項設定為 ALLOW_ANY。除非您在安裝 Istio 時明確將其設定為 REGISTRY_ONLY 模式,否則它可能預設為啟用。

    如果您不確定,可以執行以下命令來顯示您的網格設定

    $ kubectl get configmap istio -n istio-system -o yaml
    

    除非您看到明確設定 meshConfig.outboundTrafficPolicy.mode 的值為 REGISTRY_ONLY,否則您可以確定該選項設定為 ALLOW_ANY,這是唯一其他可能的值,也是預設值。

  2. SOURCE_POD 向外部 HTTPS 服務發出幾個請求,以確認成功的回應 200

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sSI https://www.google.com | grep  "HTTP/"; kubectl exec "$SOURCE_POD" -c curl -- curl -sI https://edition.cnn.com | grep "HTTP/"
    HTTP/2 200
    HTTP/2 200
    

恭喜!您已成功從網格傳送輸出流量。

這種存取外部服務的簡單方法有一個缺點,即您會失去對外部服務流量的 Istio 監控和控制。下一節將說明如何監控和控制您的網格對外部服務的存取。

受控存取外部服務

使用 Istio ServiceEntry 設定,您可以從 Istio 叢集內存取任何可公開存取的服務。本節將說明如何在不失去 Istio 的流量監控和控制功能的情況下,設定對外部 HTTP 服務 httpbin.org 以及外部 HTTPS 服務 www.google.com 的存取。

變更預設封鎖原則

為了示範啟用對外部服務的受控方式,您需要將 meshConfig.outboundTrafficPolicy.mode 選項從 ALLOW_ANY 模式變更為 REGISTRY_ONLY 模式。

  1. meshConfig.outboundTrafficPolicy.mode 選項變更為 REGISTRY_ONLY

    如果您使用 IstioOperator CR 安裝 Istio,請將以下欄位新增至您的設定

    spec:
      meshConfig:
        outboundTrafficPolicy:
          mode: REGISTRY_ONLY
    

    否則,請將對等的設定新增至您的原始 istioctl install 命令,例如

    $ istioctl install <flags-you-used-to-install-Istio> \
                       --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY
    
  2. SOURCE_POD 向外部 HTTPS 服務發出幾個請求,以驗證它們現在是否被封鎖

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sI https://www.google.com | grep  "HTTP/"; kubectl exec "$SOURCE_POD" -c curl -- curl -sI https://edition.cnn.com | grep "HTTP/"
    command terminated with exit code 35
    command terminated with exit code 35
    

存取外部 HTTP 服務

  1. 建立 ServiceEntry 以允許存取外部 HTTP 服務。

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: ServiceEntry
    metadata:
      name: httpbin-ext
    spec:
      hosts:
      - httpbin.org
      ports:
      - number: 80
        name: http
        protocol: HTTP
      resolution: DNS
      location: MESH_EXTERNAL
    EOF
    
  2. SOURCE_POD 向外部 HTTP 服務發出請求

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS http://httpbin.org/headers
    {
      "headers": {
        "Accept": "*/*",
        "Host": "httpbin.org",
        ...
        "X-Envoy-Decorator-Operation": "httpbin.org:80/*",
        ...
      }
    }
    

    請注意 Istio Sidecar 代理新增的標頭:X-Envoy-Decorator-Operation

  3. 檢查 SOURCE_POD 的 Sidecar 代理的日誌

    $ kubectl logs "$SOURCE_POD" -c istio-proxy | tail
    [2019-01-24T12:17:11.640Z] "GET /headers HTTP/1.1" 200 - 0 599 214 214 "-" "curl/7.60.0" "17fde8f7-fa62-9b39-8999-302324e6def2" "httpbin.org" "35.173.6.94:80" outbound|80||httpbin.org - 35.173.6.94:80 172.30.109.82:55314 -
    

    請注意與您對 httpbin.org/headers 的 HTTP 請求相關的條目。

存取外部 HTTPS 服務

  1. 建立 ServiceEntry 以允許存取外部 HTTPS 服務。

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: ServiceEntry
    metadata:
      name: google
    spec:
      hosts:
      - www.google.com
      ports:
      - number: 443
        name: https
        protocol: HTTPS
      resolution: DNS
      location: MESH_EXTERNAL
    EOF
    
  2. SOURCE_POD 向外部 HTTPS 服務發出請求

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sSI https://www.google.com | grep  "HTTP/"
    HTTP/2 200
    
  3. 檢查 SOURCE_POD 的 Sidecar 代理的日誌

    $ kubectl logs "$SOURCE_POD" -c istio-proxy | tail
    [2019-01-24T12:48:54.977Z] "- - -" 0 - 601 17766 1289 - "-" "-" "-" "-" "172.217.161.36:443" outbound|443||www.google.com 172.30.109.82:59480 172.217.161.36:443 172.30.109.82:59478 www.google.com
    

    請注意與您對 www.google.com 的 HTTPS 請求相關的條目。

管理外部服務的流量

與叢集間請求類似,也可以為使用 ServiceEntry 設定存取的外部服務設定路由規則。在此範例中,您在對 httpbin.org 服務的呼叫上設定逾時規則。

  1. 從用作測試來源的 Pod 內部,向 httpbin.org 外部服務的 /delay 端點發出 curl 請求

    $ kubectl exec "$SOURCE_POD" -c curl -- time curl -o /dev/null -sS -w "%{http_code}\n" http://httpbin.org/delay/5
    200
    real    0m5.024s
    user    0m0.003s
    sys     0m0.003s
    

    請求應在大約 5 秒內傳回 200 (OK)。

  2. 使用 kubectl 在對 httpbin.org 外部服務的呼叫上設定 3 秒逾時

$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: httpbin-ext
spec:
  hosts:
  - httpbin.org
  http:
  - timeout: 3s
    route:
    - destination:
        host: httpbin.org
      weight: 100
EOF
  1. 等待幾秒鐘,然後再次發出 curl 請求

    $ kubectl exec "$SOURCE_POD" -c curl -- time curl -o /dev/null -sS -w "%{http_code}\n" http://httpbin.org/delay/5
    504
    real    0m3.149s
    user    0m0.004s
    sys     0m0.004s
    

    這次在 3 秒後出現 504 (Gateway Timeout)。儘管 httpbin.org 等待了 5 秒,但 Istio 在 3 秒時切斷了請求。

清除受控存取外部服務

$ kubectl delete serviceentry httpbin-ext google
$ kubectl delete virtualservice httpbin-ext --ignore-not-found=true

直接存取外部服務

如果您想完全繞過特定 IP 範圍的 Istio,您可以設定 Envoy Sidecar,以防止它們攔截外部請求。若要設定繞過,請變更 global.proxy.includeIPRangesglobal.proxy.excludeIPRanges 設定選項,並使用 kubectl apply 命令更新 istio-sidecar-injector 設定映射。這也可以在 Pod 上透過設定對應的註釋(例如 traffic.sidecar.istio.io/includeOutboundIPRanges)來設定。更新 istio-sidecar-injector 設定後,它會影響未來的所有應用程式 Pod 部署。

從 Sidecar 代理重新導向排除所有外部 IP 的簡單方法是將 global.proxy.includeIPRanges 設定選項設定為用於內部叢集服務的 IP 範圍。這些 IP 範圍值取決於執行叢集的平台。

確定您平台的內部 IP 範圍

根據您的叢集提供者設定 values.global.proxy.includeIPRanges 的值。

IBM Cloud Private

  1. cluster/config.yaml 下的 IBM Cloud Private 設定檔取得您的 service_cluster_ip_range

    $ grep service_cluster_ip_range cluster/config.yaml
    

    以下是範例輸出

    service_cluster_ip_range: 10.0.0.1/24
    
  2. 使用 --set values.global.proxy.includeIPRanges="10.0.0.1/24"

IBM Cloud Kubernetes Service

要查看叢集中使用的 CIDR,請使用 ibmcloud ks cluster get -c <叢集名稱> 並尋找 Service Subnet

$ ibmcloud ks cluster get -c my-cluster | grep "Service Subnet"
Service Subnet:                 172.21.0.0/16

然後使用 --set values.global.proxy.includeIPRanges="172.21.0.0/16"

Google Kubernetes Engine (GKE)

這些範圍不是固定的,因此您需要執行 gcloud container clusters describe 命令來確定要使用的範圍。例如:

$ gcloud container clusters describe XXXXXXX --zone=XXXXXX | grep -e clusterIpv4Cidr -e servicesIpv4Cidr
clusterIpv4Cidr: 10.4.0.0/14
servicesIpv4Cidr: 10.7.240.0/20

使用 --set values.global.proxy.includeIPRanges="10.4.0.0/14\,10.7.240.0/20"

Azure Kubernetes Service (AKS)

Kubenet

要查看叢集中使用的服務 CIDR 和 Pod CIDR,請使用 az aks show 並尋找 serviceCidr

$ az aks show --resource-group "${RESOURCE_GROUP}" --name "${CLUSTER}" | grep Cidr
    "podCidr": "10.244.0.0/16",
    "podCidrs": [
    "serviceCidr": "10.0.0.0/16",
    "serviceCidrs": [

然後使用 --set values.global.proxy.includeIPRanges="10.244.0.0/16\,10.0.0.0/16"

Azure CNI

如果您使用非覆蓋網路模式的 Azure CNI,請按照這些步驟操作。如果使用覆蓋網路的 Azure CNI,請按照Kubenet 指示操作。如需更多資訊,請參閱Azure CNI Overlay 文件

要查看叢集中使用的服務 CIDR,請使用 az aks show 並尋找 serviceCidr

$ az aks show --resource-group "${RESOURCE_GROUP}" --name "${CLUSTER}" | grep serviceCidr
    "serviceCidr": "10.0.0.0/16",
    "serviceCidrs": [

要查看叢集中使用的 Pod CIDR,請使用 az CLI 檢查 vnet

$ az aks show --resource-group "${RESOURCE_GROUP}" --name "${CLUSTER}" | grep nodeResourceGroup
  "nodeResourceGroup": "MC_user-rg_user-cluster_region",
  "nodeResourceGroupProfile": null,
$ az network vnet list -g MC_user-rg_user-cluster_region | grep name
    "name": "aks-vnet-74242220",
        "name": "aks-subnet",
$ az network vnet show -g MC_user-rg_user-cluster_region -n aks-vnet-74242220 | grep addressPrefix
    "addressPrefixes": [
      "addressPrefix": "10.224.0.0/16",

然後使用 --set values.global.proxy.includeIPRanges="10.244.0.0/16\,10.0.0.0/16"

Minikube、Docker For Desktop、裸機

預設值為 10.96.0.0/12,但它不是固定的。使用以下命令確定您的實際值:

$ kubectl describe pod kube-apiserver -n kube-system | grep 'service-cluster-ip-range'
      --service-cluster-ip-range=10.96.0.0/12

使用 --set values.global.proxy.includeIPRanges="10.96.0.0/12"

設定代理繞過

使用您平台特定的 IP 範圍更新您的 istio-sidecar-injector 設定映射。例如,如果範圍是 10.0.0.1/24,請使用以下命令:

$ istioctl install <flags-you-used-to-install-Istio> --set values.global.proxy.includeIPRanges="10.0.0.1/24"

使用您用來安裝 Istio 的相同命令,並新增 --set values.global.proxy.includeIPRanges="10.0.0.1/24"

存取外部服務

由於繞過設定僅影響新的部署,您需要依照開始之前章節中的描述,終止然後重新部署 curl 應用程式。

更新 istio-sidecar-injector 設定映射並重新部署 curl 應用程式後,Istio sidecar 將只攔截並管理叢集內的內部請求。任何外部請求都會繞過 sidecar 並直接前往其預定的目的地。例如:

$ kubectl exec "$SOURCE_POD" -c curl -- curl -sS http://httpbin.org/headers
{
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    ...
  }
}

與透過 HTTP 或 HTTPS 存取外部服務不同,您不會看到任何與 Istio sidecar 相關的標頭,而且傳送到外部服務的請求不會出現在 sidecar 的日誌中。繞過 Istio sidecar 意味著您無法再監控對外部服務的存取。

清除直接存取外部服務

更新設定以停止繞過一系列 IP 的 sidecar 代理。

$ istioctl install <flags-you-used-to-install-Istio>

了解發生的狀況

在本任務中,您了解了從 Istio 網格呼叫外部服務的三種方式。

  1. 設定 Envoy 以允許存取任何外部服務。

  2. 使用服務條目在網格內註冊可存取的外部服務。這是建議的方法。

  3. 設定 Istio sidecar,使其在重新對應的 IP 表格中排除外部 IP。

第一種方法會將流量導向 Istio sidecar 代理,包括呼叫網格內未知的服務。使用此方法時,您無法監控對外部服務的存取,也無法利用 Istio 的流量控制功能。若要輕鬆地將特定服務切換到第二種方法,只需為這些外部服務建立服務條目即可。此過程可讓您最初存取任何外部服務,然後再決定是否要控制存取、啟用流量監控並根據需要使用流量控制功能。

第二種方法可讓您將所有相同的 Istio 服務網格功能用於呼叫叢集內或外部的服務。在本任務中,您學習了如何監控對外部服務的存取,並為呼叫外部服務設定逾時規則。

第三種方法會繞過 Istio sidecar 代理,讓您的服務可以直接存取任何外部伺服器。但是,以這種方式設定代理需要了解特定叢集提供者知識和組態。與第一種方法類似,您也會失去對外部服務存取的監控,而且您無法將 Istio 功能應用於外部服務的流量。

安全性注意事項

若要以更安全的方式實作出口流量控制,您必須將出口流量導向出口閘道,並檢閱其他安全性考量章節中描述的安全性問題。

清理

關閉curl 服務。

壓縮
$ kubectl delete -f @samples/curl/curl.yaml@
此資訊是否有用?
您是否有任何改進建議?

感謝您的回饋!