在默认情况下所有istio服务网格内某个服务实例的出战流量都将被重定向到其Envoy Sidecar代理,集群外部URL的可访问性取决于Sizdecar代理的配置。 在默认情况下,isito将Envoy代理配置为允许传递请求到未知服务(未在isito服务发现中注册的服务),这带来了一定的便利性,但一般情况下在生产环境建议配置更为严格的配置。 在实际中,由我们负责开发的部署在服务网格中的服务往往还需要访问一些外部资源,如外部的API、中间件等,这就需要配置从istio服务网格内访问外部服务的方式。

本节学习如何从istio服务网格内的服务中访问外部服务,有三种方法:

  • 配置istio sidecar允许访问任意外部服务
  • 使用ServiceEntry API资源对象将一个可访问的外部服务注册到服务网格中(推荐)
  • 配置对特定范围内的IP绕过istio sidecar代理

配置istio sidecar允许访问任意外部服务

配置istio sidecar允许访问任意外部服务,即指配置Envoy直接转发流量到外部服务。 Istio有一个安装选项global.outboundTrafficPolicy.mode用来配置sidecar对外部服务(未在istio内部服务注册中定义的服务)的处理方式。 如果选项值为ALLOW_ANY,sidecar将允许调用未知的服务,如果选项值为REGISTRY_ONLY,那么Istio代理将会阻止调用任何未在服务网格注册中定义的服务或ServiceEntry的host。

一般ALLOW_ANY是默认值,无论是使用哪种方式安装的isito,可以使用下面的命令查看这个配置:

1
kubectl get istiooperator installed-state -n istio-system -o jsonpath='{.spec.meshConfig.outboundTrafficPolicy.mode}'

如果上面的命令输出ALLOW_ANY或没有任何输出,则说明配置的是ALLOW_ANY。可以使用下面的命令修改这个配置:

1
istioctl install <flags-you-used-to-install-Istio> --set meshConfig.outboundTrafficPolicy.mode=ALLOW_ANY

例如我们在第1节中使用istioctl部署的istio的命令是istioctl install --set profile=demo -y,则使用下面的命令修改outboundTrafficPolicy:

1
istioctl install --set profile=demo -y --set meshConfig.outboundTrafficPolicy.mode=ALLOW_ANY

此时再次查看:

1
2
kubectl get istiooperator installed-state -n istio-system -o jsonpath='{.spec.meshConfig.outboundTrafficPolicy.mode}'
ALLOW_ANY

因为default命名空间在前面部署bookinfo应用时已经开启了istio sidecar的自动注入功能,这里我们在default命令空间中手动启动一个radial/busyboxplus:curl pod用来测试,启动的这个pod将被自动注入istio sidecar代理:

1
2
3
4
5
kubectl run curl --image=radial/busyboxplus:curl -it
[ root@curl:/ ]$ curl -sSI https://www.baidu.com | grep "HTTP/"
HTTP/1.1 200 OK
curl -sSI http://httpbin.org/headers | grep "HTTP/"
HTTP/1.1 200 OK

在这个curl容器中访问百度首页https://www.baidu.comhttp://httpbin.org/headers,确认请求都可以发出,且返回了正确的200状态码。

下面修改meshConfig.outboundTrafficPolicy.modeREGISTRY_ONLY,再次在这个curl容器中访问百度首页和https://httpbin.org/headers,会被sidecar代理阻止:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
istioctl install --set profile=demo -y --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY

kubectl get istiooperator installed-state -n istio-system -o jsonpath='{.spec.meshConfig.outboundTrafficPolicy.mode}'
REGISTRY_ONLY

kubectl exec -it curl -- sh
[ root@curl:/ ]$ curl -sSI https://www.baidu.com | grep "HTTP/"
curl: (35) Unknown SSL protocol error in connection to www.baidu.com:443

curl -sSI https://httpbin.org/headers | grep "HTTP/"
curl: (35) Unknown SSL protocol error in connection to httpbin.org:443

使用ServiceEntry将一个外部服务注册到服务网格中

确认meshConfig.outboundTrafficPolicy已经配置为REGISTRY_ONLY,即不允许服务网格内的服务访问外部的未知服务,这在也是官方更推荐的严格配置。 即现在默认情况下对服务网格内的服务实例反问任何外部的未知服务采取的都是拒绝的策略。

假设此时服务网格内的curl服务需要访问httpbin.org,此时httpbin.org对istio服务网格来说还是未知的,所以需要为其创建一个ServiceEntry将其注册到服务网格中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: httpbin-ext
spec:
  hosts:
  - httpbin.org
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
  location: MESH_EXTERNAL
EOF

此时在服务网格内的curl容器中就可以正常访问http://httpbin.org/headers了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
kubectl exec -it curl -- sh
curl http://httpbin.org/headers
{
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    ......
    "X-Envoy-Decorator-Operation": "httpbin.org:80/*",
    ......
  }
}

注意envoy代理添加了X-Envoy-Decorator-Operation的header。

上面配置了以http协议访问httpbin.org,还不能以https访问,修改这个ServiceEntry使其可以以https访问:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: httpbin-ext
spec:
  hosts:
  - httpbin.org
  ports:
  - number: 80
    name: http
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
  location: MESH_EXTERNAL
EOF

此时在服务网格内的curl容器中就可以正常访问https://httpbin.org/headers了,这里略过测试过程。

当把外部服务注册到istio服务网格后,就可以使用istio的流量管理功能像管理网格内的服务一样管理外部服务的流量了。 可以把isito流量管理的配置请求路由、进行故障注入、设置请求超时等各种功能应用到外部服务上。

这里设置调用外部服务httpbin.org的超时时间为3秒。设置请求超时需要借助虚拟服务,为httpbin.org创建一个虚拟服务:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin-ext
spec:
  hosts:
    - httpbin.org
  http:
  - timeout: 3s
    route:
      - destination:
          host: httpbin.org
        weight: 100
EOF

在服务网格内的curl容器中对http://httpbin.org/delay/5发出请求测试,因为我们设置了3秒的请求超时,所以不会等到httpbin.org的5秒延迟响应结果,而会在3秒的时候直接出现504(Gateway Tiemout),这是因为istio sidecar代理在3秒后因到达了配置的超时时间而切断了请求。

配置对特定范围内的IP绕过istio sidecar代理,直接访问外部服务

“配置istio sidecar允许访问任意外部服务"和"使用ServiceEntry将一个外部服务注册到服务网格中"两种方式对外部服务的请求都要经过envoy sidecar。 可以让特定范围的IP绕过envoy sidecar代理直接访问外部服,可以通过修改global.proxy.includeIPRangesglobal.proxy.excludeIPRanges,并使用kubectl apply命令更新istio-sidecar-injector配置实现。 也可以通过annotation在pod上进行设置,例如traffic.sidecar.istio.io/includeOutboundIPRanges,影响的将知识新部署应用的Pod。

注意如果配置绕过istio envoy sidecar代理直接访问外部服务后,将失去了istio对外部服务管理的所有功能,因为该方法完全绕过了sidecar。

另外,如果想排除所有外部 IP 重定向到 Sidecar 代理的一种简单方法是将global.proxy.includeIPRanges配置选项设置为内部集群服务使用的IP范围,如k8s pod的CIDR。

总结

本节学习了从istio服务网格内的服务中访问外部服务,有三种方式:

  • 配置istio sidecar允许访问任意外部服务: 此方法通过istio sidecar代理来引导流量,包括对网格内部未知服务的调用。但使用这种方法,将无法监控对外部服务的访问,也无法利用Isito的流量管理功能。 要轻松为特定的服务切换到第二种方法,只需为那些外部服务创建ServiceEntry即可。 此过程使你可以先访问任何外部服务,然后再根据需要决定是否启用控制访问、流量监控、流量控制等功能。
  • 使用ServiceEntry API资源对象将一个可访问的外部服务注册到服务网格中(推荐): 此方法可以让你使用Istio服务网格所有的功能去调用集群内或集群外的服务
  • 配置对特定范围内的IP绕过istio sidecar代理: 此方法绕过了Istio Sidecar代理,使服务可以直接访问任意的外部服务。 但是,以这种方式配置代理需要了解集群提供商相关知识和配置。与第一种方法类似,你也将失去对外部服务访问的监控,并且无法将Istio功能应用于外部服务的流量。

参考