原文链接:控制 Egress 流量

本文主要内容来自 Istio 官方文档,并对其进行了大量扩展和补充。

缺省情况下,Istio 服务网格内的 Pod,由于其 iptables 将所有外发流量都透明的转发给了 Sidecar,所以这些集群内的服务无法访问集群之外的 URL,而只能处理集群内部的目标。

本文的任务描述了如何将外部服务暴露给 Istio 集群中的客户端。你将会学到如何通过定义 ServiceEntry 来调用外部服务;或者简单的对 Istio 进行配置,要求其直接放行对特定 IP 范围的访问。

1. 开始之前

  • 根据安装指南的内容,部署 Istio。
  • 启动 sleep 示例应用,我们将会使用这一应用来完成对外部服务的调用过程。 如果启用了 Sidecar 的自动注入功能,运行:
$ kubectl apply -f samples/sleep/sleep.yaml
复制代码

否则在部署 sleep 应用之前,就需要手工注入 Sidecar:

$ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml)
复制代码

实际上任何可以 execcurl 的 Pod 都可以用来完成这一任务。

2. Istio 中配置外部服务

通过配置 Istio ServiceEntry,可以从 Istio 集群中访问外部任意的可用服务。这里我们会使用 httpbin.org 以及 www.baidu.com 进行试验。

配置外部服务

1. 创建一个 ServiceEntry 对象,放行对一个外部 HTTP 服务的访问:

$ cat <<EOF | istioctl create -f -
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: httpbin-ext
spec:
  hosts:
  - httpbin.org
  ports:
  - number: 80
    name: http
    protocol: HTTP
EOF
复制代码

2. 另外创建一个 ServiceEntry 对象和一个 VirtualService,放行对一个外部 HTTPS 服务的访问:

$ cat <<EOF | istioctl create -f -
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: baidu
spec:
  hosts:
  - www.baidu.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: baidu
spec:
  hosts:
  - www.baidu.com
  tls:
  - match:
    - port: 443
      sniHosts:
      - www.baidu.com
    route:
    - destination:
        host: www.baidu.com
        port:
          number: 443
      weight: 100
EOF
复制代码

发起对外部服务的访问

使用 kubectl exec 命令进入测试 Pod。假设使用的是 sleep 服务,运行如下命令:

$ export SOURCE_POD=$(kubectl get pod -l app=sleep -o go-template='{{range .items}}{{.metadata.name}}{{end}}')
$ kubectl exec -it $SOURCE_POD -c sleep bash
复制代码

发起一个对外部 HTTP 服务的请求:

$ curl http://httpbin.org/headers
复制代码

发起一个对外部 HTTPS 服务的请求:

$ curl https://www.baidu.com
复制代码

HTTP ServiceEntry 配置深度解析

按照之前的惯例,还是先来解读一下 HTTP 协议的 ServiceEntry 映射到 Envoy 配置层面具体是哪些内容,这样才能对 ServiceEntry 有更加深刻的认识。

创建一个 HTTP 协议的 ServiceEntry(不指定 GateWay) 本质上是在服务网格内的所有应用的所有 Pod上创建相应的路由规则和与之对应的 Cluster。指定 GateWay 的 ServiceEntry 遵循的是另一套法则,后面我们再说。

可以通过 istioctl 来验证一下(以 httpbin-ext 为例):

# 查看 sleep 的 Pod Name:
$ kubectl get pod -l app=sleepNAME                     READY     STATUS    RESTARTS   AGE
sleep-5bc866558c-89shb   2/2       Running   0          49m
复制代码

查看路由

$ istioctl pc routes sleep-5bc866558c-89shb --name 80 -o json
复制代码
[{"name": "80","virtualHosts": [{"name": "httpbin.org:80","domains": ["httpbin.org","httpbin.org:80"],"routes": [{"match": {"prefix": "/"},"route": {"cluster": "outbound|80||httpbin.org","timeout": "0.000s","maxGrpcTimeout": "0.000s"},"decorator": {"operation": "httpbin.org:80/*"},
...
复制代码

可以看到从 Pod sleep-5bc866558c-89shb 内部对域名 httpbin.org 发起的请求通过 HTTP 路由被定向到集群 outbound|80||httpbin.orgoutbound 表示这是出站流量

查看 Cluster

$ istioctl pc clusters sleep-5bc866558c-89shb --fqdn httpbin.org -o json
复制代码
[{"name": "outbound|80||httpbin.org","type": "ORIGINAL_DST","connectTimeout": "1.000s","lbPolicy": "ORIGINAL_DST_LB","circuitBreakers": {"thresholds": [{}]}}
]
复制代码
  • type : 服务发现类型。ORIGINAL_DST 表示原始目的地类型,大概意思就是:连接进入之前已经被解析为一个特定的目标 IP 地址。这种连接通常是由代理使用 IP table REDIRECT 或者 eBPF 之类的机制转发而来的。完成路由相关的转换之后,代理服务器会将连接转发到该 IP 地址。httpbin.org 是外网域名,当然可以解析,所以连接进入之前可以被解析为一个特定的目标 IP 地址。Envoy 服务发现类型的详细解析可以参考:Service discovery。ServiceEntry.Resolution 字段的解析可以参考:ServiceEntry.Resolution。

    这里我简要说明一下,ServiceEntry 的 resolution 字段可以取三个不同的值,分别对应 Envoy 中的三种服务发现策略:

    • NONE : 对应于 Envoy 中的 ORIGINAL_DST。如果不指定 resolution 字段,默认使用这个策略。
    • STATIC : 对应于 Envoy 中的 STATIC。表示使用 endpoints 中指定的静态 IP 地址作为服务后端。
    • DNS : 对应于 Envoy 中的 STRICT_DNS。表示处理请求时尝试向 DNS 查询 IP 地址。如果没有指定 endpoints,并且没有使用通配符,代理服务器会使用 DNS 解析 hosts 字段中的地址。如果指定了 endpoints,那么指定的地址就会作为目标 IP 地址。
  • lbPolicy : 负载均衡策略。ORIGINAL_DST_LB 表示使用原始目的地的负载均衡策略。具体参考: Load balancing。

如果你还部署了 bookinfo 示例应用,可以通过执行 istioctl pc routes <productpage_pod_name> --name 80 -o jsonistioctl pc clusters <productpage_pod_name> --fqdn httpbin.org -o json 来验证一下,你会发现输出的结果和上面一模一样。如果还不放心,可以查看 bookinfo 应用内的所有 Pod,你会得到相同的答案。至此你应该可以理解在服务网格内的所有应用的所有 Pod上创建相应的路由规则和与之对应的 Cluster这句话的含义了。

HTTPS ServiceEntry 配置深度解析

HTTPS 协议的 ServiceEntry 与 Envoy 配置文件的映射关系与 HTTP 协议有所不同。

创建一个 HTTPS 协议的 ServiceEntry(不指定 GateWay) 本质上是在服务网格内的所有应用的所有 Pod上创建相应的监听器和与之对应的 Cluster。指定 GateWay 的 ServiceEntry 我会另行发文详述。

可以通过 istioctl 来验证(以 baidu 为例)。为了更精确地分析该 ServiceEntry,可以先把 VirtualService 删除:

$ istioctl delete virtualservice baidu
复制代码

查看监听器:

$ istioctl pc listeners sleep-5bc866558c-89shb --address 0.0.0.0 --port 443 -o json
复制代码
[{"name": "0.0.0.0_443","address": {"socketAddress": {"address": "0.0.0.0","portValue": 443}},"filterChains": [{"filters": [...{"name": "envoy.tcp_proxy","config": {"cluster": "outbound|443||www.baidu.com","stat_prefix": "outbound|443||www.baidu.com"}}
...
复制代码
  • name : 监听器过滤器的名称。该字段的值必须与 Envoy 所支持的过滤器匹配,不可随意填写,具体参考:listener.Filter。此处 envoy.tcp_proxy 表示使用 TCP 代理,而 TCP 代理是无法基于路由过滤的,所以这里不会创建路由规则,而是直接将请求转到 Cluster

查看 Cluster:

$ istioctl pc clusters sleep-5bc866558c-89shb --fqdn www.baidu.com -o json
复制代码
[{"name": "outbound|443||www.baidu.com","type": "STRICT_DNS","connectTimeout": "1.000s","hosts": [{"socketAddress": {"address": "www.baidu.com","portValue": 443}}],"circuitBreakers": {"thresholds": [{}]},"dnsLookupFamily": "V4_ONLY"}
]
复制代码

从监听器的配置来看,由于绑定的是 0.0.0.0,而且也没有指定域名,看起来应该可以访问集群外任何 443 端口的服务。实际上这是行不通的,因为当请求通过监听器转到 Cluster 之后,由于 Cluster 采用的是严格的 DNS 服务发现策略,只要域名不是 www.baidu.com,都不会解析。你可以使用 kubectl exec 命令进入 sleep Pod 来测试一下:

$ kubectl exec -it $SOURCE_POD -c sleep bash
复制代码

发起对外部 HTTPS 服务的请求:

$ curl https://www.163.com
curl: (51) SSL: no alternative certificate subject name matches target host name 'www.163.com'$ curl https://www.taobao.com
curl: (51) SSL: no alternative certificate subject name matches target host name 'www.taobao.com'$ curl https://192.192.192.192
curl: (51) SSL: certificate subject name 'baidu.com' does not match target host name '192.192.192.192'
复制代码

而如果你将服务发现策略改为 NONE,就会发现除了可以访问 www.baidu.com,还可以访问 www.163.comwww.taobao.com 等其他 https 协议的网站,至于为什么会这样,前面介绍服务发现策略的时候我已经详细解释过了。

TLS VirtualService 配置深度解析

关于 VirtualService 的解析之前的文章已有相关说明,不过这里的 VirtualService 与之前遇到的不同,涉及到了 TLSRoute

  • tls : 透传 TLS 和 HTTPS 流量。TLS 路由通常应用在 https-tls- 前缀的平台服务端口,或者经 Gateway 透传的 HTTPS、TLS 协议 端口,以及使用 HTTPS 或者 TLS 协议的 ServiceEntry 端口上。具体参考:TLSRoute。

    • sniHosts : 必要字段。要匹配的 SNI(服务器名称指示)。可以在 SNI 匹配值中使用通配符。比如 *.com 可以同时匹配 foo.example.comexample.com
  • route : 流量的转发目标。目前 TLS 服务只允许一个转发目标(所以权重必须设置为 100)。当 Envoy 支持 TCP 权重路由之后,这里就可以使用多个目标了。

查看映射到 Envoy 中的配置:

$ istioctl pc listeners sleep-5bc866558c-89shb --address 0.0.0.0 --port 443 -o json
复制代码
[{"name": "0.0.0.0_443","address": {"socketAddress": {"address": "0.0.0.0","portValue": 443}},"filterChains": [{"filterChainMatch": {"serverNames": ["www.baidu.com"]},"filters": [...{"name": "envoy.tcp_proxy","config": {"cluster": "outbound|443||www.baidu.com","stat_prefix": "outbound|443||www.baidu.com"}}
...
复制代码
  • filterChainMatch : 用于为监听器过滤器链指定匹配条件,具体参考:listener.FilterChainMatch。

最后我们来思考一下:既然不创建 TLS VirtualService 也可以访问 www.baidu.com,那么创建 TLS VirtualService 和不创建 TLS VirtualService 有什么区别呢?正确答案是:没有关联 VirtualServicehttps- 或者 tls- 端口流量会被视为透传 TCP 流量,而不是透传 TLS 和 HTTPS 流量。

为外部服务设置路由规则

通过 ServiceEntry 访问外部服务的流量,和网格内流量类似,都可以进行 Istio 路由规则 的配置。下面我们使用 istioctl 为 httpbin.org 服务设置一个超时规则。

1. 在测试 Pod 内部,调用 httpbin.org 这一外部服务的 /delay 端点:

$ kubectl exec -it $SOURCE_POD -c sleep bash
$ time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5200real    0m5.024s
user    0m0.003s
sys     0m0.003s
复制代码

这个请求会在大概五秒钟左右返回一个内容为 200 (OK) 的响应。

2. 退出测试 Pod,使用 istioctl 为 httpbin.org 外部服务的访问设置一个 3 秒钟的超时:

cat <<EOF | istioctl create -f -
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
复制代码

3. 等待几秒钟之后,再次发起 curl 请求:

$ kubectl exec -it $SOURCE_POD -c sleep bash
$ time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5504real    0m3.149s
user    0m0.004s
sys     0m0.004s
复制代码

这一次会在 3 秒钟之后收到一个内容为 504 (Gateway Timeout) 的响应。虽然 httpbin.org 还在等待他的 5 秒钟,Istio 却在 3 秒钟的时候切断了请求。

3. 直接调用外部服务

如果想要跳过 Istio,直接访问某个 IP 范围内的外部服务,就需要对 Envoy sidecar 进行配置,阻止 Envoy 对外部请求的劫持。可以在 Helm 中设置 global.proxy.includeIPRanges 变量,然后使用 kubectl apply 命令来更新名为 istio-sidecar-injectorConfigmap。在 istio-sidecar-injector 更新之后,global.proxy.includeIPRanges 会在所有未来部署的 Pod 中生效。

使用 global.proxy.includeIPRanges 变量的最简单方式就是把内部服务的 IP 地址范围传递给它,这样就在 Sidecar proxy 的重定向列表中排除掉了外部服务的地址了。

内部服务的 IP 范围取决于集群的部署情况。例如你的集群中这一范围是 10.0.0.1/24,这个配置中,就应该这样更新 istio-sidecar-injector:

$ helm template install/kubernetes/helm/istio <安装 Istio 时所使用的参数> --set global.proxy.includeIPRanges="10.0.0.1/24" -x templates/sidecar-injector-configmap.yaml | kubectl apply -f -
复制代码

注意这里应该使用和之前部署 Istio 的时候同样的 Helm 命令,尤其是 --namespace 参数。在安装 Istio 原有命令的基础之上,加入 --set global.proxy.includeIPRanges="10.0.0.1/24" -x templates/sidecar-injector-configmap.yaml 即可。

然后和前面一样,重新部署 sleep 应用。更新了 ConfigMap istio-sidecar-injector 并且重新部署了 sleep 应用之后,Istio sidecar 就应该只劫持和管理集群内部的请求了。任意的外部请求都会简单的绕过 Sidecar,直接访问目的地址。

$ export SOURCE_POD=$(kubectl get pod -l app=sleep -o go-template='{{range .items}}{{.metadata.name}}{{end}}')
$ kubectl exec -it $SOURCE_POD -c sleep curl http://httpbin.org/headers
复制代码

4. 总结

这个任务中,我们使用两种方式从 Istio 服务网格内部来完成对外部服务的调用:

  1. 使用 ServiceEntry (推荐方式)
  2. 配置 Istio sidecar,从它的重定向 IP 表中排除外部服务的 IP 范围

第一种方式(ServiceEntry)中,网格内部的服务不论是访问内部还是外部的服务,都可以使用同样的 Istio 服务网格的特性。我们通过为外部服务访问设置超时规则的例子,来证实了这一优势。

第二种方式越过了 Istio sidecar proxy,让服务直接访问到对应的外部地址。然而要进行这种配置,需要了解云供应商特定的知识和配置。

5. 清理

1. 删除规则:

$ istioctl delete serviceentry httpbin-ext baidu
$ istioctl delete virtualservice httpbin-ext baidu
复制代码

2. 停止 sleep 服务:

$ kubectl delete -f samples/sleep/sleep.yaml
复制代码

转载于:https://juejin.im/post/5ca097e9f265da30b9634b1b

控制 Egress 流量相关推荐

  1. 第十七部分 Istio控制 Egress 流量

    简述 默认情况下,Istio服务Mesh中的Pod,由于其 iptables 将所有外发流量都透明的转发给了 Sidecar,所以这些集群内的服务无法访问集群之外的 URL,而只能处理集群内部的目标. ...

  2. 【品高云技巧】002.通过弹性IP控制网络流量(QoS)

    1.场景 与内网应用不同,当企业使用租用的互联网带宽对外部提供服务时,需要考虑各个应用的实际带宽占用,不能让宝贵的公网带宽资源被无限制占用,从而影响业务运行. 2.解决思路 BingoCloudOS提 ...

  3. 用tc(traffic control)控制网络流量

    1.用TC控制网络延时.具体来说就是控制本机处理一个数据报文的时延,也就是rtt. sudo tc qdisc add dev eth0 root netem delay 1000ms //设置1秒的 ...

  4. linux 控制网卡流量,如何管理和控制多网卡 Linux 虚拟机的流量走向

    如何管理和控制多网卡 Linux 虚拟机的流量走向 02/28/2018 本文内容 现象描述 多网卡虚拟机默认会使用主网卡跟外界进行通信,其他的辅网卡默认是不会被用来跟外界通信,可以使用本文介绍的方法 ...

  5. OpenShift 4 之Istio-Tutorial (11) 控制Egress访问

    <OpenShift 4.x HOL教程汇总> 说明:本文已经在OpenShift 4.6环境中验证 Istio缺省是不限制服务网格中的服务对外部访问的,不过我们可以对Egress进行控制 ...

  6. 怎样用Netfilter/IPtables控制P2P流量

    今年4月,看到一则报道说尽管某宽带公司现有技术可以容纳的网络用户容量为400至600万用户,可是目前,在容纳了45万用户的情况下,网络已经拥挤不堪,时常出现断网情况,一到上网高峰,网速就会急剧下降. ...

  7. 交换机、路由器网络监控平台,准入控制、流量监控

    交换机作为局域网中的核心设备之一,它的工作性能直接决定着网络的数据传输性能.可是,在长时间工作之后,交换机难免会遇到这样或那样的故障现象:为了及时解决故障现象,管理人员就需要一款简单易用的交换机管理软 ...

  8. 使用TC的htb队列控制网络流量

    起因,放在公司内的部分服务器对外提供服务,而且是很重要的服务,但由于公司员工上网也要占据很大的流量,往往导致服务器抢不到带宽,严重影响服务器的对外服务,于是考虑限制公司员工上网的带宽,确保服务器对外提 ...

  9. golang 安全的tcp server_Go 语言使用 TCP_NODELAY 控制发包流量

    编写健壮且高性能的网络服务需要付出大量的努力.提高服务性能的方式有很多种,比如优化应用层的代码,更进一步,还可以看看垃圾回收器,操作系统,网络传输,以及部署我们服务的硬件是否有优化空间. TCP/IP ...

最新文章

  1. facebox目标检测改进
  2. EChart.js 简单入门
  3. 吴恩达deeplearning资源汇总帖
  4. linux如何查看git安装路径,Git - 如何验证Ubuntu上是否安装Git以及在何处安装Git - Ubuntu问答...
  5. 高仿QQ即时聊天软件开发系列之三登录窗口用户选择下拉框
  6. nmap结果导出html,nmap的简单使用 - osc_ijgldkz9的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. 【课后服务】20181022切蛋糕
  8. 【转】Web布局中的几种宽高自适应
  9. 鼠标自动移动 防止锁屏睡眠
  10. matlab求解线性规划问题的实例代码,matlab 求解线性规划问题
  11. 计算机组成原理实验:基本运算器实验
  12. windows系统上安装.cab文件
  13. 【英语语法入门】 第31讲 [被动语态 (1)]被动态的构成和含义
  14. 求两个数的最大公约数,Euclid算法证明,以及C语言代码实现
  15. 蓝牙协议spec文档免费下载官网下载(免费)
  16. golang errors
  17. 解决SVN或eclipse安装SVN插件失败问题
  18. 视频文本检索之CLIP4Clip
  19. 【Multisim仿真】TL494电路仿真 DC转DC 5V 1A输出
  20. 【LittleXi】规划兼职工作

热门文章

  1. php 照片变成卡通照片,怎么把照片做成q版卡通 照片变q版卡通人物 q版卡通头像制作...
  2. springboot+Thymeleaf生成PDF
  3. 树莓派 4b 配置 USB 网络连接
  4. ipad 浏览器对于onscroll的延迟
  5. 准备考试?python也能帮你划重点,上考场
  6. js 写一个任意类型转浮点小数点保留两位
  7. APP乱查征信?小心你的隐私被卖了!
  8. jpg怎么转换成pdf文档
  9. c语言switch问候语,C语言switch语句用法详解
  10. Axure绘制跑马灯