晚上发现,使用Kubernetes CronJob创建定时任务时,CronJob创建的实例发送HTTP请求到同集群内的其他服务,返回404。但第二天早上突然好了,非常神奇。
前提条件:
CronJob创建的Pod没有Istio proxy组件,无法访问一个有Istio Proxy的Pod
一个有Istio Proxy的Pod可以访问另一个有一个有Istio Proxy的Pod
偶发性,有时CronJob创建的Pod可以访问一个有Istio Proxy的Pod
以下是记录排查过程
发现CronJob 无法访问其他服务实例,先试试是不是连不上网,这样可以去找运维处理。
能ping通,那就是Kubernetes集群内部的问题。再试试,能不能ping通其他的node ip,… …嗯,也能ping 通。
或许是代码写的有问题?毕竟是日日夜夜写Bug,写些Bug也情有可原。
用kubectl exec
命令 登录到这个pod上,用wget访问出问题的那个接口
也是404,那还好代码依然没出Bug,好的代码就是这么自信。那就是天灾,集群网络出了问题。
用计算机网络的思路想想,Http Status Code 404,应用层报的错。看看别的Pod能不能访问这个接口。
于是从这个Pod部署的Node节点上,找了一个别的Pod,亦然用kubectl exec
命令登陆进去,wget他。
嗯,没问题。
看问题就集中在CronJob无法访问其他Pod。
根据流量流转模型
从 Kube-Proxy到pod 或者 从Istio Side-Car Proxy到Pod 都是没有问题的,否则其他服务同样无法访问。
开始控制变量法思考,两个实例之间有什么区别。
两个Pod之间应该只差了一个Istio Proxy,那么先注入进去看看。
嗯 可以了。
但现在依然有两个问题:
- 我并不知道为什么这个问题是偶发性的
- 注入Istio Proxy的Pod无法被CronJob控制,即Pod达到Completed状态时,依然会以 1/2的形式存在,CronJob无法启动新的Pod
问题1还要继续分析下去
问题2解决方案至少有两个,google上查Better support for sidecar containers in batch jobs就能查出来
看了一下我们的网络架构,访问的Service下有两种实例,线上实例和灰发实例。这两种实例通过Deployment文件里的Lable区分开。Service在做Pod之间负载均衡的时候,会有策略去访问。我估计应该CronJob创建的实例在流量到Service时,不知道访问那个Pod,所以报了404。
但我通过在CronJob中的JobTemplate中添加了相应的Label变量,亦然是404。
然后看了一下VirtualService
和DestinationRule
,还是没有什么头绪。决定先看看这个Istio Proxy加和不加有没有什么区别。
翻了一遍Istio 的 VirtualService
和DestinationRule
的文档,前者是流量对于Service
的选择,他可以选择流量进入哪一个Service
的哪一个Pod
中, DestinationRule
就是对那个Pod
的定义。我发现在VirtualService
中并没有这样的定义,导致从出问题的Pod
出去的流量不知道应该选择哪一个目标Service
的Pod
最终导致404。非常符合我的猜想。
然后给VirtualService
加了一个路由选择的条件
spec:
hosts:
- "virtual-host"
http:
- match:
- sourceLabels:
type: normal
route:
- destination:
host: virtual-host
subset: normal
即请求中的host
是virtual-host
且请求发送的Pod
带有normal
标签(Label
)会被导入到 host
是virtual-host
的Service
的normal
子集中。
同时,还应该在DestinationRule
中对这个normal
子集,进行定义。
这里Debug的时候遇到了两个坑。第一个是不允许出现多个VirtualService
指向同一个host
,否则Istio Proxy会报错
第二个问题是,更新完VirtualService
,记得要把CronJob
删除掉,重新建一个才有用。
估计偶发性是因为灰度发布的时候,路由会根据Pod
所带的Label
进行路由选择,这个时候我的Pod
由于没有带label
所以不知道选择正常的Pod
还是灰度的Pod
。一旦不在灰度发布时段,由于只有一种Pod
所以就默认选择了正常的Pod
。
(完,掰掰, (:△」∠))