凌晨 12 点突发 Istio 生产事故!一顿操作猛如虎解决了

在一次业务切换中,由于 Istio 未代理 7000 端口导致 502 错误。经过分析,发现 7000 端口流量未被转发,其他端口正常。通过三种解决方案:Service Entry、调整 includeIPRanges 配置和创建 Service 手动管理外部服务,最终解决了问题。推荐使用 Service Entry 方案,以保持 Istio 的流量控制功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

事故起因

业务上新集群,本来以为"洒洒水",11 点切,12 点就能在家睡觉了。流量切过来后,在验证过程中,发现网页能够正常打开,在登录时返回了 502,当场懵逼。在相关的容器日志发现一个高频的报错条目“7000 端口无法连接”,向业务组了解到这是 redis 集群中的一个端口,前后端是通过 redis 交互的,该集群同时还有 7001-7003 其它三个端口。

用 nc 命令对 redis 集群进行连接测试:向服务端发送 keys * 命令时,7000 端口返回的是 HTTP/1.1 400 Bad Request,其他三个端口是 redis 返回的 -NOAUTH Authentication required。

	$ nc 10.0.0.6 7000
	keys *
	HTTP/1.1 400 Bad Request
	content-length: 0
	connection: close

	$ nc 10.0.0.6 7003
	keys *
	-NOAUTH Authentication required

判断 7000 端口连接到了其他应用上,至少不是 redis。在宿主机上抓包发现没有抓到访问 7000 端口的流量,然后查看容器的 nf_conntrackb 表,发现 7000 端口的数据只有到本地的会话信息;7003 的有两条会话信息,一条到本机的,一条到目标服务器的。

	$ grep 7000 /proc/net/nf_conntrack
	ipv4     2 tcp      6 110 TIME_WAIT src=10.64.192.14 dst=10.0.0.6 sport=50498 dport=7000 src=127.0.0.1 dst=10.64.192.14 sport=15001 dport=50498 [ASSURED] mark=0 zone=0 use=2

	$ grep 7003 /proc/net/nf_conntrack
	ipv4     2 tcp      6 104 TIME_WAIT src=10.64.192.14 dst=10.0.0.6 sport=38952 dport=7003 src=127.0.0.1 dst=10.64.192.14 sport=15001 dport=38952 [ASSURED] mark=0 zone=0 use=2
	ipv4     2 tcp      6 104 TIME_WAIT src=10.64.192.14 dst=10.0.0.6 sport=38954 dport=7003 src=10.0.0.6 dst=10.64.192.14 sport=7003 dport=38954 [ASSURED] mark=0 zone=0 use=2

由此判断出 istio 没有代理转发出 7000 的流量,这突然就触及到了我的知识盲区,一大堆人看着,办公室 26 度的空调,一直在冒汗。没办法了,在与业务商量后,只能先关闭 istio 注入,优先恢复了业务。回去后恶补 istio 的相关资料。终于将问题解决。记录下相关信息,以供日后参考。

背景知识补充

istio 的 Sidecar 有两种模式:

  • ALLOW_ANY:istio 代理允许调用未知的服务,黑名单模式。

  • REGISTRY_ONLY:istio 代理会阻止任何没有在网格中定义的 HTTP 服务或 service entry 的主机,白名单模式。

istio-proxy(Envoy)的配置结构

istio-proxy(Envoy)的代理信息大体由以下几个部分组成:

  • Cluster:在 Envoy 中,Cluster 是一个服务集群,Cluster 中包含一个到多个 endpoint,每个 endpoint 都可以提供服务,Envoy 根据负载均衡算法将请求发送到这些 endpoint 中。Cluster 分为 inbound 和 outbound 两种,前者对应 Envoy 所在节点上的服务;后者占了绝大多数,对应 Envoy 所在节点的外部服务。可以使用如下方式分别查看 inbound 和 outbound 的 Cluster。

  • Listeners:Envoy 采用 listener 来接收并处理 downstream 发过来的请求,可以直接与 Cluster 关联,也可以通过 rds 配置路由规则(Routes),然后在路由规则中再根据不同的请求目的地对请求进行精细化的处理。

  • Routes:配置 Envoy 的路由规则。istio 下发的缺省路由规则中对每个端口(服务)设置了一个路由规则,根据 host 来对请求进行路由分发,routes 的目的为其他服务的 Cluster。

  • Endpoint:Cludter 对应的后端服务,可以通过 istio pc endpoint 查看 inbound 和 outbound 对应的 endpoint 信息。

服务发现类型

Cluster 的服务发现类型主要有:

  • ORIGINAL_DST:ORIGINAL_DST 类型的 Cluster,Envoy 在转发请求时会直接采用 downstream 请求中的原始目的地 IP 地址。

  • EDS:EDS 获取到该 Cluster 中所有可用的 Endpoint,并根据负载均衡算法(缺省为 Round Robin)将 Downstream 发来的请求发送到不同的 Endpoint。istio 会自动为集群中的 service 创建代理信息,listener 的信息从 service 获取,对应的 Cluster 被标记为 EDS 类型。

  • STATIC:缺省值,在集群中列出所有可代理的主机 Endpoints。当没有内容为空时,不进行转发。

  • LOGICAL_DNS:Envoy 使用 DNS 添加主机,但如果 DNS 不再返回时,也不会丢弃。

  • STRICT_DNS:Envoy 将监控 DNS,而每个匹配的 A 记录都将被认为是有效的。

两个特殊集群

BlackHoleCluster:黑洞集群,匹配此集群的流量将被不会被转发。

	{
			"name": "BlackHoleCluster",
			"type": "STATIC",
			"connectTimeout": "10s"
	}

类型为 static,但是没有指定可代理的 Endpoint,所以流量不会被转发。

PassthroughCluster:透传集群,匹配此集群的流量数据包的目的 IP 不会改变。

	{
			"name": "PassthroughCluster",
			"type": "ORIGINAL_DST",
			"connectTimeout": "10s",
			"lbPolicy": "CLUSTER_PROVIDED",
			"circuitBreakers": {
				 "thresholds": [
						{
								"maxConnections": 4294967295,
								 "maxPendingRequests": 4294967295,
								 "maxRequests": 4294967295,
								 "maxRetries": 4294967295
							}
					]
	 }

类型为 original_dst,流量将原样转发。

一个特殊的 Listener

istio 中有一个特殊的 Listener 叫 virtualOutbound,定义如下:

virtualOutbound:每个 Sidecar 都有一个绑定到 0.0.0.0:15001 的 listener,该 listener 下关联了许多 virtual listener。iptables 会先将所有出站流量导入该 listener,该 listener 有一个字段 useOriginalDst 设置为 true,表示会使用最佳匹配原始目的地的方式将请求分发到 virtual listener,如果没有找到任何 virtual listener,将会直接发送到数据包原目的地的 PassthroughCluster。

useOriginalDst 字段的具体意义是,如果使用 iptables 重定向连接,则代理接收流量的目标地址可能与原始目标地址不同。当此标志设置为 true 时,侦听器会将重定向流量转交给与原始目标地址关联的侦听器。如果没有与原始目标地址关联的侦听器,则流量由接收它的侦听器处理。默认为 false。

virtualOutbound 的流量处理流程如图所示:

file

这是 virtualOutbound 的部分配置:

	{
		 "name": "envoy.tcp_proxy",
		 "typedConfig": {
				"@type": "type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy",
				"statPrefix": "PassthroughCluster",
				"cluster": "PassthroughCluster"
			 }
	}
	……………
	"useOriginalDst": true

istio 的 outbond 流量处理

开启流量治理后,pod 访问外部资源的流量转发路径如图所示:

file

istio 注入后 istio-proxy 有一个监听在 15001 的端口,所有非 istio-proxy 用户进程产生的 outbond 流量,通过 iptables 规则被重定向到 15001。

	# Sidecar 注入的 pod 监听的端口
	$ ss -tulnp
	State       Recv-Q Send-Q             
为什么使用istio:云平台令使用它们的公司受益匪浅。但不可否认的是,上云会给 DevOps 团队带来压力。为了可移植性,开发人员必须使用微服务来构建应用,同时运维人员也正在管理着极端庞大的混合云和多云的部署环境。 Istio 允许您连接、保护、控制和观察服务。从较高的层面来说,Istio 有助于降低这些部署的复杂性,并减轻开发团队的压力。它是一个完全开源的服务网格,作为透明的一层接入到现有的分布式应用程序里。它也是一个平台,拥有可以集成任何日志、遥测和策略系统的 API 接口。Istio 多样化的特性使您能够成功且高效地运行分布式微服务架构,并提供保护、连接和监控微服务的统一方法。教学内容:istio原理,envoy原理,envoy案例,envoy配置,istio crd配置,istio流量管理,istio安全配置,istio可观察性,istio策略控制,istio升级,istio常见问题,istio wasm,istio多控制面板,gateway-api,slime教学特色:a.1000多个istio实战案例,20多个envoy案例。800多个envoyfilter案例,全程已实战为主,理论相对较少,案例90%可试验b.涵盖98%以上crd字段配置c.不仅讲解yaml配置,同时结合envoy配置讲解d.不回避难内容,深入讲解envoyfilter配置e深入讲解envoyf详细讲解额外内容,比如gateway-api,wasm,升降级,发布,灰度发布,蓝绿发布,istioctl命令,slime,多控制面板,多集群,常见问题g以一个完整案例串联所有内容h以markdown文件提供课件,内容详细,方便大家练习I有学员指出我的istio课程不够突出重,安装80/20原则,20%内容是常用的,那我是否就讲这20%就可以了呢,其他课程确实是这么干的,他们只讲擅长的20%,我的目的不是这样的,我希望istio课程买我的一个就够了,让你全面学习istio,甚至遇到偏的问题不需要百度,课程里就有讲过,但是难免会出现一个问题,就是不够突出重,我尽量兼顾全面的时候突出重,讲到重,核心功能时我会提示下。 
要实现每年12月的第一个周六凌晨2的任务调度,可以通过分析 Cron 表达式的各个字段及其含义来构建合适的表达式。 Cron 表达式通常由六个或七个字段组成(视具体实现而定),分别为秒、分、小时、日期、月份、星期以及可选的年份。对于本需求: - **秒**:设为 `0`,因为任务在整触发。 - **分**:设为 `0`,同样是因为任务在整触发。 - **小时**:设为 `2`,表示凌晨。 - **日期**:由于我们关注的是具体的某一天(即 12 月的第一个周六),因此该字段应留为空白或使用特殊字符 `?` 来忽略具体日期[^4]。 - **月份**:设为 `12`,代表十二月。 - **星期**:设为 `6` 或者 `SAT`,表示周六;同时为了限定其为当月的第一周,需附加特殊的标记 `#1`,这表明这是每个月中的第一个周六[^3][^4]。 - **年份**(如果支持):可以省略,因为我们希望此规则适用于每一年。 综合以上各部分,最终得到如下 Cron 表达式: ```cron 0 0 2 ? 12 SAT#1 * ``` 以下是对此表达式的解释: - `0`: 秒数,在第零秒启动; - `0`: 分钟数,在零分钟处运行; - `2`: 小时数,指明于凌晨两时操作; - `?`: 不指定确切的日数值,因已通过星期设定条件; - `12`: 指定仅限于十二月份生效; - `SAT#1`: 定义了只针对每月首度出现之周六工作; - `*`: 对年度无特别限制,默认全年皆适用[^5]。 ### 注意事项 某些系统的 Cron 实现可能并不完全支持上述全部特性,特别是关于“哪一周”的定义(`#`) 和 是否包含秒级别控制等方面存在差异,请确认目标环境的支持情况后再应用该配置。 ```python import schedule import time def job(): print("Task executed at the first Saturday of December, 2 AM.") schedule.every().december.do(job).on_first_saturday.at('02:00') while True: schedule.run_pending() time.sleep(1) ``` 注意这里的 Python 调度库仅为示意,并不一定原生支持如此复杂的 Cron 功能,实际部署仍建议依据系统自带工具完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值