作者:王思宇,阿里云技術專家,OpenKruise 社區負責人
通常情況下,人們只能使用普通舊資料作為 Kubernetes 中最小的操作單元,一些公司在他們的集群中入侵了 Kubelet 的代碼,以便他們可以對容器做更多的事情,然而,為運行時擴展操作確實是一種錯誤的方法,因為它不利于開源和社區的合作,現在,云原生計算基金會沙箱專案之一 OpenKruise 提供了高級功能,可以在每個原始 Kubernetes 集群中操作容器運行時,在本次演講中,我們將介紹 OpenKruise 中一些功能的用法,以及它如何與 Kubelet 和 CRI 合作,
本次分享主要分為以下幾個部分,首先我們介紹在 Kubernetes 中,針對于對容器 runtime 的操作限制有哪些,也就是說我們在 Kubernetes 中,它的機制限制了我們哪些操作,其實是對 controller runtime 是做不到的;第二點是 OpenKruise 是怎樣拓展對 controller runtime 的這些操作;第三點是我們簡單做一個 demo,我們如何通過 OpenKruise 來實作這些操作的;第四點是簡單介紹一下我們后續的一些規劃,
Kubernetes 中針對容器運行時的操作有哪些限制?
Kubernetes 中的容器運行時

如上圖所示,這是一個 Kubernetes 的基本結構,它的結構在每個節點( Node)上,其實是 Kubelet 在 API server 里面收到它的,比如 Pod 的變化,當 Kubelet 收到一個 Pod 創建之后,通過 CRI(Container Runtime Interface) , CNI 以及類似的公共介面(例如 CSI)來呼叫底層真正的介面實作者去完成操作,對于容器運行時來說,是通過 CRI 介面呼叫底層真正的 Runtime 運行時來完成對容器的創建和啟動鏡像拉取這些操作,
其中 CRI 是 Kubernetes1.5 之后加入的一個新功能,由協議緩沖區和 gRPC API 組成,提供了一個明確定義的抽象層,它的目的是對于 Kubelet 能屏蔽底下 Runtime 實作的細節而只顯示所需的介面,
(https://github.com/kubernetes/cri-api)
在 Kubernetes1.5 之前,Kubelet 與 Docker 是相耦合的,Kubelet 其實是引入了 Docker 的 client,由它們直接對 Docker 操作,有了 CRI ,對于 Kubelet 來說就不用關心底層真正的 Runtime 實作是什么,而只需要呼叫這層介面,介面背后的實作可能是 Containerd-d ,可能是 CRI-O,也可能是 Docker,
CRI 的職責是對容器運行時以及對鏡像做相關的管理,包括對容器的啟停操作,對 Sandbox 容器的操作,容器 States 的資料采集,以及鏡像的拉取和查詢等操作,因此,CRI 提供了比較完善的容器介面,如下圖,

Kubernetes 中容器運行時的操作限制
Kubernetes API 并沒有提供對容器運行時的介面操作,它唯一提供的是對 v1 版本的 Pod 操作(Pod API CRUD,Pod Subresources API),除了 Pod 創建和更新之外,唯一能跟 Runtime 做比較相對應操作的是 Exec subresource 和 Log subresource,
Kubernetes 的 API 層面限制了用戶只能創建或洗掉 Pod ,除此之外,里面的容器只能做 Exec, Log 這樣的操作,在 Kubernetes 介面層面,用戶無法進行比如拉取鏡像、重啟容器等操作,

那有沒有可能去拓展這個 API 呢?
我們發現 Kubelet 目前沒有提供任何 hook 解決 plugin 的這個操作,來讓外層能去動態拓展 Kubelet 所做的事情,( Kubelet 的介面是不提供這樣的插件機制的)那是否可以加入一個與 Kubelet 類似的新組件,可以連接到 CRI API,來拓展 Kubernetes 容器進行時的操作呢?
我們同樣會呼叫 CRI 這一層,比如它可以拉鏡像,可以重啟容器,它的上層也可以接收一個對于 Kubernetes API 上定義的一個 CRD 資源,這個 CRD 資源定義了讓用戶能夠宣告對 CRI 介面做一些操作,比如它可以定義指定用戶去拉鏡像,去重啟容器,可以做更多的事情,
這種方式是我們能想到的,對于這個 Kubernetes 容器運行時 operations 的拓展思路,

OpenKruise 是什么?
OpenKruise 概念
Openkruise 是 Kubernetes 的一個拓展套件,它彌補了 Kubernetes 很多功能不足,例如對于應用作業負載(應用部署發布相關功能)的不足,對于 container runtime 操作的不足等,它可以配合原生 Kubernetes 使用,并為管理應用容器、sidecar、鏡像分發等方面提供更加強大和高效的能力,
2020 年 11 月,OpenKruise 作為 Sandbox 專案加入 CNCF,

Openkruise 本身并不是一個 PasS 平臺,但 PasS 平臺可以通過利用 Openkruise 提供的拓展能力更好的管理,運維云原生的應用,感興趣的朋友可以通過以下網址了解更多 OpenKruise 相關資訊,
Github:
https://github.com/openkruise/kruise
WebSite:
https://openkruise.io
OpenKruise 的功能
OpenKruise 是基于 CRD 的拓展,其功能大致可分為五部分:
(1)應用作業負載:包括針對無狀態應用,有狀態應用的灰度發布、流量控制、它的原地升級等相關功能;
(2)Sidecar 容器管理:提供更多增強的獨立定義以及獨立部署;
(3)應用多磁區管理(Multi-domain management):一個應用如果要部署在多個磁區,會進行打散和分片的管理,
(4)應用可用性防護:保護云原生應用在 Kubernetes 上運行時的高可用性;
(5)拓展增強操作:通過這種方式來實作對 container runtime(運行時)增強的操作能力,其中拓展增強操作是本文主要介紹的功能,后續我們會詳細展開,

OpenKruise 功能圖
OpenKruise 的架構

如圖所示,OpenKruise 主要分成中心端(Kruise-manager)和節點端(Node)兩個組件,中心端的 Kruise-manager 包含 controllers 和 webhooks ,通過 Kruise-manager 中心端的角色和每個節點上 kruise-daemon 功能結合,可以完成很多 Kubernetes 本身不提供的能力,Kruise-daemon 是用來避免對 Kubelet 做改造,通過拓展的方式對 CRI runtime 進行操作,
Runtime 的拓展功能
Runtime 有三個核心拓展功能,
原地升級功能
原地升級是一種可以避免洗掉、新建 Pod 的升級鏡像能力,

如上圖所示:第一部分并不是直接通過 kruise-daemon 拓展,而是利用 Kubelet 的原生機制,叫做原地升級,
如何理解原地升級?我們舉一個簡單的例子:比如原來有一個 pod-a ,此時的 pod-a 是通過 deployment 的或者 Openkruise 的 cloneset 擴容出來的,如果我們想要升級 app容器的鏡像版本,比如從 Fv1 升級到 Fv2,正常情況下大家使用 development 部署是采用 Recreatte Update 也就是重建 Pod 升級,重建完成后我們會看到 Pod 的名字,Pod UID, (鏡像也會升級為 V2) 很大程度上都會發生改變,
再看后面兩者,前者 Pod 的名字和 UID 一定會發生變化,因為它已經不是同一個 Pod 的物件了,相對于我們這次介紹的原地升級,Pod 的物件其實還是原來的物件,Pod 的名字,Pod UID 都不變,其次,Pod 所在節點的 IP 也都不變,唯一變化的是鏡像從 v1 級到了 v2,由于 Pod 節點沒有發生任何變化,Pod 物件就不需要經過調度器重新調度,IP 分配,volume 分配,掛載這些耗時也都消除掉了,因此一個很明顯好處就是節省了調度的耗時,
大家都知道,當應用鏡像從 v1 升到 v2 的程序中,可能只是最頂上的 layers 發生了變化,底下絕大部分的這個 base 鏡像,公共 layers 是沒有發生變化的,
當我們在同一個節點上面做原地升級的時候,可以復用原有 v1 鏡像的大部分 layers ,只用下載小部分的 layers 鏡像,
在升級 app 容器的程序中,Pod 中的其他容器,如 sidecar 容器,是一直正常運行的,沒有受到影響,反過來說,當我們升級 sidecar 容器時,容器也是正常運行的,這樣可以很大程度上避免在升級一個旁路(比如運維)容器的程序中,也要對業務能力造成影響,
1.1 優勢
? 節省操作耗時,包括:Pod 調度、IP 分配、volume 分配、掛載等;
? 復用大部分鏡像層;
? 當一個容器進行升級時,不會對 Pod 中的其它容器造成影響;
1.2 作業原理
原地升級的原理可以簡單理解為 Kubelet 在創建每個容器時,會為容器計算一個 hash 值,當上層修改了比如 app 容器的 image 之后,Kubelet 就認為容器的 hash 值發生了變化,當 Kubelet 發現 Pod spec 中 app 容器的 hash 值和實際的,如 container d 對應的 hash 值不一致時,就會把舊的 app 容器停掉,用新的鏡像再重建新的 app 容器,從而實作容器的原地升級的能力,

容器重啟功能

容器重啟的功能是很多業務,包括運維平臺都很依賴的功能,大家可能會問,在 Kubernetes 中,一個 Pod 既然是無狀態的,那么想重啟時就直接洗掉 Pod,再新建一個 Pod 不就可以了嗎?
這是當然可以的,但對于業務來說可能還存在很多 debug 場景,并不只是重建一個新的 Pod 就可以,而是要從原地把容器進行重啟,相當于把里面的業務行程重啟,比如想保留一些 volume 中的資料,一些網路、堆疊資訊等,這些場景都導致業務需要有 Kubernetes Pod 的容器原地重啟能力,
Kubernetes 原生是不具備容器重啟能力的,對于 Kubernetes 來說,如果想要重啟容器,只能手動進入容器,把容器里的應用行程殺掉,這時當容器退出,Kubernetes 會再把它拉起,當然這種方式其實都比較 hack 的這么一種方式, Openkruise 所提供的容器重啟能力對于 API 來說,只需要創建一個 CR,
CR 里寫的東西很明確,name spacesl 只需定義跟 pod 在同一個 name spacesl 里,其中 name 是自定義的名字,通過指定需要重啟的 Pod 是哪個,需要重啟 pod 出來哪些 containers,當定義了這些資訊之后,提交 CR,當 kruise 收到 CR ,kruise - manager 會先經過 webhooks,對它注入一些資訊,接下來 kruise-daemon 拿到 CR 會根據 CR 中定義的資訊(比如會找到對應 Pod 的容器)執行 preStop hook,再通過 CRI 介面,通過 EXTC 執行 preStop,當 preStop 執行完成之后再呼叫這個 CRI 的 stop ,
其實這個停止方式和本身 Kubelet 在洗掉 Pod 時對容器的停止方式是一致的,當 kruise-daemon 對舊容器,比如對零號的 app(app_0)容器停掉之后,Kubelet 感知到 app 容器停掉了,接著就會新建一個 F1 容器并把它拉起,通過這種方式來實作優雅的容器原地重啟能力,
代碼示例:
apiVersion: apps.kruise.io/v1alpha1
kind: ContainerRecreateRequest
metadata:
namespace: pod-namespace
name: xxx
spec:
podName: pod-name
containers:
- name: app
strategy:
# ...
activeDeadlineSeconds: 300
ttlSecondsAfterFinished: 1800
status:
containerRecreateStates:
- name: app
phase: Succeeded
phase: Completed
# ..
鏡像預熱功能
提前在節點上包括新建的 Node 上預熱,就可以大幅度減少后續 Pod 擴容的耗時,

從上圖我們可以看到,對于上層用戶來說 Openkruise 提供了一個 CRD 叫 ImagePullJob,用戶可以定義需要預熱哪個鏡像,也可以選擇性的配置 selector(selector 可以是節點的標簽選擇器也可以根據 Pod 進行選擇),以上都可以在 Pod 所在節點上進行預熱,
當用戶建立 ImagePullJob 后,對于 kruise 內部邏輯來說,kruise 會把 ImagePullJob 拆分到每個 node 對應 node image 的 CR 上,當同步上去后,節點上的 kruise-daemon 會拿到這個節點所對應node image 的 CR ,在節點上預熱 CR 中定義的多個鏡像,
換句話說,每個節點所對應的 node image 中的鏡像串列,其實就表示了上層所有 ImagePullJob 指定在這個節點上要拉取鏡像全集,kruise-daemon 底層拿到 node image 后,相當于也是呼叫 CRI 的 Pod image 介面來完成鏡像的預熱,
代碼示例:
apiVersion: apps.kruise.io/v1alpha1
kind: ImagePullJob
metadata:
name: test-job
spec:
image: nginx:latest
parallelism: 10
selector:
# ...
podSelector:
# ...
completionPolicy:
# ...
未來專案規劃
2021 年 12 月,OpenKruise 完成了首個正式版本 v1.0 的發布,使云原生應用自動化達到新的高峰,OpenKruise 從 2019 年發布 0.1 版本到現在已經有 2 年多的時間,已有超過 70 位貢獻者參與貢獻,star 數量已經超過 3000,2022,我們將推進 OpenKruise 成為 CNCF Incubation 專案,推動云原生應用自動化領域進一步成熟,
使用用戶:
? 阿里巴巴集團, 螞蟻集團, 斗魚TV, 申通, Boss 直聘
? 杭銀消費, 萬翼科技, 多點, Bringg, 佐疆科技
? Lyft, 攜程, 享住智慧, VIPKID, 掌門 1 對 1
? 小紅書, 比心, 永輝科技中心, 跟誰學, 哈啰出行
? Spectro Cloud, 艾佳生活, Arkane Systems, 滴普科技, 火花思維
? OPPO, 蘇寧, 歡聚時代, 匯量科技, 深圳鳳凰木網路有限公司
? 小米, 網易,美團金融, Shopee, LinkedIn
發布云原生技術最新資訊、匯集云原生技術最全內容,定期舉辦云原生活動、直播,阿里產品及用戶最佳實踐發布,與你并肩探索云原生技術點滴,分享你需要的云原生內容,
關注【阿里巴巴云原生】公眾號,獲取更多云原生實時資訊!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/445513.html
標籤:其他
上一篇:分布式資料庫發展路徑
