由于所有来自启用了istio的pod的出站流量在默认情况下都被重定向到它的sidecar代理,所以在集群外部访问url取决于代理的配置。默认情况下,Istio将特使代理配置为传递未知服务请求。尽管这为开始使用Istio提供了一种方便的方法,但是配置更严格的控制通常是可取的。

本指南将展示如何通过三种方式来访问外部的服务。

  • 允许envoy代理将请求传递给未在网格内配置的服务。

  • 配置服务条目去提供到外部服务访问控制。

  • 针对指定的IP地址范围完全的旁路掉Envoy代理

1. 准备工作

  • 部署sleep 案例应用程序作为发送请求的测试源。如果启用了自动sidecar注入,运行以下命令来部署示例应用程序:
  1. $ kubectl apply -f samples/sleep/sleep.yaml
  • 手工注入的话使用以下命令
  1. $ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml)
  • 设置SOURCE_POD环境变量,获取source pod的变量名称。
  1. $ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})

2. 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模式,否则它可能在默认情况下是启用的。

运行下面命令确认配置正确:

  1. $ kubectl get configmap istio -n istio-system -o yaml | grep -o "mode: ALLOW_ANY"

[warning] 如果上面的命令,你获得为空值。那么请执行如下命令进行修改

  1. [root@c72082 istio-1.6.1]# kubectl edit cm istio -n istio-system
  2. data:
  3. mesh: "accessLogEncoding: TEXT\naccessLogFile: /dev/stdout\naccessLogFormat: \"\"\ndefaultConfig:\n
  4. \ concurrency: 2\n configPath: ./etc/istio/proxy\n connectTimeout: 10s\n controlPlaneAuthPolicy:
  5. NONE\n discoveryAddress: istiod.istio-system.svc:15012\n drainDuration: 45s\n
  6. \ parentShutdownDuration: 1m0s\n proxyAdminPort: 15000\n proxyMetadata:\n DNS_AGENT:
  7. \"\"\n serviceCluster: istio-proxy\n tracing:\n zipkin:\n address: zipkin.istio-system:9411\ndisableMixerHttpReports:
  8. true\ndisablePolicyChecks: false\nenablePrometheusMerge: false\ningressClass:
  9. istio\ningressControllerMode: STRICT\ningressService: istio-ingressgateway\nprotocolDetectionTimeout:
  10. 100ms\nreportBatchMaxEntries: 100\nreportBatchMaxTime: 1s\nsdsUdsPath: unix:/etc/istio/proxy/SDS\ntrustDomain:
  11. cluster.local\ntrustDomainAliases: null\noutboundTrafficPolicy: \n mode: REGISTRY_ONLY"

如果你设置的配置是REGISTRY_ONLY模式,那么可以运行以下命令改变它。

  1. $ kubectl get configmap istio -n istio-system -o yaml | sed 's/mode: REGISTRY_ONLY/mode: ALLOW_ANY/g' | kubectl replace -n istio-system -f -
  1. 从SOURCE_POD向外部HTTPS服务发出两个请求,以确认成功的200响应
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.baidu.com | grep "HTTP/"
  2. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://edition.cnn.com | grep "HTTP/"

这种访问外部服务的简单方法有一个缺点,即丢失了对外部服务流量的Istio监视和控制。下一节将介绍如何监视和控制mesh对外部服务的访问。

3. 控制到外部服务的访问

使用Istio ServiceEntry配置,您可以从您的Istio集群中访问任何可公开访问的服务。本节将向您展示如何配置对外部HTTP服务(httpbin.org)和外部HTTPS服务(www.baidu.com)的访问权限,而不会丢失Istio的流量监视和控制特性。

3.1 改变默认的阻止策略

要演示启用外部服务的受控方法,您需要更改meshConfig.outboundTrafficPolicy.mode。从ALLOW_ANY模式到REGISTRY_ONLY模式的模式选项。

[warning]您可以向已经在ALLOW_ANY模式下可访问的服务添加受控访问。通过这种方式,您可以开始在一些外部服务上使用Istio特性,而不会阻塞其他服务。一旦您配置了所有的服务,您就可以将模式切换到REGISTRY_ONLY来阻止任何其他无意的访问。

  1. 运行下面的命令去更改meshConfig.outboundTrafficPolicy.mode选项为REGISTRY_ONLY:
  1. $ kubectl get configmap istio -n istio-system -o yaml | sed 's/mode: ALLOW_ANY/mode: REGISTRY_ONLY/g' | kubectl replace -n istio-system -f -
  1. 从SOURCE_POD向外部HTTPS服务发出几个请求,以验证它们是否被阻塞:
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.baidu.com | grep "HTTP/"; kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://edition.cnn.com | grep "HTTP/"
  2. command terminated with exit code 35
  3. command terminated with exit code 35

[warning]它可能过一会才会生效,因此你可能会获得成功的连接。等待几秒再去尝试。

3.2 访问外部的HTTP服务
  1. 创建服务条目去允许访问外部服务
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: ServiceEntry
  4. metadata:
  5. name: httpbin-ext
  6. spec:
  7. hosts:
  8. - httpbin.org
  9. ports:
  10. - number: 80
  11. name: http
  12. protocol: HTTP
  13. resolution: DNS
  14. location: MESH_EXTERNAL
  15. EOF
  1. 测试结果如下所示
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl http://httpbin.org/headers

注意通过istio sidecar代理添加的报头:X-Envoy-Decorator-Operation

  1. 检查SOURCE_POD的sidecar代理日志:
  1. $ kubectl logs $SOURCE_POD -c istio-proxy | tail

3.3 访问外部HTTPS服务
  1. 创建ServiceEntry去允许访问外部的服务。
  1. $ kubectl create -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: ServiceEntry
  4. metadata:
  5. name: baidu
  6. spec:
  7. hosts:
  8. - www.baidu.com
  9. ports:
  10. - number: 443
  11. name: https
  12. protocol: HTTPS
  13. resolution: DNS
  14. location: MESH_EXTERNAL
  15. EOF
  1. 测试到外部的HTTPS服务访问
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- curl -I https://www.baidu.com | grep "HTTP/"
  1. 检查SOURCE_POD的sidecar代理日志。
  1. $ kubectl logs $SOURCE_POD -c istio-proxy | tail

3.4 管理到外部服务的流量

与集群间请求类似,还可以为使用ServiceEntry配置访问的外部服务设置Istio路由规则。在本例中,您对httpbin.org服务的调用设置了超时规则。

  1. 在用作测试源的pod内部,向httpbin.org外部服务的/delay端点发出curl请求:
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5

大约需要5秒钟会返回200的代码。

  1. 使用kubectl去设置调用httpbin.org3秒超时时间
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: VirtualService
  4. metadata:
  5. name: httpbin-ext
  6. spec:
  7. hosts:
  8. - httpbin.org
  9. http:
  10. - timeout: 3s
  11. route:
  12. - destination:
  13. host: httpbin.org
  14. weight: 100
  15. EOF
  1. 等待几秒后,再次请求
  1. $ kubectl exec -it $SOURCE_POD -c sleep -- time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
  2. 504
  3. real 0m 3.03s
  4. user 0m 0.00s
  5. sys 0m 0.00s

在大约3秒后出现一个504的超时,虽然httpbin.org等待了5秒,但Istio在3秒时切断了请求。

3.5 清除控制到外部服务的访问
  1. $ kubectl delete serviceentry httpbin-ext baidu
  2. $ kubectl delete virtualservice httpbin-ext --ignore-not-found=true

4. 直接到外部服务的访问

如果您想要完全绕过某个特定IP范围的Istio,您可以配置envoy sidecars,以防止它们拦截外部请求。要设置旁路,请更改global.proxy.includeIPRangesglobal.proxy.excludeIPRanges并使用kubectl应用命令更新istio-sidecar-injector配置映射。也可以通过设置相应的注释(如traffic.sidecar.istio.io/includeOutboundIPRanges)在pod上配置它。在更新了istio-sidecar-injector配置之后,它会影响到所有未来pod应用的部署。

[warning]与使用ALLOW_ANY流量策略指示Istio sidecar代理传递对未知服务的调用的外部服务的Envoy passthrough不同,这种方法完全绕过sidecar,本质上禁用了指定ip的所有Istio特性。您不能像使用ALLOW_ANY方法那样,渐进地为特定目的地添加服务条目。因此,只有在出于性能或其他原因无法使用sidecar配置外部访问时,才建议将此配置方法作为最后的手段。

  1. 确定集群内部的IP
  1. $ kubectl describe pod kube-apiserver -n kube-system | grep 'service-cluster-ip-range'
  1. 配置代理的旁路
  1. $ istioctl manifest apply --set profile=demo --set values.global.proxy.includeIPRanges="10.96.0.0/12"
  1. 访问外部的服务
  1. $ export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
  2. $ kubectl exec -it $SOURCE_POD -c sleep curl http://httpbin.org/headers
  1. 把配置改为以前的
  1. $ istioctl manifest apply --set profile=demo

5. 理解发生了什么

在此小节中,我们看到了通过三种方式从Istio mesh调用外部服务

  1. 配置Envoy去允许访问任何外部的服务
  2. 使用一个服务条目在mesh中去注册一个可访问的外部服务。 这是推荐的方法
  3. 配置istio sidecar去排除外部的IPs.

第一种方法通过Istio sidecar代理引导流量,包括对网格内未知的服务的调用。当使用这种方法时,您不能监视对外部服务的访问,也不能利用Istio的流量控制特性。要轻松地切换到特定服务的第二种方法,只需为这些外部服务创建服务条目。这个过程允许您首先访问任何外部服务,然后决定是否控制访问、启用流量监视并根据需要使用流量控制特性。

第二种方法允许您使用所有相同的Istio service mesh特性来调用集群内外的服务。在本任务中,您学习了如何监视对外部服务的访问并为对外部服务的调用设置超时规则。

第三种方法绕过Istio sidecar代理,让您的服务直接访问任何外部服务器。然而,以这种方式配置代理确实需要特定于集群提供程序的知识和配置。与第一种方法类似,您还会失去对外部服务访问的监视,并且不能将流量上的Istio特性应用于外部服务。

6. 清空本实验

  1. $ kubectl delete -f samples/sleep/sleep.yaml

7. 设置外出的流量策略模型

  1. 检查当前的值
  1. $ kubectl get configmap istio -n istio-system -o yaml | grep -o "mode: ALLOW_ANY" | uniq
  2. $ kubectl get configmap istio -n istio-system -o yaml | grep -o "mode: REGISTRY_ONLY" | uniq
  1. 改变模式的话执行如下命令
  1. # change from ALLOW_ANY to REGISTRy_ONLY
  2. kubectl get configmap istio -n istio-system -o yaml | sed 's/mode: ALLOW_ANY/mode: REGISTRY_ONLY/g' | kubectl replace -n istio-system -f -
  3. # change from REGISTRY_ONLY to ALLOW_ANY
  4. kubectl get configmap istio -n istio-system -o yaml | sed 's/mode: REGISTRY_ONLY/mode: ALLOW_ANY/g' | kubectl replace -n istio-system -f -