摘要:執(zhí)行該初始化任務的容器被成為初始化容器。目前,有等狀態(tài)。網(wǎng)絡身份的維護主要通過穩(wěn)定的和來維護,他們通過的配置文件指定。若其操作導致最小可用數(shù)低于應用要求,則操作會被拒絕。
本文討論 K8S 1.3 的一些新功能,以及正在進行中的功能。讀者應該對 kubernetes 的基本結構已經(jīng)有所了解。
支持更多類型的應用1、Init container
Init container 是1.3 中的 alpha feature,目的是支持一類需要在啟動 Pod“普通容器”前,先進行 Pod 初始化的應用。執(zhí)行該初始化任務的容器被成為“初始化容器”(init container)。例如,在啟動應用之前,初始化數(shù)據(jù)庫,或等待數(shù)據(jù)庫啟動等。下圖是一個包含 init container 的 Pod:
對于此類 Pod,kubernetes 的運行策略如下:
初始化容器按順序依次執(zhí)行,即圖中容器 1->2;
若其中某一個初始化容器運行失敗,則整個 Pod 失??;
當所有初始化容器運行成功,啟動普通容器,即圖中容器 A 和 B
在 alpha 版本中使用 init container 需要用 annotation,下圖是來自 k8s 的一個例子(略有裁剪):
可以看到,我們在啟動 nginx 普通容器之前,先用 init container 來獲取 index.html,之后訪問 nginx 就會直接返回該文件。當 init container 功能穩(wěn)定后,k8s 會直接在 pod.spec 內加上 init Containers 字段,如下所示:
init container 看起來是一個小功能,但是在實現(xiàn)上還是需要考慮不少問題,比如幾個比較重要的點:
資源問題:當調度存在 init container 的 Pod 時,應該怎樣計算所需要的資源?兩個極端情況:如果對 init container 和 regular container 所需要的資源求和,那么當 init container 成功初始化 Pod 之后,就不會再使用所請求的資源,而系統(tǒng)認為在使用,會造成浪費;反之,不計算 init container 的資源又會導致系統(tǒng)不穩(wěn)定(init container 所使用的資源未被算入調度資源內)。目前的方法是取折中:由于初始化容器和普通容器不會同時運行,因此 Pod 的資源請求是兩者中的最大值。對于初始化容器,由于他們是依次運行,因此選擇其中的最大值;對于普通容器,由于是同時運行,選擇容器資源的和。
Pod Status: 目前,Pod 有 Pending, Running, Terminating 等狀態(tài)。對于有初始化容器的 Pod,如果仍然使用 Pending 狀態(tài),則很難區(qū)分 Pod 當前在運行初始化容器還是普通容器。因此,理想情況下,我們需要增加一個類似于 Initializing 的狀態(tài)。在 alpha 版本中暫時還未添加。
健康檢查及可用性檢查:有了 init container 之后,我們該如何檢查容器的健康狀態(tài)?alpha 版本將兩個檢查都關閉了,但 init container 是會在 node 上實實在在運行的容器,理論上是需要進行檢查的。對于可用性檢查,關閉掉是一個可行的辦法,因為 init container 的可用性其實就是當它運行結束的時候。對于健康檢查,node 需要知道某個 Pod 是否處在初始化階段;如果處在初始化階段,那么 node 就可以對 init container 進行健康檢查。因此,kubernetes 很有可能在添加類似 Initializing 的 Pod 狀態(tài)之后,開啟 init container 的健康檢查。
圍繞 init container 的問題還有很多,比如 QoS,Pod 的更新等等,其中不少都是有待解決的問題,這里就不一一展開了。
2、PetSet
PetSet 應該算是社區(qū)期待已久的功能,其目的是支持有狀態(tài)和集群化的應用,目前也是 alpha 階段。PetSet 的應用場景很多,包括類似 zookeeper、etcd 之類的 quorum leader election 應用,類似 Cassandra 的 Decentralized quorum 等。PetSet 中,每個 Pod 都有唯一的身份,分別包括:名字,網(wǎng)絡和存儲;并由新的組件 PetSet Controller 負責創(chuàng)建和維護。下面依次看一看 kubernetes 是如何維護 Pod 的唯一身份。
名字比較容易理解,當我們創(chuàng)建一個 RC 之后,kubernetes 會創(chuàng)建指定副本數(shù)量的 Pod,當使用 kubectl 獲取 Pod 信息時,我們會得到如下信息:
其中,5 個字符的后綴為 kubernetes 自動生成。當 Pod 重啟,我們會得到不同的名字。對于 PetSet 來講,Pod 重啟必須保證名字不變。因此,PetSet 控制器會維護一個 identityMap,每一個 PetSet 中的每個 Pod 都會有一個唯一名字,當 Pod 重啟,PetSet 控制器可以感知到是哪個 Pod,然后通知 API server 創(chuàng)建新的同名 Pod。目前的感知方法很簡單,PetSet 控制器維護的 identityMap 將 Pod 從 0 開始進行編號,然后同步的過程就像報數(shù)一樣,哪個編號不在就重啟哪個編號。
此外,該編號還有另外一個作用,PetSet 控制器通過編號來確保 Pod 啟動順序,只有 0 號 Pod 啟動之后,才能啟動 1 號 Pod。
網(wǎng)絡身份的維護主要通過穩(wěn)定的 hostname 和 domain name 來維護,他們通過 PetSet 的配置文件指定。例如,下圖是一個 PetSet 的 Yaml 文件(有裁剪),其中 metadata.name 指定了 Pod 的 hostname 前綴(后綴即前面提到的從 0 開始的索引),spec.ServiceName 指定了 domain name。
通過上面的 Yaml 文件創(chuàng)建出來兩個 Pod:web-0 和 web-1。其完整的域名為 web-0.nginx.default.svc.cluster.local,其中 web-0 為 hostname,nginx 為 Yaml 中指定的 domain name,剩下的部分與普通 service 無異。當創(chuàng)建請求被下發(fā)到節(jié)點上時,kubelet 會通過 container runtime 設置 UTS namespace,如下圖所示(省略了部分組件如 apiserver)。
此時,hostname 已經(jīng)在容器層面設置完成,剩下還需要為 hostname 增加集群層面的解析,以及添加 domain name 的解析,這部分工作理所當然就交給了 kube dns。了解 Kubernetes 的讀者應該知道,要添加解析,我們需要創(chuàng)建 service;同理,這里也需要為 PetSet 創(chuàng)建 service。不同的是,普通的 service 默認后端的 Pod 是可替換的,并采用諸如 roundrobin,client ip 的方式選擇后端的 Pod,這里,由于每個 Pod 都是一個 Pet,我們需要定位每一個 Pod,因此,我們創(chuàng)建的 service 必須要能滿足這個要求。在 PetSet 中,利用了 kubernetes headless service。Headless service 不會分配 cluster IP 來 load balance 后端的 Pod,但會在集群 DNS 服務器中添加記錄:創(chuàng)建者需要自己去利用這些記錄。下圖是我們需要創(chuàng)建的 headless service,注意其中的 clusterIP 被設置為 None,表明這是一個 headless service。
Kube dns 進行一番處理之后,會生成如下的記錄:
可以看到,訪問 web-0.nginx.default.svc.cluster.local 會返回 pod IP,訪問 nginx.default.svc.cluster.local 會返回所有 Pet 中的 pods IP。一個常見的方式是通過訪問 domain 的方式來獲取所有的 peers,然后依次和多帶帶的 Pod 通信。
存儲身份這塊采用的是 PV/PVC 實現(xiàn),當我們創(chuàng)建 PetSet 時,需要指定分配給 Pet 的數(shù)據(jù)卷,如下圖:
這里,volumeClaimTemplates 指定每個 Pet 需要的存儲資源。注意目前所有 Pet 都得到相同大小和類型的數(shù)據(jù)卷。當 PetSet 控制器拿到請求時,會為每一個 Pet 創(chuàng)建 PVC,然后將每個 Pet 和對應的 PVC 聯(lián)系起來:
之后的 PetSet 只需要確保每個 Pet 都與相對應的 PVC 綁定在一起即可,其他工作,類似于創(chuàng)建數(shù)據(jù)卷,掛載等工作,都交給其他組件。
通過名字,網(wǎng)絡,存儲,PetSet 能夠 cover 大多數(shù)的案例。但是,目前還存在很多需要完善的地方,感興趣的讀者可以參考:鏈接
3、Scheduled Job
Scheduled Job 本質上是集群 cron,類似 mesos chronos,采用標準的 cron 語法。遺憾的是在 1.3 中還并未達到發(fā)布的標準。Scheduled Job 其實在很早就提出來過,但當時 kubernetes 的重點還在 API 層面,并且即使有很大需求,也計劃在 Job(1.2GA)之后實現(xiàn)。當 scheduled job 在之后的版本發(fā)布之后,用戶可以用一條簡單的命令在 kubernetes 上運行 Job,例如:kubectl run cleanup -image=cleanup --runAt="0 1 0 0 *" -- /scripts/cleanup.sh一些關于 scheduled job 的更新可以參考:鏈接
4、Disruption Budget
Disruption Budget 的提出是為了向 Pod 提供一個反饋機制,確保應用不會被集群自身的變動而受影響。例如,當集群需要進行重調度時,應用可以通過 Disruption Budget 來說明 Pod 能不能被遷移。Disruption Budget 只負責集群自身發(fā)起的變動,不負責突發(fā)事件比如節(jié)點突然掉線,或者應用本身的問題比如不斷重啟的變動。Disruption Budget 同樣沒有在 1.3 中發(fā)布。
與 kubernetes 大多數(shù)資源類似,我們需要通過 Yaml 文件創(chuàng)建一個 PodDisruptionBudget 資源,例如,下圖所示的 Disruption Budget 選中了所有帶有 app:nginx 標簽的 pod,并且要求至少有 3 個 Pod 在同時運行。
Controller manager 內有一個新的組件 Disruption Budget Controller,來負責維護所有 Budget 的狀態(tài),例如上圖中的 status 表明當前共有 4 個健康的 Pod(currentHealthy),應用要求至少有 3 個(desiredHealthy),總共有 5 個Pod(expectedPods)。為了維護這個狀態(tài),Disruption Budget Controller 會遍歷所有的 Budget 和所有的 Pod。有了 Budget 的狀態(tài),需要改變 Pod 狀態(tài)的組件都要先查詢之。若其操作導致最小可用數(shù)低于應用要求,則操作會被拒絕。
Disruption Budget 與 QoS 聯(lián)系很緊密。例如,如果一個 QoS level 很低的應用有著非常嚴格的 Disruption Budget,系統(tǒng)應該如何處理?目前,kubernetes 還沒有嚴格的處理這個問題,一個可行的辦法是對 Disruption Budget 做優(yōu)先級處理,確保高優(yōu)先級的應用擁有高優(yōu)先級的 Disruption Budget;此外,Disruption Budget 可以加入 Quota 系統(tǒng),高優(yōu)先級的應用可以獲得更多 Disruption Budget Quota。關于 Disruption Budget 的討論可以參考:鏈接
支持更好的集群管理1、Cascading Deletion
在 kubernetes 1.2 之前,刪除控制單元都不會刪除底層的資源。例如,通過 API 刪除 RC 之后,其管理的 Pod 不會被刪除(使用 kubectl 可以刪除,但 kubectl 里面有 reaper 邏輯,會依次刪除底層的所有 Pod,本質上是客戶端邏輯)。另外一個例子,當刪除下圖中的 Deployment 時,ReplicaSet 不會被自動刪除,當然,Pod 也不會被回收。
Cascading deletion 指的就是在刪除控制單元后,將被管理單元也同時回收。但是,kubernetes 1.3 中的 cascading deletion 并不是簡單地講 kubectl 中的邏輯復制到 server 端,而是做了更高層次的工作:垃圾回收。簡單來講,garbagecollector controller 維護了幾乎所有集群資源的列表,并接收資源修改的事件。controller 根據(jù)事件類型更新資源關系圖,并將受影響的資源放入 Dirty Queue 或者 Orphan Queue 中。具體實現(xiàn)可以參考官方文檔和 garbage collector controller 實現(xiàn):鏈接
2、Node eviction
Node/kubelet eviction 指的是在節(jié)點將要超負荷之前,提前將 Pod 剔除出去的過程,主要是為了內存和磁盤資源。在 kubernetes 1.3 之前,kubelet 不會“提前”感知節(jié)點的負荷,只會對已知的問題進行處理。當內存吃緊時,kubernetes 依靠內核 OOM killer;磁盤方面則定期對 image 和 container 進行垃圾回收。但是,這種方式有局限性,OOM killer 本身需要消耗一定資源,并且時間上有不確定性;回收容器和鏡像不能處理容器寫日志的問題:如果應用不斷寫日志,則會消耗掉所有磁盤,但不會被 kubelet 處理。
Node eviction 通過配置 kubelet 解決了以上問題。當啟動 kubelet 時,我們通過指定 memory.available, nodefs.available, nodefs.inodesFree 等參數(shù)來確保節(jié)點穩(wěn)定工作。例如,memory.available < 200Mi 表示當內存少于 200Mi時,kubelet 需要開始移除 Pod(可以配置為立即移除或者延遲移除,即 hard vs soft)。kubernetes 1.3 中,node eviction 的特性是 opt-in,默認關閉,可以通過配置 kubelet 打開相關功能。
盡管 node eviction 是 kubelet 層面采取的措施,我們也必須考慮與整個集群的交互關系。其中最重要的一點是如何將這個問題反饋給 scheduler,不然被剔除的 Pod 很有可能會被重新調度回來。為此,kubernetes 添加了新的 node condition:MemoryPressure, DiskPressure。當節(jié)點的狀態(tài)包含其中任意一種時,調度器會避免往該節(jié)點調度新的 Pod。這里還有另外一個問題,即如果節(jié)點的資源使用剛好在閾值附近,那么節(jié)點的狀態(tài)可能會在 Pressure 和 Not Pressure 之間抖動。防抖動的方法有很多種,例如平滑濾波,即將歷史數(shù)據(jù)也考慮在內,加權求值。k8s 目前采用較為簡單的方法:即如果節(jié)點處于 Pressure 狀態(tài),為了轉變成 Not Pressure 狀態(tài),資源使用情況必須低于閾值一段時間(默認 5 分鐘)。這種方法會導致 false alarm,比如,若一個應用每隔一段時間請求一塊內存,之后很快釋放掉,那么可能會導致節(jié)點一直處于 Pressure 狀態(tài)。但大多數(shù)情況下,該方法能處理抖動的情況。
說到 eviction pod,那么另外一個不得不考慮的問題就是找一個倒霉的 Pod。這里 kubernetes 定義了不少規(guī)則,總結下來主要是兩點:1. 根據(jù) QoS 來判斷,QoS 低的應用先考慮;2. 根據(jù)使用量判斷,使用量與總請求量比例大的 Pod 優(yōu)先考慮。具體細節(jié)可以參考:鏈接
3、Network Policy
Network policy 的目的是提供 Pod 之間的隔離,用戶可以定義任意 Pod 之間的通信規(guī)則,粒度為端口。例如,下圖的規(guī)則可以解釋成:擁有標簽“db”的 Pod,只能被擁有標簽“frontend”的 Pod 訪問,且只能訪問 tcp 端口 6379。
Network policy 目前處于 beta 版本,并且只是 API。也就是說,kubernetes 不會真正實現(xiàn)網(wǎng)絡隔離:如果我們將上述 Yaml 文件提交到 kubernetes,并不會有任何反饋,kubernetes 只是保存了這個 Policy 內容。真正實現(xiàn) policy 功能需要其他組件,比如 calico 實現(xiàn)了一個 controller,會讀取用戶創(chuàng)建的 Policy 來實現(xiàn)隔離,可以參考:鏈接。關于 Network Policy 的細節(jié),可以參考:鏈接
4、Federation
Federation cluster 翻譯成中文叫“聯(lián)合集群”,即將多個 kubernetes 集群聯(lián)合成一個整體,并且不改變原始 kubernetes 集群的工作方式。根據(jù) kubernetes 官方設計文檔,federation 的設計目的主要是滿足服務高可用,混合云等需求。在 1.3 版本之前,kubernetes 實現(xiàn)了 federation-lite,即一個集群中的機器可以來自于相同 cloud 的不同 zone;1.3 版本中,federation-full 的支持已經(jīng)是 beta 版本,即每個集群來自不同的 cloud(或相同)。
Federation的核心組件主要是 federation-apiserver 和 federation-controller-manager,以 Pod 形式運行在其中一個集群中。如下圖所示,外部請求直接與 Federation Control Panel 通信,由 Federation 分析請求并發(fā)送至 kubernetes 集群。
在應用層面,F(xiàn)ederation 目前支持 federated services,即一個應用跨多個集群的訪問,具體細節(jié)可以參考:鏈接以及鏈接
結束語kubernetes 1.3 帶來了非常多的特性,這里只 cover 了其中一部分。在安全方面,kubernetes 已經(jīng)支持 RBAC,實現(xiàn)更好的權限控制;PodSecurityContext 也進入 beta 版本,支持運行部分需要特權的 Pod 等。在性能方面,由于 protocol buffere serialization 的引入,是性能提高了幾倍,并且正在醞釀中的 etcd3 會將性能提升更進一步。相信之后的版本會帶給我們更多的驚喜。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/32482.html
摘要:它實現(xiàn)了中的橫向自動擴容。目前只支持針對使用度進行動態(tài)擴容。這個就是真正控制擴容的,其結構如下其中的是一個的引用,定義了自動擴容的配置允許的最大實例數(shù),最小實例數(shù),以及使用配額。這也是為了避免出現(xiàn)頻繁的擴容縮容。 最新一版的kubernetes release中我們看到了一個令人欣喜的特性:Autoscaling。它實現(xiàn)了replicationcontroller中pod的橫向自動擴容...
摘要:序言最近閑暇無事閱讀了一下的源碼對整體的結構有了初步認識與大家分享不知道為什么右邊的目錄一直出不來非常不舒服不如移步到吧是的核心模塊也是個調度模塊各種異步事件都是由他調度的所以必須弄清他的執(zhí)行邏輯源碼分析而的核心部分則是這個循環(huán)內部的邏輯貼 序言 最近閑暇無事,閱讀了一下tornado的源碼,對整體的結構有了初步認識,與大家分享 不知道為什么右邊的目錄一直出不來,非常不舒服. 不如移...
摘要:節(jié)點對不會有影響,查詢處于狀態(tài)并一直保持。根據(jù)上一節(jié)描述,此時已經(jīng)有正確的在其他節(jié)點,此時故障節(jié)點恢復后,執(zhí)行優(yōu)雅刪除,刪除舊的。會從狀態(tài)變?yōu)闋顟B(tài),執(zhí)行優(yōu)雅刪除,,然后執(zhí)行重新調度與重建操作。會從狀態(tài)直接變成狀態(tài),不涉及重建。 節(jié)點離線后的 pod 狀態(tài) 在 kubernetes 使用過程中,根據(jù)集群的配置不同,往往會因為如下情況的一種或幾種導致節(jié)點 NotReady: kubele...
摘要:前言本文將嘗試詳細的帶大家一步步走完一個異步操作從而了解是如何實現(xiàn)異步的其實本文是對上一篇文的實踐和復習主旨在于關注異步的實現(xiàn)所以會忽略掉代碼中的一些異常處理文字較多湊合下吧接下來只會貼出部分源碼幫助理解希望有耐心的同學打開源碼一起跟蹤一遍 前言 本文將嘗試詳細的帶大家一步步走完一個異步操作,從而了解tornado是如何實現(xiàn)異步io的. 其實本文是對[上一篇文][1]的實踐和復習 主...
閱讀 3369·2021-11-24 09:39
閱讀 2925·2021-10-12 10:20
閱讀 1998·2019-08-30 15:53
閱讀 3146·2019-08-30 14:14
閱讀 2660·2019-08-29 15:36
閱讀 1196·2019-08-29 14:11
閱讀 2065·2019-08-26 13:51
閱讀 3496·2019-08-26 13:23