OCI,CRI到kubernetes runtime

導讀

接觸kubernetes的時候, 搞不懂OCI,CRI,runC,containerd,shim 之間的區別和聯系, 下面梳理一下OCI產生的背景,對docker的影響,以及編排工具kubernetes CRI的產生背景及變化
爭取通過下面的梳理說明白

\color{green}{OCI}


\color{green}{OCI}

談到OCI,會想到docker,先有docker后有OCI,說到docker就說到容器技術, docker不是最早的容器技術,比如早期的chroot Jails,Solaris Containers等,但是是docker把容器技術推向了巔峰,讓更多人關注并使用了容器技術

docker自2013發布以來,github中docker的代碼活躍度居高不下,更多的個人或企業使用docker,容器就是docker也逐漸被大家認可,如果docker就是容器的標準,那其他容器怎么辦(比如coreOS推出的rkt),
其次容器上層的編排工具(容器集群調度,比如kubernetes,mesos等)和docker緊密耦合,docker 接口的變化導致上層編排的穩定性甚至服務異常.

如果容器以docker作為標準,那么docker接口的變化可能導致社區中所有相關工具都要更新,不然就無法使用,如果沒有標準,這將導致容器實現的碎片化,出現大量的沖突和冗余,
這兩種情況都是社區不愿意看到的事情,于是OCI出現了

它的核心目標圍繞容器的格式和運行時制定一個開放的工業化標準,并推動這個標準,保持容器的靈活性和開放性,容器能運行在任何的硬件和系統上.
容器不應該綁定到特定的客戶機或編排堆棧,不應該與任何特定的供應商緊密關聯,并且可以跨多種操作系統

官網上對 OCI 的介紹如下:

Established in June 2015 by Docker and other leaders in the container industry, the OCI currently contains two specifications: the Runtime Specification (runtime-spec) and the Image Specification (image-spec). The Runtime Specification outlines how to run a “filesystem bundle” that is unpacked on disk. At a high-level an OCI implementation would download an OCI Image then unpack that image into an OCI Runtime filesystem bundle. At this point the OCI Runtime Bundle would be run by an OCI Runtime.

OCI由docker以及其他容器行業領導者創建于2015年,目前主要有兩個標準:容器運行時標準(runtime-spec)和容器鏡像標準(image-spec)
這兩個標準通過OCI runtime filesytem bundle的標準格式連接在一起,OCI鏡像可以通過工具轉換成bundle,然后 OCI 容器引擎能夠識別這個bundle來運行容器

文檔主要做了兩個事情:

  • 創建鏡像的規則
  • 運行鏡像的規則

\color{green}{ OCI Standard Document}

  1. 容器鏡像標準(image-spec)

    • 文件系統: 以layer保存的文件系統,每個layer保存了和上層之間變化的部分,layer應該保存哪些文件,怎么表示增加、修改和刪除的文件等
    • config文件: 保存了文件系統的層級信息(每個層級的hash值,以及歷史信息)以及容器運行時需要的一些信息(比如環境變量、工作目錄、命令參數、mount 列表)
    • manifest文件: 鏡像的config文件索引,有哪些layer,額外的annotation信息,manifest文件中保存了很多和當前平臺有關的信息
    • index文件: 可選的文件,指向不同平臺的manifest文件,這個文件能保證一個鏡像可以跨平臺使用,每個平臺擁有不同的manifest文件,使用index作為索引
  2. 容器運行時標準(runtime spec)

    容器的狀態包括如下屬性

    • ociVersion: OCI版本
    • id: 容器的ID,在宿主機唯一
    • status: 容器運行時狀態,生命周期
      • creating: 使用 create 命令創建容器,這個過程稱為創建中,創建包括文件系統、namespaces、cgroups、用戶權限在內的各項內容
      • created: 容器創建出來,但是還沒有運行,表示鏡像和配置沒有錯誤,容器能夠運行在當前平臺
      • running: 容器的運行狀態,里面的進程處于up狀態,正在執行用戶設定的任務
      • stopped: 容器運行完成,或者運行出錯或者stop命令之后,容器處于暫停狀態,這個狀態,容器還有很多信息保存在平臺中,并沒有完全被刪除
    • pid: 容器進程在宿主機的進程ID
    • bundle: 容器文件目錄,存放容器rootfs及相應配置的目錄
    • annotations: 與容器相關的注釋

\color{green}{docker architecture}

了解了OCI標準, 我們再看一下docker架構的演變,早期docker所有功能都在docker daemon里面的,但是之后功能越來越多,越來越重,同時響應社區兼容OCI標準,docker做了架構調整

調整后將容器運行時相關的程序從docker daemon剝離出來,形成了containerd, Containerd向docker提供運行容器的API,二者通過gRPC進行交互, containerd最后會通過runC來實際運行容器,

調整完后的docker架構圖如下(docker 1.11版本以后)


containerd.png

\color{green}{Runc}

runC的前身是docker的libcontainer項目,在libcontainer的基礎上做了封裝,捐贈給OCI的一個符合標準的runtime實現,上圖可以看出docker引擎內部也是基于runC構建的

關于libcontainer和runC stackoverflow 的一個回答:

The Open Container Format (OCF) specification is a written document (or set of documents) defining what a "standard container" is,
in terms of filesystem, available operations and execution environment.
The document seems to be backed up with Go code. This specification is currently (July 2015) a work-in-progress.
Runc is an implementation of the standard. At the time of writing, it is basically a repackaging of libcontainer.
Docker uses libcontainer/runc, but adds a lot of tooling and features on top, such as volumes, networking and management of containers.
There is more information on the Docker blog and Open Containers site
If you're just getting started with containers, I would start with Docker and look into the other projects later once you understand how containers work.

runC只做一件事情就是運行容器,提供創建和運行容器的CLI(command-line interface)工具, runC直接與容器所依賴的cgroup/namespace linux kernel等進行交互,
負責為容器配置cgroup/namespace等啟動容器所需的環境,創建啟動容器的相關進程


\color{green}{ containerd-shim}

關于containerd-shim 看一下Michael Crosby (runC,containerd作者)的解釋

The shim allows for daemonless containers. It basically sits as the parent of the container's process to facilitate a few things. First it allows the runtimes, i.e. runc,to exit after it starts the container. This way we don't have to have the long running runtime processes for containers. When you start mysql you should only see the mysql process and the shim. Second it keeps the STDIO and other fds open for the container incase containerd and/or docker both die. If the shim was not running then the parent side of the pipes or the TTY master would be closed and the container would exit.
Finally it allows the container's exit status to be reported back to a higher level tool like docker without having the be the actual parent of the container's process and do a wait4.
I did a talk on this last week at dockercon US. You can see my slides here. https://github.com/crosbymichael/dockercon-2016
Hopefully that will explain a little more about how containerd and the shim work.

containerd-shim進程由containerd進程拉起,即containerd進程是containerd-shim的父進程, 容器進程由containerd-shim進程拉起, 這樣的優點比如升級,重啟docker或者containerd 不會影響已經running的容器進程, 而假如這個父進程就是containerd,那每次containerd掛掉或升級,整個宿主機上所有的容器都得退出了. 而引入了 containerd-shim 就規避了這個問題(當 containerd 退出或重啟時, shim 會 re-parent 到 systemd 這樣的 1 號進程上)


\color{green}{ containerd}

containerd是一個簡單的守護進程,它可以使用runC管理容器,使用gRPC暴露容器的其他功能. 相比較Docker引擎使用gRPC, containerd暴露出針對容器的增刪改查的接口,然而Docker引擎只是使用 full-blown HTTP API接口對Images,Volumes,network,builds等暴露出這些方法


\color{green}{CRI}

了解了OCI,以及docker在兼容OCI標準架構的調整后, 迎來我們的重點 CRI
CRI是kubernetes推出的一個標準, 推出標準可見其在容器編排領域的地位

講CRI之前我們先簡單了解一下kubelet拉起一個容器的過程,如下:


20190602155250485.png
  1. Kubelet通過CRI接口(gRPC)調用docker-shim,請求創建一個容器這一步中,kubelet可以視作一個簡單的CRI Client,而docker-shim就是接收請求的Server,
    注意的是docker-shim是內嵌在Kubelet中的
  2. docker-shim收到請求后,轉化成Docker Daemon能聽懂的請求,發到Docker Daemon上請求創建一個容器
  3. Docker Daemon請求containerd創建一個容器
  4. containerd收到請求后創建一個containerd-shim進程,通過containerd-shim操作容器,容器進程需要一個父進程來做諸如收集狀態, 維持stdin等fd打開等工作
  5. containerd-shim在調用runC來啟動容器
  6. runC 啟動完容器后本身會直接退出,containerd-shim則會成為容器進程的父進程,負責收集容器進程的狀態,上報給containerd

\color{green}{ CRI history}

通過上面kubelet創建容器的流程, 我們可以看到kubelet通過CRI的標準來與外部容器運行時進行交互

kubernetes 早期版本1.5之前內置了docker和rkt,也就是支持兩種運行時, 這個時候如果用戶想自定義運行時就比較痛苦了,需要修改kubelet源碼

同時不同的容器運行時各有所長,隨著k8s在容器編排領域里面老大的地位,許多用戶希望kubernetes支持更多的容器運行時,滿足不同用戶,不同環境的使用
于是從kubernetes1.5開始增加了CRI接口, 有了CRI接口無需修改kubelet源碼就可以支持更多的容器運行時

于此同時內置的docker和rtk逐漸從kubernetes源碼中移除,到kubernetes1.11版本Kubelet內置的rkt代碼刪除,CNI的實現遷移到dockers-shim之內,
除了docker之外,其他的容器運行時都通過CRI接入.

外部的容器運行時一般稱為CRI shim,它除了實現CRI接口外,也要負責為容器配置網絡,即CNI,有了CNI可以支持社區內的眾多網絡插件.


\color{green}{ CRI Define Interface}

CRI主要定義兩個接口, ImageService和RuntimeService,如下圖


0.jpeg
  • ImageService:負責鏡像的生命管理周期
    • 查詢鏡像列表
    • 拉取鏡像到本地
    • 查詢鏡像狀態
    • 刪除本地鏡像
    • 查詢鏡像占用空間
  • RuntimeService:負責管理Pod和容器的生命周期
    • PodSandbox 的管理接口
      PodSandbox是對kubernete Pod的抽象,用來給容器提供一個隔離的環境(比如掛載到相同的cgroup下面)并提供網絡等共享的命名空間.PodSandbox通常對應到一個Pause容器或者一臺虛擬機
    • Container 的管理接口
      在指定的 PodSandbox 中創建、啟動、停止和刪除容器。
    • Streaming API接口
      包括Exec、Attach和PortForward 等三個和容器進行數據交互的接口,這三個接口返回的是運行時Streaming Server的URL,而不是直接跟容器交互
    • 狀態接口
      包括查詢API版本和查詢運行時狀態

\color{green}{ CRI container engine}

  • cri-o:同時兼容OCI和CRI的容器運行時
  • cri-containerd:基于Containerd的Kubernetes CRI 實現
  • rkt:由CoreOS主推的用來跟docker抗衡的容器運行時
  • docker:kuberentes最初就開始支持的容器運行時,目前還沒完全從kubelet中解耦,docker公司同時推廣了OCI標準
  • Kata Containers:符合OCI規范同時兼容CRI
  • gVisor:由谷歌推出的容器運行時沙箱(Experimental)

\color{green}{ CRI and OCI}

容器生態可以下面的三層抽象:

Orchestration API -> Container API -> Kernel API

  • Orchestration API: kubernetes API標準就是這層的標準,無可非議
  • Container API: 標準就是CRI
  • Kernel API: 標準就是OCI

參考資料

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容