成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Kubernetes 驚天地泣鬼神之大Bug

云計(jì)算
自從三月份生產(chǎn)、非生產(chǎn)全面上線 Kubernetes 后,本以為部署的問(wèn)題可以舒一口氣了,但是斷斷續(xù)續(xù)在生產(chǎn)、非生產(chǎn)環(huán)境發(fā)現(xiàn)一個(gè)詭異的問(wèn)題,這禮拜又調(diào)試了三天,在快要放棄的時(shí)候居然找到原因了,此缺陷影響目前(2018-5-23)為止所有 Kubernetes 版本(見(jiàn)后面更新,夸大了)。

自從三月份生產(chǎn)、非生產(chǎn)全面上線 Kubernetes 后,本以為部署的問(wèn)題可以舒一口氣了,但是斷斷續(xù)續(xù)在生產(chǎn)、非生產(chǎn)環(huán)境發(fā)現(xiàn)一個(gè)詭異的問(wèn)題,這禮拜又調(diào)試了三天,在快要放棄的時(shí)候居然找到原因了,此缺陷影響目前(2018-5-23)為止所有 Kubernetes 版本(見(jiàn)后面更新,夸大了),包括 GitHub 當(dāng)前 master 分支,后果是某種情況觸發(fā)下,Kubernetes service 不能提供服務(wù),影響非常惡劣。

問(wèn)題的現(xiàn)象是,在某種情況下,一個(gè)或者多個(gè) Kubernetes service 對(duì)應(yīng)的 Kubernetes endpoints 消失幾分鐘至幾十分鐘,然后重新出現(xiàn),然后又消失,用 "kubectl get ep --all-namespaces" 不斷查詢,可以觀察到一些 AGE 在分鐘級(jí)別的 endpoints 要么忽然消失,要么 AGE 突然變小從一分鐘左右起步。Endpoints 的不穩(wěn)定,必然導(dǎo)致對(duì)應(yīng)的 Kubernetes service 無(wú)法穩(wěn)定提供服務(wù)。有人在 Github 上報(bào)告了 issue,但是一直沒(méi)得到開(kāi)發(fā)人員注意和解決。

首先解釋下 Kubernetes 大體上的實(shí)現(xiàn)機(jī)制,有助于理解下面的破案過(guò)程。

Kubernetes 的實(shí)現(xiàn)原理跟配置管理工具 CFengine、Ansible、Salt 等非常類(lèi)似:configuration convergence——不斷的比較期望的配置和實(shí)際的配置,修訂實(shí)際配置以收斂到期望配置。

Kubernetes 的關(guān)鍵系統(tǒng)服務(wù)有 api-server、scheduler、controller-manager 三個(gè)。api-server 一方面作為 Kubernetes 系統(tǒng)的訪問(wèn)入口點(diǎn),一方面作為背后 etcd 存儲(chǔ)的代理服務(wù)器,Kubernetes 里的所有資源對(duì)象,包括 Service、Deployment、ReplicaSet、DaemonSet、Pod、Endpoint、ConfigMap、Secret 等等,都是通過(guò) api-server 檢查格式后,以 protobuf 格式序列化并存入 etcd。這就是一個(gè)寫(xiě)入“期望配置”的過(guò)程。

Controller-manager 服務(wù)里包含了很多 controller 實(shí)例,對(duì)應(yīng)各種資源類(lèi)型:

 

001.jpg
v1.12.0-alpha.0/cmd/kube-controller-manager/app/controllermanager.go#L317

這些 controller 做的事情就是收斂:它通過(guò) api-server 的 watch API 去間接的 watch etcd,以收取 etcd 里數(shù)據(jù)的 changelog,對(duì)改變(包括ADD、DELETE、UPDATE)的資源(也就是期望的“配置“),逐個(gè)與通過(guò) kubelet + Docker 收集到的信息(實(shí)際“配置”)做對(duì)比并修正差異。

比如 etcd 里增加了一個(gè) Pod 資源,那么 controller 就要請(qǐng)求 scheduler 調(diào)度,然后請(qǐng)求 kubelet 創(chuàng)建 Pod,如果etcd里刪除了一個(gè) Service 資源,那么就要?jiǎng)h除其對(duì)應(yīng)的 endpoint 資源,而這個(gè) endpoint 刪除操作會(huì)被 kube-proxy 監(jiān)聽(tīng)到而觸發(fā)實(shí)際的 iptables 命令。

注意上面 controller 通過(guò) watch 獲取 changelog 只是一個(gè)實(shí)現(xiàn)上的優(yōu)化,它沒(méi)有周期性的拿出所有的資源對(duì)象然后逐個(gè)判斷,在集群規(guī)模很大時(shí),這樣的全量收斂是很慢的,后果就是集群的調(diào)度、自我修復(fù)進(jìn)行的非常慢。

有了大框架的理解后,endpoints 被誤刪的地方是很容易找到的:

 

002.jpg
v1.12.0-alpha.0/pkg/controller/endpoint/endpoints_controller.go#L396

然后問(wèn)題來(lái)了,什么情況下那個(gè) Services(namespace).Get(name) 會(huì)返回錯(cuò)誤呢?通過(guò)注釋?zhuān)梢钥吹皆?service 刪除時(shí)會(huì)走到 397 行里去,把無(wú)用的 endpoints 刪掉,因?yàn)?endpoint 是給 service 服務(wù)的,service 不存在時(shí),endpoint 沒(méi)有存在的意義。

然后問(wèn)題來(lái)了,通過(guò) "kubectl get svc" 可以看到出問(wèn)題期間,服務(wù)資源一直都在,并沒(méi)有重建,也沒(méi)有剛剛部署,甚至很多服務(wù)資源都是創(chuàng)建了幾個(gè)月,為啥它對(duì)應(yīng)的 endpoints 會(huì)被誤刪然后重建呢?這個(gè)問(wèn)題困擾了我兩個(gè)月,花了很長(zhǎng)時(shí)間和很多腦細(xì)胞,今天在快放棄時(shí)突然有了重大發(fā)現(xiàn)。

由于我司搭建的 Kubernetes 集群開(kāi)啟了 X509 認(rèn)證以及 RBAC 權(quán)限控制,為了便于審查,我開(kāi)啟了 kube-apiserver 的審計(jì)日志,在出問(wèn)題時(shí),審計(jì)日志中有個(gè)特別的模式:

 

003.jpg
用 jq 命令摘取的審計(jì)日志片段

審計(jì)日志中,在每個(gè) endpoint delete & create 發(fā)生前,都有一個(gè) "/api/v1/services...watch=true" 的 watch 調(diào)用,上面講到,controller-manager 要不斷的去爬 etcd 里面資源的 changelog,這里很奇怪的問(wèn)題是,這個(gè)調(diào)用的 "resourceVersion=xxx" 的版本值始終不變,難道不應(yīng)該不斷從 changelog 末尾繼續(xù)爬取因?yàn)?resourceVersion 不斷遞增么?

通過(guò)一番艱苦卓絕的連猜帶蒙,終于找到“爬取changelog”對(duì)應(yīng)的代碼:

 

004.jpg
v1.12.0-alpha.0/staging/src/k8s.io/client-go/tools/cache/reflector.go#L394

上面的代碼對(duì) resourceVersion 的處理邏輯是: 遍歷 event 列表,取當(dāng)前 event 的 "resourceVersion" 字段作為新的要爬取的“起始resourceVersion",所以很顯然遍歷結(jié)束后,"起始resourceVersion" 也就是***一條 event 的 "resourceVersion"。

好了,我們來(lái)看看 event 列表漲啥樣,把上面 api-server 的請(qǐng)求照搬就可以看到了:

 

  1. kubectl proxy 
  2. curl -s localhost:8001/api/v1/services?resourceVersion=xxxx&timeoutSeconds=yyy&watch=t 

 

005.jpg
/api/v1/services 的輸出,僅示意,注意跟上面的審計(jì)日志不是同一個(gè)時(shí)間段的

可以很明顯看到,坑爹,resourceVersion 不是遞增的!

這個(gè)非遞增的問(wèn)題其實(shí)很容易想明白,resourceVersion 并不是 event 的序列號(hào),它是 Kubernetes 資源自身的版本號(hào),如果把 etcd 看作 Subversion,兩者都有一個(gè)全局遞增的版本號(hào),把 Kubernetes 資源看作 Subversion 里保存的文件。 在 svn revision=100 時(shí)存入一個(gè)文件 A,那么A的版本是 100,然后不斷提交其它文件的修改到 svn,然后在某個(gè)版本刪掉 A,此時(shí)用 svn log 看到的相關(guān)文件的“自身***一次修改版本”并不是遞增的,***一條的“自身***一次修改版本”是 100。

所以真相大白了,reflector.go 那段遍歷 etcd "changelog" 的代碼,誤以為 event 序列的 resourceVersion 是遞增的了,雖然絕大部分時(shí)候是這樣的。由于這段代碼是通用的,所有資源都受這個(gè)影響,所以是非常嚴(yán)重的 bug,之前看到很多人報(bào)告(我自己也遇到)controller-manager 報(bào)錯(cuò) "reflector.go:341] k8s.io/kubernetes/pkg/controller/bootstrap/bootstrapsigner.go:152: watch of *v1.ConfigMap ended with: too old resource version: " 很可能也是這個(gè)導(dǎo)致的,因?yàn)樗д`從很老的 resourceVersion 開(kāi)始爬取 etcd "changelog",但 etcd 已經(jīng)把太老的 changelog 給 “compact” 掉了。

***總結(jié)下怎么觸發(fā)以及繞過(guò)這個(gè) bug:

觸發(fā)

陸續(xù)創(chuàng)建、刪除、創(chuàng)建 Kubernetes service 對(duì)象,然后"kubectl delete svc xxx"刪掉創(chuàng)建時(shí)間靠前的 service,也就是往 service event list 末尾插入了一條 resourceVersion 比較小的記錄,這將使得 controller-manager 去從已經(jīng)爬過(guò)的 service event list 位置重新爬取重放,然后就重放了 service 的 ADDED、DELETED event,于是 controller-manager 內(nèi)存里緩存的 service 對(duì)象被刪除,導(dǎo)致 EndpointController 刪除了“不存在的”service 對(duì)應(yīng)的 endpoints。

繞過(guò)

用 docker restart 重啟 kube-controller-manager 容器,強(qiáng)迫其從 event list ***位置開(kāi)始爬取

創(chuàng)建一個(gè) service,其 resourceVersion 會(huì)是 etcd 的***全局版本號(hào),這個(gè) ADDED event 會(huì)出現(xiàn)在 event list 末尾,從而 controller-manager 從這個(gè)***的 resourceVersion 開(kāi)始爬取

"kubectl edit" 修改某個(gè) service,加點(diǎn)無(wú)意義的 label 之類(lèi)的,保存,這樣其 resourceVersion 也會(huì)更新,之后跟上一個(gè) workaround 原理一樣了。

錯(cuò)誤的繞過(guò)方式

  • "kubectl delete pod/xxx":不影響 service event list
  • "kubectl delete deploy/xxxx":不影響 service event list

Kubernetes 里凡是創(chuàng)建后基本不變的資源,比如 service、configmap、secrets 都會(huì)受這個(gè)影響,它們的版本號(hào)都很久,刪一個(gè)后都會(huì)觸發(fā)這個(gè) bug,比如 configmap,可能就會(huì)被重復(fù)的更新,映射到容器里的 config file 也就不斷更新,對(duì)于不支持 config hot reload 的服務(wù)沒(méi)有影響,對(duì)于支持 config hot reload 的服務(wù),會(huì)頻繁的重新加載配置文件重新初始化,可能導(dǎo)致意想不到的問(wèn)題。

Bug 的修復(fù)很簡(jiǎn)單,在遍歷 event list 選擇 resourceVersion 時(shí),總是取 max(event.resourceVersion, currentResourceVersion) 即可,我提了個(gè) pull request 給 Kubernetes 官方看看,希望我這個(gè)粗暴的修正不會(huì)帶來(lái)新的問(wèn)題。

責(zé)任編輯:未麗燕 來(lái)源: 知乎專(zhuān)欄
相關(guān)推薦

2012-12-28 11:03:02

2024-07-03 12:01:36

2025-06-10 04:11:00

2017-07-18 10:05:58

2009-11-24 09:44:59

WIN7chrome谷歌

2016-01-11 10:10:53

2019-01-22 10:10:07

2023-05-10 09:42:39

代碼開(kāi)源

2023-11-17 22:56:47

ChatGPTAI

2023-03-31 11:36:52

阿里中臺(tái)架構(gòu)

2019-07-29 10:46:14

HTTPHTTP 3HTTP 2

2021-09-13 15:54:01

程序員技能開(kāi)發(fā)者

2013-11-26 15:44:25

Android設(shè)計(jì)模式

2013-12-13 09:31:43

2010-05-21 17:19:15

2012-04-26 22:41:13

2012-07-26 15:15:03

微軟Office2013蘋(píng)果

2019-10-17 10:12:02

Go語(yǔ)言Java函數(shù)

2015-08-27 16:55:09

2012-07-19 13:50:11

Power7+IBM
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩视频免费看 | 久久99精品久久久久婷婷 | 免费日本视频 | 毛片区| 欧美在线一区二区三区 | 精精国产xxxx视频在线播放 | 黑人巨大精品欧美一区二区免费 | 久久精品久久精品久久精品 | 在线观看视频中文字幕 | 国产羞羞视频在线观看 | 精品国产乱码久久久久久牛牛 | 中文字幕精品一区久久久久 | 午夜丰满寂寞少妇精品 | 国产精品a一区二区三区网址 | 婷婷综合激情 | 日韩一区二区三区在线观看 | 欧美日韩精品一区二区三区四区 | 一级大片 | www国产亚洲精品久久网站 | 中文字幕精品一区二区三区精品 | 欧美一级特黄aaa大片在线观看 | 91大神在线资源观看无广告 | 久久久www成人免费无遮挡大片 | 亚洲美女在线一区 | 久久久久国产精品一区二区 | 一级毛片在线播放 | 精品国产99| 日韩成人免费视频 | 国产日韩一区二区三区 | 天天操天天舔 | 插插宗合网 | 亚洲国产成人精品久久久国产成人一区 | 国产精品一区二区三区在线 | 91久久网站 | 久久久www成人免费精品张筱雨 | 欧美在线一区二区三区四区 | 亚洲欧美自拍偷拍视频 | 精品国产一区二区三区性色av | 天天草天天操 | 国产精品夜色一区二区三区 | 日韩免费视频一区二区 |