存取外部服務
因為預設情況下,所有來自啟用 Istio 的 Pod 的出站流量都會被重新導向到其 Sidecar 代理,因此叢集外部 URL 的可存取性取決於代理的設定。預設情況下,Istio 會將 Envoy 代理設定為將對未知服務的請求直通。雖然這提供了一種方便的方式來開始使用 Istio,但通常最好設定更嚴格的控制。
此任務將向您展示如何透過三種不同的方式存取外部服務
- 允許 Envoy 代理將請求直通到網格內部未設定的服務。
- 設定 服務條目,以提供對外部服務的受控存取。
- 完全繞過特定 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,而無需控制對外部服務的存取。然後,您可以決定稍後設定對外部服務的存取。
若要查看此方法的實際運作方式,您需要確保 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
,這是唯一其他可能的值,也是預設值。從
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
模式。
將
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
從
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 服務
建立
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
從
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
。檢查
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 服務
建立
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
從
SOURCE_POD
向外部 HTTPS 服務發出請求$ kubectl exec "$SOURCE_POD" -c curl -- curl -sSI https://www.google.com | grep "HTTP/" HTTP/2 200
檢查
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
服務的呼叫上設定逾時規則。
從用作測試來源的 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)。
使用
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
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin-ext
spec:
parentRefs:
- kind: ServiceEntry
group: networking.istio.io
name: httpbin-ext
hostnames:
- httpbin.org
rules:
- timeouts:
request: 3s
backendRefs:
- kind: Hostname
group: networking.istio.io
name: httpbin.org
port: 80
EOF
等待幾秒鐘,然後再次發出 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
$ kubectl delete serviceentry httpbin-ext
$ kubectl delete httproute httpbin-ext --ignore-not-found=true
直接存取外部服務
如果您想完全繞過特定 IP 範圍的 Istio,您可以設定 Envoy Sidecar,以防止它們攔截外部請求。若要設定繞過,請變更 global.proxy.includeIPRanges
或 global.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
從
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
使用
--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 網格呼叫外部服務的三種方式。
設定 Envoy 以允許存取任何外部服務。
使用服務條目在網格內註冊可存取的外部服務。這是建議的方法。
設定 Istio sidecar,使其在重新對應的 IP 表格中排除外部 IP。
第一種方法會將流量導向 Istio sidecar 代理,包括呼叫網格內未知的服務。使用此方法時,您無法監控對外部服務的存取,也無法利用 Istio 的流量控制功能。若要輕鬆地將特定服務切換到第二種方法,只需為這些外部服務建立服務條目即可。此過程可讓您最初存取任何外部服務,然後再決定是否要控制存取、啟用流量監控並根據需要使用流量控制功能。
第二種方法可讓您將所有相同的 Istio 服務網格功能用於呼叫叢集內或外部的服務。在本任務中,您學習了如何監控對外部服務的存取,並為呼叫外部服務設定逾時規則。
第三種方法會繞過 Istio sidecar 代理,讓您的服務可以直接存取任何外部伺服器。但是,以這種方式設定代理需要了解特定叢集提供者知識和組態。與第一種方法類似,您也會失去對外部服務存取的監控,而且您無法將 Istio 功能應用於外部服務的流量。
安全性注意事項
若要以更安全的方式實作出口流量控制,您必須將出口流量導向出口閘道,並檢閱其他安全性考量章節中描述的安全性問題。
清理
關閉curl 服務。
$ kubectl delete -f @samples/curl/curl.yaml@