Kubernetes 1.3 current and future

本文討論 K8S 1.3 的一些新功能,以及正在進行中的功能。讀者應該對 kubernetes 的基本結構已經有所瞭解。html

支持更多類型的應用

1 Init containernode

Init container 是1.3 中的 alpha feature,目的是支持一類須要在啓動 Pod「普通容器」前,先進行 Pod 初始化的應用。執行該初始化任務的容器被成爲「初始化容器」(init container)。例如,在啓動應用以前,初始化數據庫,或等待數據庫啓動等。下圖是一個包含 init container 的 Pod:nginx

 

對於此類 Pod,kubernetes 的運行策略以下:git

  • 初始化容器按順序依次執行,即圖中容器 1->2github

  • 若其中某一個初始化容器運行失敗,則整個 Pod 失敗web

  • 當全部初始化容器運行成功,啓動普通容器,即圖中容器 A 和 B數據庫

在 alpha 版本中使用 init container 須要用 annotation,下圖是來自 k8s 的一個例子(略有裁剪):後端

能夠看到,咱們在啓動 nginx 普通容器以前,先用 init container 來獲取 index.html,以後訪問 nginx 就會直接返回該文件。當 init container 功能穩定後,k8s 會直接在 pod.spec 內加上 init Containers 字段,以下所示:api

 

init container 看起來是一個小功能,可是在實現上仍是須要考慮很多問題,好比幾個比較重要的點:安全

資源問題:當調度存在 init container 的 Pod 時,應該怎樣計算所須要的資源?兩個極端狀況:若是對 init container 和 regular container 所須要的資源求和,那麼當 init container 成功初始化 Pod 以後,就不會再使用所請求的資源,而系統認爲在使用,會形成浪費;反之,不計算 init container 的資源又會致使系統不穩定(init container 所使用的資源未被算入調度資源內)。目前的方法是取折中:因爲初始化容器和普通容器不會同時運行,所以 Pod 的資源請求是二者中的最大值。對於初始化容器,因爲他們是依次運行,所以選擇其中的最大值;對於普通容器,因爲是同時運行,選擇容器資源的和。

Pod Status: 目前,Pod 有 Pending, Running, Terminating 等狀態。對於有初始化容器的 Pod,若是仍然使用 Pending 狀態,則很難區分 Pod 當前在運行初始化容器仍是普通容器。所以,理想狀況下,咱們須要增長一個相似於 Initializing 的狀態。在 alpha 版本中暫時還未添加。

健康檢查及可用性檢查:有了 init container 以後,咱們該如何檢查容器的健康狀態?alpha 版本將兩個檢查都關閉了,但 init container 是會在 node 上實實在在運行的容器,理論上是須要進行檢查的。對於可用性檢查,關閉掉是一個可行的辦法,由於 init container 的可用性其實就是當它運行結束的時候。對於健康檢查,node 須要知道某個 Pod 是否處在初始化階段;若是處在初始化階段,那麼 node 就能夠對 init container 進行健康檢查。所以,kubernetes 頗有可能在添加相似 Initializing 的 Pod 狀態以後,開啓 init container 的健康檢查。

圍繞 init container 的問題還有不少,好比 QoS,Pod 的更新等等,其中很多都是有待解決的問題,這裏就不一一展開了 :)

PetSet

PetSet 應該算是社區期待已久的功能,其目的是支持有狀態和集羣化的應用,目前也是 alpha 階段。PetSet 的應用場景不少,包括相似 zookeeper、etcd 之類的 quorum leader election 應用,相似 Cassandra 的 Decentralized quorum 等。PetSet 中,每一個 Pod 都有惟一的身份,分別包括:名字,網絡和存儲;並由新的組件 PetSet Controller 負責建立和維護。下面依次看一看 kubernetes 是如何維護 Pod 的惟一身份。

名字比較容易理解,當咱們建立一個 RC 以後,kubernetes 會建立指定副本數量的 Pod,當使用 kubectl 獲取 Pod 信息時,咱們會獲得以下信息:

其中,5 個字符的後綴爲 kubernetes 自動生成。當 Pod 重啓,咱們會獲得不一樣的名字。對於 PetSet 來說,Pod 重啓必須保證名字不變。所以,PetSet 控制器會維護一個 identityMap,每個 PetSet 中的每一個 Pod 都會有一個惟一名字,當 Pod 重啓,PetSet 控制器能夠感知到是哪一個 Pod,而後通知 API server 建立新的同名 Pod。目前的感知方法很簡單,PetSet 控制器維護的 identityMap 將 Pod 從 0 開始進行編號,而後同步的過程就像報數同樣,哪一個編號不在就重啓哪一個編號。

此外,該編號還有另一個做用,PetSet 控制器經過編號來確保 Pod 啓動順序,只有 0 號 Pod 啓動以後,才能啓動 1 號 Pod。

網絡身份的維護主要經過穩定的 hostname 和 domain name 來維護,他們經過 PetSet 的配置文件指定。例如,下圖是一個 PetSet 的 Yaml 文件(有裁剪),其中 metadata.name 指定了 Pod 的 hostname 前綴(後綴即前面提到的從 0 開始的索引),spec.ServiceName 指定了 domain name。


       經過上面的 Yaml 文件建立出來兩個 Pod:web-0 和 web-1。其完整的域名爲 web-0.nginx.default.svc.cluster.local,其中 web-0 爲 hostname,nginx 爲 Yaml 中指定的 domain name,剩下的部分與普通 service 無異。當建立請求被下發到節點上時,kubelet 會經過 container runtime 設置 UTS namespace,以下圖所示(省略了部分組件如 apiserver)。

此時,hostname 已經在容器層面設置完成,剩下還須要爲 hostname 增長集羣層面的解析,以及添加 domain name 的解析,這部分工做理所固然就交給了 kube dns。瞭解 Kubernetes 的讀者應該知道,要添加解析,咱們須要建立 service;同理,這裏也須要爲 PetSet 建立 service。不一樣的是,普通的 service 默認後端的 Pod 是可替換的,並採用諸如 roundrobin,client ip 的方式選擇後端的 Pod,這裏,因爲每一個 Pod 都是一個 Pet,咱們須要定位每個 Pod,所以,咱們建立的 service 必需要能知足這個要求。在 PetSet 中,利用了 kubernetes headless service。Headless service 不會分配 cluster IP 來 load balance 後端的 Pod,但會在集羣 DNS 服務器中添加記錄:建立者須要本身去利用這些記錄。下圖是咱們須要建立的 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 實現,當咱們建立 PetSet 時,須要指定分配給 Pet 的數據卷,以下圖:

這裏,volumeClaimTemplates 指定每一個 Pet 須要的存儲資源。注意目前全部 Pet 都獲得相同大小和類型的數據卷。當 PetSet 控制器拿到請求時,會爲每個 Pet 建立 PVC,而後將每一個 Pet 和對應的 PVC 聯繫起來:

以後的 PetSet 只須要確保每一個 Pet 都與相對應的 PVC 綁定在一塊兒便可,其餘工做,相似於建立數據卷,掛載等工做,都交給其餘組件。

經過名字,網絡,存儲,PetSet 可以 cover 大多數的案例。可是,目前還存在不少須要完善的地方,感興趣的讀者能夠參考:https://github.com/kubernetes/kubernetes/issues/28718

3 Scheduled Job

Scheduled Job 本質上是集羣 cron,相似 mesos chronos,採用標準的 cron 語法。遺憾的是在 1.3 中還並未達到發佈的標準。Scheduled Job 其實在很早就提出來過,但當時 kubernetes 的重點還在 API 層面,而且即便有很大需求,也計劃在 Job(1.2GA)以後實現。當 scheduled job 在以後的版本發佈以後,用戶能夠用一條簡單的命令在 kubernetes 上運行 Job,例如:kubectl run cleanup -image=cleanup --runAt="0 1 0 0 *"  -- /scripts/cleanup.sh一些關於 scheduled job 的更新能夠參考:https://github.com/kubernetes/kubernetes/pull/25595

4 Disruption Budget

Disruption Budget 的提出是爲了向 Pod 提供一個反饋機制,確保應用不會被集羣自身的變更而受影響。例如,當集羣須要進行重調度時,應用能夠經過 Disruption Budget 來講明 Pod 能不能被遷移。Disruption Budget 只負責集羣自身發起的變更,不負責突發事件好比節點忽然掉線,或者應用自己的問題好比不斷重啓的變更。Disruption Budget 一樣沒有在 1.3 中發佈。

與 kubernetes 大多數資源相似,咱們須要經過 Yaml 文件建立一個 PodDisruptionBudget 資源,例如,下圖所示的 Disruption Budget 選中了全部帶有 app:nginx 標籤的 pod,而且要求至少有 3 個 Pod 在同時運行。

 

Controller manager 內有一個新的組件 Disruption Budget Controller,來負責維護全部 Budget 的狀態,例如上圖中的 status 代表當前共有 4 個健康的 Pod(currentHealthy),應用要求至少有 3 個(desiredHealthy),總共有 5 個Pod(expectedPods)。爲了維護這個狀態,Disruption Budget Controller 會遍歷全部的 Budget 和全部的 Pod。有了 Budget 的狀態,須要改變 Pod 狀態的組件都要先查詢之。若其操做致使最小可用數低於應用要求,則操做會被拒絕。Disruption Budget 與 QoS 聯繫很緊密。例如,若是一個 QoS level 很低的應用有着很是嚴格的 Disruption Budget,系統應該如何處理?目前,kubernetes 尚未嚴格的處理這個問題,一個可行的辦法是對 Disruption Budget 作優先級處理,確保高優先級的應用擁有高優先級的 Disruption Budget;此外,Disruption Budget 能夠加入 Quota 系統,高優先級的應用能夠得到更多 Disruption Budget Quota。關於 Disruption Budget 的討論能夠參考:https://github.com/kubernetes/kubernetes/issues/12611

支持更好的集羣管理

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 根據事件類型更新資源關係圖,並將受影響的資源放入 Dirty Queue 或者 Orphan Queue 中。具體實現能夠參考官方文檔和 garbage collector controller 實現:https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/garbage-collection.md

2 Node eviction

Node/kubelet eviction 指的是在節點將要超負荷以前,提早將 Pod 剔除出去的過程,主要是爲了內存和磁盤資源。在 kubernetes 1.3 以前,kubelet 不會「提早」感知節點的負荷,只會對已知的問題進行處理。當內存吃緊時,kubernetes 依靠內核 OOM killer;磁盤方面則按期對 image 和 container 進行垃圾回收。可是,這種方式有侷限性,OOM killer 自己須要消耗必定資源,而且時間上有不肯定性;回收容器和鏡像不能處理容器寫日誌的問題:若是應用不斷寫日誌,則會消耗掉全部磁盤,但不會被 kubelet 處理。

Node eviction 經過配置 kubelet 解決了以上問題。當啓動 kubelet 時,咱們經過指定 memory.available, nodefs.available, nodefs.inodesFree 等參數來確保節點穩定工做。例如,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。當節點的狀態包含其中任意一種時,調度器會避免往該節點調度新的 Pod。這裏還有另一個問題,即若是節點的資源使用恰好在閾值附近,那麼節點的狀態可能會在 Pressure 和 Not Pressure 之間抖動。防抖動的方法有不少種,例如平滑濾波,即將歷史數據也考慮在內,加權求值。k8s 目前採用較爲簡單的方法:即若是節點處於 Pressure 狀態,爲了轉變成 Not Pressure 狀態,資源使用狀況必須低於閾值一段時間(默認 5 分鐘)。這種方法會致使 false alarm,好比,若一個應用每隔一段時間請求一塊內存,以後很快釋放掉,那麼可能會致使節點一直處於 Pressure 狀態。但大多數狀況下,該方法能處理抖動的狀況。

說到 eviction pod,那麼另一個不得不考慮的問題就是找一個倒黴的 Pod。這裏 kubernetes 定義了很多規則,總結下來主要是兩點:1. 根據 QoS 來判斷,QoS 低的應用先考慮;2. 根據使用量判斷,使用量與總請求量比例大的 Pod 優先考慮。具體細節能夠參考:https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/kubelet-eviction.md

3 Network Policy

Network policy 的目的是提供 Pod 之間的隔離,用戶能夠定義任意 Pod 之間的通訊規則,粒度爲端口。例如,下圖的規則能夠解釋成:擁有標籤「db」的 Pod,只能被擁有標籤「frontend」的 Pod 訪問,且只能訪問 tcp 端口 6379。

 

Network policy 目前處於 beta 版本,而且只是 API。也就是說,kubernetes 不會真正實現網絡隔離:若是咱們將上述 Yaml 文件提交到 kubernetes,並不會有任何反饋,kubernetes 只是保存了這個 Policy 內容。真正實現 policy 功能須要其餘組件,好比 calico 實現了一個 controller,會讀取用戶建立的 Policy 來實現隔離,能夠參考:https://github.com/projectcalico/k8s-policy/。關於 Network Policy 的細節,能夠參考:https://github.com/kubernetes/kubernetes/blob/master/docs/proposals/network-policy.md

4 Federation

Federation cluster 翻譯成中文叫「聯合集羣」,即將多個 kubernetes 集羣聯合成一個總體,而且不改變原始 kubernetes 集羣的工做方式。根據 kubernetes 官方設計文檔,federation 的設計目的主要是知足服務高可用,混合雲等需求。在 1.3 版本以前,kubernetes 實現了 federation-lite,即一個集羣中的機器能夠來自於相同 cloud 的不一樣 zone;1.3 版本中,federation-full 的支持已是 beta 版本,即每一個集羣來自不一樣的 cloud(或相同)。

 Federation的核心組件主要是 federation-apiserver 和 federation-controller-manager,以 Pod 形式運行在其中一個集羣中。以下圖所示,外部請求直接與 Federation Control Panel 通訊,由 Federation 分析請求併發送至 kubernetes 集羣。

在應用層面,Federation 目前支持 federated services,即一個應用跨多個集羣的訪問,具體細節能夠參考:http://blog.kubernetes.io/2016/07/cross-cluster-services.html 以及http://kubernetes.io/docs/admin/federation/

結束語

kubernetes 1.3 帶來了很是多的特性,這裏只 cover 了其中一部分。在安全方面,kubernetes 已經支持 RBAC,實現更好的權限控制;PodSecurityContext 也進入 beta 版本,支持運行部分須要特權的 Pod 等。在性能方面,因爲 protocol buffere serialization 的引入,是性能提升了幾倍,而且正在醞釀中的 etcd3 會將性能提高更進一步。相信以後的版本會帶給咱們更多的驚喜。

相關文章
相關標籤/搜索