概述
在 Istio 中,我们可以使用 Egress 来统一管理Mesh网格中的服务访问外部服务的统一出口。
Istio 中访问外部服务的方法
我们来看看在 Istio 中,网格内部的服务想要访问网格外部服务有哪些方式呢?
- 配置 global.outboundTrafficPolicy.mode=ALLOW_ANY 允许网格内部服务任意调用网格外部的服务;
- 使用 ServiceEntry 服务入口注册外部服务
- 配置 Sidecar 让流量绕过代理
- 配置 Egress 网关
其中,方式1和方式2我们已经在上一篇 ServiceEntry 中体验过啦!方式3是一种并不推荐的方式,我们不展开讲解。本文重点围绕 Egress 网关进行讲解。
Egress 的基本概念
Egress 定义了网格的出口点,允许你将监控、路由等功能应用于离开网格的流量。
Egress 常用于如下场景:
- 所有出流量必须流经一组专用节点(安全因素)
- 为无法访问公网的内部服务做代理
实战
场景描述
在本文中,我们将会创建一个 egress 网关,让内部服务通过它来访问外部服务。
如下图所示:
通过本文的学习,希望你可以掌握:
- 学会使用 egress 网关
- 理解 egress 存在的意义
StepByStep
Step1:检查 egressgateway 组件、Sleep Pod 是否存在
首先,我们需要检查一下 Istio 中是否正常安装了 egressgateway 组件。
如果你使用的是 demo profile 安装,应该是已经安装了 egressgateway 组件,如果是 default profile,则默认其实并没有安装 egressgateway 组件。
kubectl get pods -n istio-system
另外,如果你完整的实践了上一篇 Istio 服务入口的实战的话,你应该已经创建了一个 sleep 的Pod用于充当客户端,此处也可以检查一下:
kubectl get pods -n istio-demo
Step2:为外部服务定义ServiceEntry
如果你完整的实践了上一篇 Istio 服务入口的实战的话,其实你已经为外部服务 httpbin.org 定义了一个 ServiceEntry,定义的 Yaml 如下:
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
此处我们不再赘述。
Step3:定义 Egress Gateway
下面,我们来定义一个 Egress Gateway 的配置:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: istio-egressgateway
spec:
selector:
istio: egressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- httpbin.org
可以看到它也是一个 Gateway 字段对象,和我们之前配置 IngressGateway 时用到的 API 资源对象是一致的。
Step4:定义路由,将流量引导到 egressgateway
现在,我们需要创建一个 VirtualService:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-for-egressgateway
spec:
hosts:
- httpbin.org
gateways:
- istio-egressgateway
- mesh
http:
- match:
- gateways:
- mesh
port: 80
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
port:
number: 80
weight: 100
- match:
- gateways:
- istio-egressgateway
port: 80
route:
- destination:
host: httpbin.org
port:
number: 80
weight: 100
这个配置稍微显的有些复杂,我们暂时先操作一下,原理部分会放到原理说明的配置分析中进行讲解。
kubectl apply -f vs.yaml -n istio-demo
Step5:查看日志进行验证
下面,我们来尝试通过 sleep 容器访问 httpbin.org 服务看看:
export POD_NAME=$(kubectl get pods -n istio-demo -l app=sleep -o jsonpath='{.items[0].metadata.name}')
kubectl exec -it $POD_NAME -n istio-demo -c sleep curl http://httpbin.org/headers
# {
# "origin": "113.24.224.46 1.119.148.54"
# }
可以看到,我们的请求是能够正常执行的。
那么,这个出口流量真的经过了 Egressgateway 了么?我们来查看一下 egress 的日志:
kubectl logs -f egressgateway-xxxx-xxx -n istio-demo
此时,我们可以看到日志中的确有我们请求的相关信息了。说明我们的请求的确是经过了 egressgateway 并向外访问的。
原理说明
配置分析
上面的配置看起来有点儿复杂,下面,我们来详细分析一下刚才的配置看看。
首先,我们看通过示例图看一下刚才 sleep 服务访问 httpbin 服务的整体链路是怎么样的:
- 首先,我们通过一个 ServiceEntry 将 httpbin 服务 Involve 到我们的 mesh 网格中;
- 接下来,我们定义了一个 Egress 网关,该网关位于 Mesh 的边界;
- 然后我们定义了一个 VirtualService,需要注意的是,在这个虚拟服务中,包含了两个路由规则:
- 提供给 Mesh 网格内部服务:将 Mesh 网格给的流量转给 Egress 网关。
- 提供给 Egress 网关:将 Egress 网关带来的流量发送给真实的服务地址。