kubernetes中的容器建立無疑是個複雜的過程,涉及內部各類組件的統一協做,還有對接外部的CRI運行時,本文嘗試初探一下容器建立流程中的各類細節,瞭解其各類組件協做流程,從而在後續出現問題的時候,也好能大概有點排查方向segmentfault
kubelet中的線程模型屬於master/worker模型,經過單master來監聽各類事件源,併爲每一個Pod建立一個goroutine來進行Pod業務邏輯的處理,master和worker之間經過一個狀態管道來進行通訊api
在經過yaml建立Pod以後,kubernetes會根據當前的事件和當前的Pod狀態,來不斷進行調整,從而達到最終目標狀態的一致性微信
kubelet的結構體聲明就高達300多行代碼,可見其複雜程度,可是咱們按照容器建立這個流程,咱們去觀察其核心流程,其實主要能夠歸納爲三部分:kubelet、containerRuntime、CRI容器運行時網絡
kubelet的事件源主要包含兩個部分:靜態Pod和Apiserver,咱們這裏只考慮普通的Pod,則會直接將Pod加入到PodManager來進行管理,而且進行准入檢查ide
准入檢查主要包含兩個關鍵的控制器:驅逐管理與預選檢查
驅逐管理主要是根據當前的資源壓力,檢測對應的Pod是否容忍當前的資源壓力;
預選檢查則是根據當前活躍的容器和當前節點的信息來檢查是否知足當前Pod的基礎運行環境,例如親和性檢查,同時若是當前的Pod的優先級特別高或者是靜態Pod,則會嘗試爲其進行資源搶佔,會按照QOS等級逐級來進行搶佔從而知足其運行環境源碼分析
kubelet接收到一個新建立的Pod首先會爲其建立一個事件管道,而且啓動一個容器管理的主線程消費管道里面的事件,而且會基於最後同步時間來等待當前kubelet中最新發生的事件(從本地的podCache中獲取),若是是一個新建的Pod,則主要是經過PLEG中更新時間操做,廣播的默認空狀態來做爲最新的狀態性能
當從本地的podCache中獲取到最新的狀態信息和從事件源獲取的Pod信息後,會結合當前當前statusManager和probeManager裏面的Pod裏面的容器狀態來更新,從而獲取當前感知到的最新的Pod狀態ui
以前的准入檢查是Pod運行的資源硬性限制的檢查,而這裏的准入檢查則是軟狀態即容器運行時和版本的一些軟件運行環境檢查,若是這裏檢查失敗,則會講對應的容器狀態設置爲Blockedspa
在經過准入檢查以後,會調用statusManager來進行POd最新狀態的同步,此處可能會同步給apiserver插件
在更新完成狀態以後會啓動一個PodCOntainerManager主要做用則是爲對應的Pod根據其QOS等級來進行Cgroup配置的更新
接下來kubelet會爲Pod的建立準備基礎的環境,包括Pod數據目錄的建立、鏡像祕鑰的獲取、等待volume掛載完成等操做
建立Pod的數據目錄主要是建立 Pod運行所須要的Pod、插件、Volume目錄,而且會經過Pod配置的鏡像拉取祕鑰生成祕鑰信息,到此kubelet建立容器的工做就已經基本完成
前面咱們提到過針對Pod的操做,最終都是基於事件和狀態的同步而完成,在containerRUntime並不會區分對應的事件是建立仍是更新操做,只是根據當前的Pod的信息與目標狀態來進行對比,從而構建出對應的操做,達到目標狀態
計算容器變動主要包括:Pod的sandbox是否變動、短聲明週期容器、初始化容器是否完成、業務容器是否已經完成,相應的咱們會獲得一個幾個對應的容器列表:須要被kill掉的容器列表、須要啓動的容器列表,注意若是咱們的初始化容器未完成,則不會進行將要運行的業務容器加入到須要啓動的容器列表,能夠看到這個地方是兩個階段
若是以前檢測到以前的初始化容器失敗,則會檢查當前Pod的全部容器和sandbox關聯的容器若是有在運行的容器,會所有進行Kill操做,而且等待操做完成
當一些Pod的容器已經運行,可是其狀態仍然是Unknow的時候,在這個地方會進行統一的處理,所有kill掉,從而爲接下來的從新啓動作清理操做,此處和3.2只會進行一個分支,但核心的目標都是清理那些運行失敗或者沒法獲取狀態的容器
在啓動Pod的容器以前,首先會爲其建立一個sandbox容器,當前Pod的全部容器都和Pod對應的sandbox共享同一個namespace從而共享一個namespace裏面的資源,建立Sandbox比較複雜,後續會繼續介紹
Pod的容器目前分爲三大類:短生命週期容器、初始化容器、業務容器,啓動順序也是從左到右依次進行,若是對於的容器建立失敗,則會經過backoff機制來延緩容器的建立,這裏咱們順便介紹下containerRuntime啓動容器的流程
鏡像的拉取首先會進行對應容器鏡像的拼接,而後將以前獲取的拉取的祕鑰信息和鏡像信息,一塊兒交給CRI運行時來進行底層容器鏡像的拉取,固然這裏也會各類backoff機制,從而避免頻繁拉取失敗影響kubelet的性能
建立容器配置主要是爲了容器的運行建立對應的配置數據,主要包括:Pod的主機名、域名、掛載的volume、configMap、secret、環境變量、掛載的設備信息、要掛載的目錄信息、端口映射信息、根據環境生成執行的命令、日誌目錄等信息
調用runtimeService傳遞容器的配置信息,調用CRI,而且最終調用容器的建立接口完成容器的狀態
經過以前建立容器返回的容器ID,來進行對應的容器的啓動,而且會爲容器建立對應的日誌目錄
若是容器配置了PostStart鉤子,則會在此處進行對應鉤子的執行,若是鉤子的類型是Exec類則會調用CNI的EXec接口完成在容器內的執行
首先會拉取sandbox鏡像
在建立容器以前會先根據SecurityContext裏面的配資信息,來進行容器SecurityContext的配置,主要包括特權等級、只讀目錄、運行帳戶組等信息
除了應用SecurityContext還會進行斷開、OOMScoreAdj、Cgroup驅動等信息的映射
根據上面的各類配置信息來進行容器的建立
checkpoint主要是將當前sandbox的配置信息進行序列化,而且存儲其當前的快照信息
啓動sandbox容器則會直接調用StartContainer同時傳入以前建立容器返回的ID完成容器的啓動,而且此時會重寫覆蓋容器的dns配置文件
容器的網絡配置主要是調用CNI插件來完成容器網絡的配置,這裏就先不展開了
kubelet是容器管理的核心大管家,其負責各類准入控制、狀態管理、探測管理、volume管理、QOS管理、CSI對接的統一調度,而且爲Runtime運行時準備基礎的數據和並反饋Pod當前的最新狀態
Runtime層則將kubelet組裝的數據,按照CRI運行時的目標配置和kubelet管理的資源配置信息來進行資源的重組,而且根據Pod的容器的狀態來決策容器的啓停、建立等操做,並完成容器的基礎配置環境的構建,並最終調用CRI完成容器的建立,而CRI運行時,則會講傳遞過來的各類數據進行進一步的組合,並應用到主機和對應的namespace資源限制,並根據本身的容器服務組織數據,調用容器服務完成容器的最終建立
本文是一個基礎版本,後續會在該版本上,繼續疊加各類細節,感興趣的朋友能夠幫忙轉發關注下,謝謝你們
k8s源碼閱讀電子書地址: https://www.yuque.com/baxiaoshi/tyado3
微信號:baxiaoshi2020關注公告號閱讀更多源碼分析文章
更多文章關注 www.sreguide.com
本文由博客一文多發平臺 OpenWrite 發佈!