总结应用 istio 常见的 10 个异样:
- Service 端口命名束缚
- 流控规定下发程序问题
- 申请中断剖析
- sidecar 和 user container 启动程序
- Ingress Gateway 和 Service 端口联动
- VirtualService 作用域
- VirtualService 不反对 host fragment
- 全链路跟踪并非齐全通明接入
- mTLS 导致连贯中断
- 用户服务监听地址限度
1. Service 端口命名束缚
istio 反对多平台,不过 Istio 和 k8s 的兼容性是最优的,不论是设计理念,外围团队还是社区,都有一脉相承的意思。但 istio 和 k8s 的适配并非齐全没有抵触, 一个典型问题就是 istio 须要 k8s service 依照协定进行端口命名(port naming)。
端口命名不满足束缚而导致的流量异样,是应用 mesh 过程中最常见的问题,其景象是协定相干的流控规定不失效,这通常能够通过查看该 port LDS 中 filter 的类型来定位。
起因
k8s 的网络对应用层是无感知的,k8s 的次要流量转发逻辑产生在 node 上,由 iptables/ipvs 来实现,这些规定并不关怀应用层里是什么协定。
istio 的外围能力是对 7 层流量进行管控,但前提条件是 istio 必须晓得每个受管控的服务是什么协定,istio 会依据端口协定的不同,下发不同的流控性能(envoy filter),而 k8s 资源定义里并不包含七层协定信息,所以 istio 须要用户显式提供。
istio 的解决方案:Protocol sniffing
协定嗅探概要:
- 检测 TLS
CLIENT_HELLO
提取 SNI、ALPN、NPN 等信息 - 基于常见协定的已知典型构造,尝试检测应用层 plaintext 内容 a. 基于 HTTP2 spec: Connection Preface,, 判断是否为 HTTP/2 b. 基于 HTTP header 构造,判断是否是 HTTP/1.x
- 过程中会设置超时管制和检测包大小限度,默认依照协定 TCP 解决
最佳实际
Protocol sniffing 缩小了老手应用 istio 所需的配置,然而可能会带来不确定的行为。不确定的行为在生产环境中是应该尽量避免的。
一些嗅探生效的例子:
- 客户端和服务端应用着某类非标准的七层协定,客户端和服务端都能够正确解析,然而不能确保 istio 主动嗅探逻辑认可这类非标准协议。比方对于 http 协定,规范的换行分隔是用 CRLF(
0x0d 0x0a
), 然而大部分 http 类库会应用并认可 LF(0x0a
)作为分隔。 - 某些自定义公有协定,数据流的起始格局和 http 报文格式相似,然而后续数据流是自定义格局:未开启嗅探时:数据流依照 L4 TCP 进行路由,合乎用户冀望 如果开启嗅探:数据流最开始会被认定为 L7 http 协定,然而后续数据不合乎 http 格局,流量将被中断
倡议生产环境不应用协定嗅探, 接入 mesh 的 service 应该依照约定应用协定前缀进行命名。
2. 流控规定下发程序问题
异样形容
在批量更新流量规定的过程中,偶然会呈现流量异样(503),envoy 日志中 RESPONSE_FLAGS
蕴含「NR」标记(No route configured),持续时间不长,会主动复原。
起因剖析
当用户应用 kubectl apply -f multiple-virtualservice-destinationrule.yaml
时,这些对象的流传和失效先后顺序是不保障的,所谓最终一致性,比方 VirtualService 中援用了某一个 DestinationRule 定义的子版本,然而这个 DestinationRule 资源的流传和失效可能在工夫上落后于 该 VirtualService 资源。
最佳实际:make before break
将更新过程从批量单步拆分为多步骤,确保整个过程中不会援用不存在的 subset:
当新增 DestinationRule subset 时,应该先 apply DestinationRule subset,期待 subset 失效后,再 apply 援用了该 subset 的 VirtualService。
当删除 DestinationRule subset 时,应该先 删除 VirtualService 中对 该 subset 的援用,期待 VirtualService 的批改失效后,在执行删除 DestinationRule subset。
3. 申请中断剖析
申请异样,到底是 istio 流控规定导致,还是业务利用的返回,流量断点呈现在哪个具体的 pod?
这是应用 mesh 最常见的窘境,在微服务中引入 envoy 作为代理后,当流量拜访和预期行为不符时,用户很难疾速确定问题是出在哪个环节。客户端收到的异样响应,诸如 403、404、503 或者连贯中断等,可能是链路中任一 sidecar 执行流量管控的后果,但也有可能是来自某个服务的正当逻辑响应。
envoy 流量模型
Envoy 承受申请流量叫做 Downstream,Envoy 发出请求流量叫做 Upstream。在解决 Downstream 和 Upstream 过程中,别离会波及 2 个流量端点,即申请的发动端和接收端:
在这个过程中,envoy 会依据用户规定,计算出符合条件的转发目标主机汇合,这个汇合叫做 UPSTREAM_CLUSTER, 并依据负载平衡规定,从这个汇合中抉择一个 host 作为流量转发的接收端点,这个 host 就是 UPSTREAM_HOST。
以上就是 envoy 申请解决的 流量五元组信息,这是 envoy 日志里最重要的局部,通过这个五元组咱们能够精确的观测流量「从哪里来」和「到哪里去」。
- UPSTREAM_CLUSTER
- DOWNSTREAM_REMOTE_ADDRESS
- DOWNSTREAM_LOCAL_ADDRESS
- UPSTREAM_LOCAL_ADDRESS
- UPSTREAM_HOST
日志剖析示例
通过日志重点观测 2 个信息:
- 断点是在哪里?
- 起因是什么?
示例一:一次失常的 client-server 申请
能够看到 2 端日志蕴含雷同的 request ID,因而能够将流量剖析串联起来。
示例二:no healthy upstream, 比方指标 deployment 衰弱正本数为 0
日志中 flag「UH」示意 upstream cluster 中没有衰弱的 host。
示例三:No route configured , 比方 DestinationRule 不足对应的 subset
日志中 flag「NR」示意找不到路由。
示例四,Upstream connection failure,比方服务未失常监听端口。
日志中 flag「UF」示意 Upstream 连贯失败,据此能够判断出流量断点地位。
4. sidecar 和 user container 启动程序
异样形容
Sidecar 模式在 kubernetes 世界很风行,但对目前的 k8s(V1.17)来说,并没有 sidecar 的概念,sidecar 容器的角色是用户主观赋予的。
对 Istio 用户来说,一个常见的困扰是:sidecar 和用户容器的启动程序:
sidecar(envoy)和用户容器的启动程序是不确定的,如果用户容器先启动了,envoy 还未实现启动,这时候用户容器往外发送申请,申请依然会被拦挡,发往未启动的 envoy,申请异样。
在 Pod 终止阶段,也会有相似的异样,本源依然是 sidecar 和一般容器的生命周期的不确定性。
解决方案
目前惯例的躲避计划次要是有这样几种:
- 业务容器提早几秒启动, 或者失败重试
- 启动脚本中被动探测 envoy 是否 ready,如
127.0.0.1:15020/ healthz/ready
无论哪种计划都显得很糟糕,为了彻底解决上述痛点,从 kubernets 1.18 版本开始,k8s 内置的 Sidecar 性能将确保 sidecar 在失常业务流程开始之前就启动并运行,即通过更改 pod 的启动生命周期,在 init 容器实现后启动 sidecar 容器,在 sidecar 容器就绪后启动业务容器,从启动流程上保障程序性。而 Pod 终止阶段,只有当所有一般容器都已达到终止状态, 才会向 sidecar 容器发送 SIGTERM 信号。
5. Ingress Gateway 和 Service 端口联动
Ingress Gateway 规定不失效的一个常见起因是:Gateway 的监听端口在对应的 k8s Service 上没有开启,首先咱们须要了解 Istio Ingress Gateway 和 k8s Service 的关系:
上图中,尽管 gateway 定义冀望管控端口 b 和 c,然而它对应的 service(通过腾讯云 CLB)只开启了端口 a 和 b,因而最终从 LB 端口 b 进来的流量能力被 istio gateway 管控。
- Istio Gateway 和 k8s Service 没有间接的关联,二者都是通过 selector 去绑定 pod,实现间接关联
- Istio CRD Gateway 只实现了将用户流控规定下发到网格边缘节点,流量仍须要通过 LB 管制能力进入网格
- 腾讯云 tke mesh 实现了 Gateway-Service 定义中的 Port 动静联动,让用户聚焦在网格内的配置。
6. VirtualService 作用域
VirtualService 蕴含了大部分 outbound 端的流量规定,它既能够利用到网格外部数据面代理中,也能够利用到网格边缘的代理中。
VirtualService 的属性 gateways
用于指定 VirtualService 的失效范畴:
- 如果
VirtualService.gateways
为空,则 istio 为其赋默认值mesh
, 代表失效范畴为网格外部 - 如果心愿 VirtualService 利用到具体边缘网关上,则须要显示为其赋值:
gateway-name1,gateway-name2...
- 如果心愿 VirtualService 同时利用到网格外部和边缘网关上,则须要显示地把
mesh
值退出VirtualService.gateways
,如mesh,gateway-name1,gateway-name2...
一个常见的问题是以上的第三种状况,VirtualService 最开始作用于网关外部,后续要将其规定扩大到边缘网关上,用户往往只会增加具体 gateway name,而脱漏mesh
:
Istio 主动给 VirtualService.gateways
设置默认值,本意是为了简化用户的配置,然而往往会导致用户利用不当,一个 feature 一不小心会被用成了 bug。
7. VirtualService 不反对 host fragment
异样案例
对某一 host 新增、批改 VirtualService,发现规定始终无奈失效,排查发现存在其余 VirtualService 也对该 host 利用了其余规定,规定内容可能不抵触,但还是可能呈现其中一些规定无奈失效的状况。
背景
- VirtualService 里的规定,依照 host 进行聚合
- 随着业务的增长,VirtualService 的内容会快速增长,一个 host 的流控规定,可能会由不同的团队散布保护。如平安规定和业务规定离开,不同业务依照子 path 离开
目前 istio 对 cross-resource VirtualService 的反对状况:
- 在网格边缘(gateway),同一个 host 的流控规定,反对散布到多个 VirtualService 对象中,istio 主动聚合,但依赖定义程序以及用户自行防止抵触。
- 在网格外部(for sidecar),同一个 host 的流控规定,不反对散布到多个 VirtualService 对象中,如果同一个 host 存在多个 VirtualService,只有第一个 VirtualService 失效,且没有冲突检测。
VirtualService 不能很好反对 host 规定分片,使得团队的保护职责不能很好的解耦,配置人员须要知悉指标 host 的所有流控规定,才有信念去批改 VirtualService。
Istio 解决方案:Virtual Service chaining(plan in 1.6)
Istio 打算在 1.6 中反对 Virtual Service 代理链:
- Virtual Service 反对分片定义 + 代理链
- 反对团队对同一 host 的 Virtual Service 进行灵便分片,比方依照 SecOps/Netops/Business 个性拆散,各团队保护各种独立的 Virtual Service
8. 全链路跟踪并非齐全通明接入
异样案例
微服务接入后 service mesh 后,链路跟踪数据没有造成串联。
起因
service mesh 遥测零碎中,对调用链跟踪的实现,并非齐全的零入侵,须要用户业务作出大量的批改能力反对,具体地,在用户收回(http/grpc)RPC 时,须要被动将上游申请中存在的 B3 trace headers
写入上游 RPC 申请头中,这些 headers 包含:
有局部用户难以了解:既然 inbound 流量和 outbound 流量曾经齐全被拦挡到 envoy,envoy 能够实现齐全的流量管控和批改,为什么还须要利用显示第传递 headers?
对于 envoy 来说,inbound 申请和 outbound 申请齐全是独立的,envoy 无奈感知申请之间的关联。实际上这些申请到底有无上下级关联,齐全由利用本人决定。举一个非凡的业务场景,如果 Pod X 接管到 申请 A,触发的业务逻辑是:每隔 10 秒 发送一个申请到 Pod Y,如 B1,B2,B3,那么这些扇出的申请 Bx(x=1,2,3…),和申请 A 是什么关系?业务可能有不同的决策:认为 A 是 Bx 的父申请,或者认为 Bx 是独立的顶层申请。
9. mTLS 导致连贯中断
在开启 istio mTLS 的用户场景中,拜访呈现 connection termination
是一个高频的异样:
这个异样的起因和 DestinationRule 中的 mTLS 配置无关,是 istio 中一个不强壮的接口设计。
- 当通过 MeshPolicy 开启全局 mTLS,如果网格中没有定义其余的 DestinationRule,mTLS 失常运行
- 如果后续网格中新增了 DestinationRule,而 DestinationRule 中能够笼罩子版本的 mTLS 值(默认是不开启!), 用户在应用 DestinationRule 时,往往很少去关注 mTLS 属性(留空)。最终导致增 DestinationRule 后 mTLS 变成了不开启,导致
connection termination
- 为了修复以上问题,用户不得不在所有 DestinationRule 中减少 mTLS 属性并设置为开启
这种 istio mtls 用户接口极度不敌对,尽管 mtls 默认做到了全局通明,业务感知不到 mtls 的存在,然而一旦业务定义了 DestinationRule,就必须要晓得以后 mtls 是否开启,并作出调整。试想 mtls 配置交由平安团队负责,而业务团队负责各自的 DestinationRule,团队间的耦合会十分重大。
10. 用户服务监听地址限度
异样形容
如果用户容器中业务过程监听的地址是具体 ip (pod ip),而不是0.0.0.0
, 该用户容器无奈失常接入 istio,流量路由失败。这是又一个挑战 Istio 最大透明化(Maximize Transparency)设计指标 的场景。
起因剖析
Istio-proxy 中的一段 iptables:
其中,ISTIO_IN_REDIRECT 是 virtualInbound, 端口 15006;ISTIO_REDIRECT 是 virtualOutbound,端口 15001。
关键点是规定二:如果 destination 不是 127.0.0.1/32, 转给 15006 (virtualInbound, envoy 监听),这里导致了对 pod ip 的流量始终会回到 envoy。
对该规定的解释:
# Redirect app calls back to itself via Envoy when using the service VIP or endpoint # address, e.g. appN => Envoy (client) => Envoy (server) => appN.
该规定是心愿在这里起作用: 假如以后 Pod a 属于 service A, Pod 中用户容器通过服务名拜访服务 A, envoy 中负载平衡逻辑将这次拜访转发到了以后的 pod ip, istio 心愿这种场景服务端依然有流量管控能力. 如图示:
革新倡议
倡议利用在接入 istio 之前,调整服务监听地址,应用 0.0.0.0
而不是具体 IP。如果业务方认为革新难度大,能够参考之前分享的一个解决方案:服务监听 pod ip 在 istio 中路由异样剖析
【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!