晚上發現,使用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
。
(完,掰掰, (:△」∠))