概述

在 Istio 中,我们可以使用 Egress 来统一管理Mesh网格中的服务访问外部服务的统一出口。

Istio 中访问外部服务的方法

我们来看看在 Istio 中,网格内部的服务想要访问网格外部服务有哪些方式呢?

  • 配置 global.outboundTrafficPolicy.mode=ALLOW_ANY 允许网格内部服务任意调用网格外部的服务;
  • 使用 ServiceEntry 服务入口注册外部服务
  • 配置 Sidecar 让流量绕过代理
  • 配置 Egress 网关

其中,方式1和方式2我们已经在上一篇 ServiceEntry 中体验过啦!方式3是一种并不推荐的方式,我们不展开讲解。本文重点围绕 Egress 网关进行讲解。

Egress 的基本概念

Egress 定义了网格的出口点,允许你将监控、路由等功能应用于离开网格的流量。
Egress 常用于如下场景:

  1. 所有出流量必须流经一组专用节点(安全因素)
  2. 为无法访问公网的内部服务做代理

实战

场景描述

在本文中,我们将会创建一个 egress 网关,让内部服务通过它来访问外部服务。
如下图所示:
image.png
通过本文的学习,希望你可以掌握:

  • 学会使用 egress 网关
  • 理解 egress 存在的意义

StepByStep

Step1:检查 egressgateway 组件、Sleep Pod 是否存在

首先,我们需要检查一下 Istio 中是否正常安装了 egressgateway 组件。
如果你使用的是 demo profile 安装,应该是已经安装了 egressgateway 组件,如果是 default profile,则默认其实并没有安装 egressgateway 组件。

  1. kubectl get pods -n istio-system

另外,如果你完整的实践了上一篇 Istio 服务入口的实战的话,你应该已经创建了一个 sleep 的Pod用于充当客户端,此处也可以检查一下:

  1. kubectl get pods -n istio-demo

Step2:为外部服务定义ServiceEntry

如果你完整的实践了上一篇 Istio 服务入口的实战的话,其实你已经为外部服务 httpbin.org 定义了一个 ServiceEntry,定义的 Yaml 如下:

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

此处我们不再赘述。

Step3:定义 Egress Gateway

下面,我们来定义一个 Egress Gateway 的配置:

  1. apiVersion: networking.istio.io/v1alpha3
  2. kind: Gateway
  3. metadata:
  4. name: istio-egressgateway
  5. spec:
  6. selector:
  7. istio: egressgateway
  8. servers:
  9. - port:
  10. number: 80
  11. name: http
  12. protocol: HTTP
  13. hosts:
  14. - httpbin.org

可以看到它也是一个 Gateway 字段对象,和我们之前配置 IngressGateway 时用到的 API 资源对象是一致的。

Step4:定义路由,将流量引导到 egressgateway

现在,我们需要创建一个 VirtualService:

  1. apiVersion: networking.istio.io/v1alpha3
  2. kind: VirtualService
  3. metadata:
  4. name: vs-for-egressgateway
  5. spec:
  6. hosts:
  7. - httpbin.org
  8. gateways:
  9. - istio-egressgateway
  10. - mesh
  11. http:
  12. - match:
  13. - gateways:
  14. - mesh
  15. port: 80
  16. route:
  17. - destination:
  18. host: istio-egressgateway.istio-system.svc.cluster.local
  19. port:
  20. number: 80
  21. weight: 100
  22. - match:
  23. - gateways:
  24. - istio-egressgateway
  25. port: 80
  26. route:
  27. - destination:
  28. host: httpbin.org
  29. port:
  30. number: 80
  31. weight: 100

这个配置稍微显的有些复杂,我们暂时先操作一下,原理部分会放到原理说明的配置分析中进行讲解。

  1. kubectl apply -f vs.yaml -n istio-demo

Step5:查看日志进行验证

下面,我们来尝试通过 sleep 容器访问 httpbin.org 服务看看:

  1. export POD_NAME=$(kubectl get pods -n istio-demo -l app=sleep -o jsonpath='{.items[0].metadata.name}')
  2. kubectl exec -it $POD_NAME -n istio-demo -c sleep curl http://httpbin.org/headers
  3. # {
  4. # "origin": "113.24.224.46 1.119.148.54"
  5. # }

可以看到,我们的请求是能够正常执行的。
那么,这个出口流量真的经过了 Egressgateway 了么?我们来查看一下 egress 的日志:

  1. kubectl logs -f egressgateway-xxxx-xxx -n istio-demo

此时,我们可以看到日志中的确有我们请求的相关信息了。说明我们的请求的确是经过了 egressgateway 并向外访问的。

原理说明

配置分析

上面的配置看起来有点儿复杂,下面,我们来详细分析一下刚才的配置看看。
首先,我们看通过示例图看一下刚才 sleep 服务访问 httpbin 服务的整体链路是怎么样的:
image.png

  • 首先,我们通过一个 ServiceEntry 将 httpbin 服务 Involve 到我们的 mesh 网格中;
  • 接下来,我们定义了一个 Egress 网关,该网关位于 Mesh 的边界;
  • 然后我们定义了一个 VirtualService,需要注意的是,在这个虚拟服务中,包含了两个路由规则:
    • 提供给 Mesh 网格内部服务:将 Mesh 网格给的流量转给 Egress 网关。
    • 提供给 Egress 网关:将 Egress 网关带来的流量发送给真实的服务地址。