访问外部服务
因为默认情况下,来自启用 Istio 的 Pod 的所有出站流量都会重定向到其 sidecar 代理,所以集群外部 URL 的可访问性取决于代理的配置。默认情况下,Istio 会将 Envoy 代理配置为传递对未知服务的请求。虽然这提供了一种方便的方法来开始使用 Istio,但通常更建议配置更严格的控制。
此任务向您展示如何通过三种不同的方式访问外部服务
- 允许 Envoy 代理将请求传递到网格内未配置的服务。
- 配置服务条目以提供对外部服务的受控访问。
- 完全绕过特定 IP 范围的 Envoy 代理。
开始之前
按照安装指南中的说明设置 Istio。使用
demo
配置配置文件或以其他方式启用 Envoy 的访问日志记录。部署curl示例应用程序以用作发送请求的测试源。如果您启用了自动 sidecar 注射,请运行以下命令来部署示例应用程序
$ kubectl apply -f @samples/curl/curl.yaml@
否则,在使用以下命令部署
curl
应用程序之前,手动注入 sidecar$ 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 ServiceEntry
配置,您可以从 Istio 集群内访问任何公共可访问的服务。本节将向您展示如何配置对外部 HTTP 服务httpbin.org以及外部 HTTPS 服务www.google.com的访问,而不会丢失 Istio 的流量监控和控制功能。
更改为默认阻止策略
为了演示以受控方式启用对外部服务的访问,您需要将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(网关超时)。虽然 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
配置映射。这也可以通过设置相应的注释(例如traffic.sidecar.istio.io/includeOutboundIPRanges
)在 Pod 上进行配置。更新istio-sidecar-injector
配置后,它会影响所有未来的应用程序 Pod 部署。
排除所有外部 IP 不重定向到 sidecar 代理的一种简单方法是将global.proxy.includeIPRanges
配置选项设置为用于内部集群服务的 IP 范围。这些 IP 范围值取决于您的集群运行的平台。
确定平台的内部 IP 范围
根据您的集群提供商设置values.global.proxy.includeIPRanges
的值。
IBM Cloud Private
从 IBM Cloud Private 配置文件(位于
cluster/config.yaml
下)获取您的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 <CLUSTER-NAME>
并查找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 覆盖网络文档。
要查看集群中使用了哪个服务 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@