前言
Docker已經推出了5年玉组,在這5年中它極大的改變了互聯網產品的架構,推進了新的產品開發(fā)丁侄、測試和運維方法惯雳。但是它自身也在激烈變化中。特別是最近2年隨著Docker開源項目的不斷演化绒障,Docker內部結構發(fā)生了翻天覆地的變化。作為一個容器平臺的使用者捍歪,可以不用關注具體的Docker演進細則户辱,但是必須明白Docker的衍化會對自己的PaaS平臺帶來什么樣的影響(如果您對Docker技術細節(jié)不關注,你可以直接看第2章和最后兩章)糙臼。本文材料來自于Docker社區(qū)庐镐,對Docker最近幾年的變化趨勢做出了總結。同時在結尾處給出了基于k8s PaaS平臺在底層容器上選型建議变逃”啬妫
演進方向
這里先把結論拋出來畜普,Docker這幾年的架構演進方向:
1糠涛、原有引擎功能下沉入containerd鞋吉,containerd向著獨立于Docker 作為通用容器運行時工具方向演進
2产场、swarm功能整合入引擎端辱,swarmkit模塊不斷弱化档桃,最終將被引擎吸收
3行冰、引擎內部功能不斷解藕出新模塊被碗,同時新功能不斷加入Docker 引擎撒犀。
一言以蔽之:containerd核心化福压,引擎集群化。
背景
Docker公司在集群管理服務編排工具競爭上落敗
Docker公司在2015年Docker 1.9推出了自己的集群管理服務編排工具swarm或舞,剛開始swarm作為一個獨立的工具荆姆,在Docker 引擎之外。但是從Docker 1.12開始Docker公司將swarm整合入了Docker引擎映凳。至此Docker swarm作為一個完整的服務編排工具和谷歌主導胆筒、紅帽支持的kubernetes社區(qū)直接沖突。于此同時Docker公司在2015開啟了自己的商業(yè)化之路诈豌,開源社區(qū)為了避免Docker公司商業(yè)化過程中將Docker淪為綁架社區(qū)的工具腐泻,所以順勢推出了多個Docker替代方案例如rkt决乎。kubernetes社區(qū)推出了CRI-O標準,只要是遵從此標準的容器運行時都可以被K8s支持派桩。一時間Docker大有被主流社區(qū)拋棄之勢构诚!經過2年和K8s的競爭時間來到2017年,Docker swarm已經在事實上徹底落敗铆惑,Kubernetes社區(qū)已經成為開源項目中熱度最高的項目范嘱。為了應對如此多的不利因素,Docker公司在2017年將自己主導的containerd捐獻給CNCF基金會(k8s是旗下的子項目)员魏;并且將更多的Docker引擎的功能下沉到Containerd中丑蛤。借此避免自己在開源社區(qū)中被邊緣化。
容器世界的標準化不斷推進
Docker公司在2013念推出Docker后撕阎,極大的顛覆了這個行業(yè)受裹,也推進了業(yè)務容器化過程。2015 Docker公司主導之下社區(qū)推出了容器的第一個行業(yè)標準OCI標準(開放容器協議)虏束。彼時Docker公司推出了第一個OCI標準的容器運行時runc棉饶。runc作為第一個oci標準運行時(runtime),只是一個參考實現镇匀,僅僅承擔容器與主機之間的交互照藻。容器運行狀態(tài)檢查、監(jiān)控汗侵,容器生命期管理幸缕,io管理、信號傳遞等一些列容器運行必不可少的功能卻“無處安放”晰韵。所以Docker公司將Containerd定位為一個生產環(huán)境下的OCI 標準運行時发乔。它承擔了runc所缺少的大部分容器運行必要功能:生命期管理,io管理雪猪,信號管理列疗。在2017年的時候OCI v1標準發(fā)布,Docker公司將Docker鏡像格式捐獻給了OCI協議浪蹂。所以在2017年發(fā)布的Containerd1.0中存儲管理這些原來由引擎承擔的功能也進入了Containerd(網絡管理功能抵栈,在https://containerd.io路線圖中被列為roadmap,但是在2016年12月份Containerd的主要維護者投票中坤次,網絡功能不被列入containerd的功能范疇 而繼續(xù)交給上層完成古劲,在github containerd的readme中2017 1月12日正式將網絡部分功能從containerd 維護范疇中刪除)。
Containerd
Containerd在Docker 1.11中才正式出現缰猴,剛開始時0.x版本产艾;2017年才推出了1.x標準。如上文所說,Container?d作為一個生產環(huán)境可用的Oci 實現闷堡,它利用了OCI 運行時和鏡像格式.下圖展現了Containerd對自己在社區(qū)中地位作出了詮釋
可以看到Containerd作為PaaS工具的通用容器運行時適配層隘膘,它利用已有的oci運行時(Containerd使用runc作為運行時,在windows上則是hcsshim)杠览,屏蔽底層操作系統的差異弯菊;為Paas提供通用的容器支撐。從這個圖可以看到Containerd計劃支持所有現有應用廣泛的Paas平臺工具□獍ⅲ現在可以確認的是AWS ECS,k8s,Docker上使用containerd管钳。Mesos和cloud foundry今天(2018年9月)尚未確定。
下圖為Containerd 1.x的架構圖
從此架構圖可以清楚的看到Containerd對上提供grpc接口方式的api软舌,而Metric api是度量功能使用的才漆。所有的編排工具容器適配層都可以使用grpc api作為containerd的客戶端,使用containerd操作容器佛点。
Distribution用于容器鏡像的pull和push動作(這部分出現在Containerd中完全是因為oci v1標準推出Docker公司將自己鏡像格式貢獻了出去醇滥,所以containerd理所當然需要對鏡像進行管理了)。Bundle(在docker的語景里是容器運行的目錄集)子系統用于容器存儲管理它的作用就是原來的graphdriver超营,它提供將容器鏡像拆解成容器運行時刻需要的Bundle鸳玩。Runtime子系統用于容器執(zhí)行和監(jiān)控,就是它直接操作runtime糟描,傳遞和接收信號(signal)怀喉,中轉fifo书妻,記錄日志船响。Content、Metadata和Snapshots是存儲管理組建躲履,Excutor和Supervisor是執(zhí)行體組建见间。整個系統通過Event事件驅動。
根據github上containerd的介紹containerd項目工作內容集中在如下幾個領域上:
1工猜、執(zhí)行:容器創(chuàng)建米诉、運行、停止篷帅、暫停史侣、恢復,exec魏身,信號傳遞惊橱、和刪除。
2箭昵、cow 文件系統支持:在overlay税朴,aufs和其他cow文件系統上內置了存儲功能
3、度量系統
4、發(fā)布:容器鏡像的pull和push正林,鏡像的管理和獲取
下面內容不作為containerd項目的工作范疇:
1泡一、網絡:網絡的創(chuàng)建和管理由高層來完成
2、build:鏡像的構建
3觅廓、volumes:volume管理:mounts鼻忠,bind等針對volume的功能應該有高層來完成
4、logging
此處需要說明一下網絡曾經作為containerd社區(qū)爭論的焦點哪亿。但是在16年年底的社區(qū)維護者投票中多數人支持網絡不留在containerd中粥烁,因為按照大多數維護者的認識網絡過于復雜,而且網絡設置常常需要跨越節(jié)點蝇棉。這部分功能由containerd的客戶端(Docker Engine 或k8s)做更合適讨阻。
這里順便介紹一下Containerd版本兼容規(guī)則:Containerd同一個大版本下的連續(xù)兩個小版本是兼容的。例Containerd1.1.0和1.2.0卻是兼容的篡殷,1.0.0和1.2.0卻不保證兼容钝吮。
Docker的演進
下圖介紹了containerd在1.11之前(不含)的Docker架構
可以看到在Docker1.11之前,沒有containerd模塊板辽,由libcontainer直接操作主機os接口奇瘦。
下圖介紹了在Docker 1.11--Docker 17.10之間的docker架構
從圖3-2看到這一時期的Docker架構變化就是引入了Containerd和runc,由Containerd完成容器生命期管理劲弦。
下圖列出了Docker 17.11(Docker 17.12為真正的stable版)開始的架構
需要注意的一點圖網絡部分并不在containerd中耳标,仍然在docker engine里。
Docker 17的具體架構演進
這里介紹的內容均來自于Moby社區(qū)的roadmap和Docker\docker-ce 的分析邑跪。
17.06---17.10的路線圖描述此一時期次坡,moby社區(qū)(引擎)的主要工作是:
1、插件功能的提升:方便插件的發(fā)布(通過registry以docker鏡像方式發(fā)布)画畅,解決插件開發(fā)的共性問題(插件任何時候的需要active砸琅,在用戶容器啟動之前就start,以及插件寫在困難)
2轴踱、引擎內部解藕:api已完成重構症脂,builder實現在daemon中已完全獨立。
3淫僻、提升引擎集群管理能力:當前跨節(jié)點網絡(overlay網絡)和節(jié)點發(fā)現已經整合到引擎里诱篷。但是引擎尚不能不依賴于swarmkit完成task調度
4、cli從engine中獨立出來(這一點源自于github moby代碼分析)雳灵。
17.11--18.03 的路線描述此一時期棕所,moby社區(qū)(引擎)的主要工作:
1、引擎使用Containerd1.0
2细办、引擎內部解藕橙凳,計劃整合buildkit工具
Docker架構演進大事記
1蕾殴、Docker 1.9 推出swarm,作為獨立工具岛啸,用于集群管理和服務編排
2钓觉、Docker 1.11 推出containerd和runc。
3坚踩、Docker 1.12 swarm進入引擎
4荡灾、Docker 17.06 引擎社區(qū)更名為moby,do?c?ke?r社區(qū)版本更名為docker-ce(類似于紅帽的fedora和rhel)
5瞬铸、Docker 17.12 Docker正式引入containerd 1.0
6批幌、Docker 18.06 正式在engine里加入了buildkit,在設置一個環(huán)境變量后可以使用buildkit完成docker build過程嗓节。
Docker 18.06.1正式將containerd 1.1引入docker荧缘。
k8s社區(qū)對Docker 17.03之后版本態(tài)度
在Docker 17.03后Docker因為moby和containerd等原因版本變動比較大,我們可以看到k8s r11發(fā)布后的2018年9月仍然沒有將Docker 17.03以后(不含)版本作為k8s的兼容Docker版本拦宣。從社區(qū)的討論來看社區(qū)已經推薦將containerd直接對接cri截粗,完成k8s的集成。見https://github.com/kubernetes/kubernetes/issues/42926鸵隧,其中cpuguy83(此人為moby社區(qū)的主要維護者)推薦直接使用containerd替代docker 17.03以后的版本對接k8s绸罗。本來docker在k8s社區(qū)中的兼容性測試由k8s sig-node 工作組完成,但是通過k8s討論可以看到sig-node并沒有計劃做docker 17.03以后docker的兼容性測試豆瘫。
最新消息是2018年9月27日k8s出r12 rc的時候珊蟀,kubeadm里已經加入了對docker18.06的支持,且完成了ci測試外驱。12 rc 文檔里將docker17.12育灸,18.03,18.06之后列入支持表略步。但在k8s中 sig-node工作組負責底層容器接口描扯,docker在k8s版本的兼容性測試本應由此工作組完成定页,但是sig-node對于docker 17.03版本以后docker版本的態(tài)度依然冷淡趟薄,一直未列入明確的工作計劃中。sig-node工作組兩位主席是谷歌和紅帽的典徊,它們對于cri更感興趣杭煎。在2018年5月,sig-node和containerd社區(qū)共同完成了cri-containerd合入containerd1.1的工作卒落,并發(fā)布了containerd 整合到kubenetes的GA羡铲。完成此部分工作后,k8s驅動containerd的結構更簡單明確儡毕。下圖介紹了docker也切,containerd在k8s上的架構圖:
從上面兩幅圖我們可以看到containerd1.1在k8s上擁有更簡單的結構圖扑媚,驅動更為簡單。而且根據k8s社區(qū)的測試雷恃,直接使用containerd替代docker可以獲得容器啟動時間疆股、內存消耗和cpu消耗減少的紅利。上述結論來自于:
https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/
所以sig-node工作組對docker 高版本不感冒倒槐。目前多方力量博弈旬痹,未來k8s下層的runtime花落誰家還再觀察。
docker-manager是老的kubelet介入docker的方式讨越。
cri從k8s 1.6開始正式進入k8s
cri直接介入containerd是從18年4月两残,containerd1.1開始
PaaS平臺選型建議
如果你正在對基于k8s的PaaS平臺進行生產環(huán)境選型,我建議你使用Docker17.03把跨,因為它成熟穩(wěn)定且k8s r9,r10和r11做過穩(wěn)定人弓、兼容性測試。如果你喜歡嘗試新事物着逐,我建議你跳過Docker17.03之后票从,直接在kublet上使用containerd1.1。如果你喜歡docker新版本滨嘱,那么你可以嘗試docker18.06峰鄙,因為Docker17.12是Docker變化最劇烈的一個版本穩(wěn)定性不好說,且kuberadm中r12 rc里加入了對18.06的支持所以用最新的好了太雨。而且更關鍵的一點docker 18.06.1使用containerd 1.1吟榴,它支持一個特性:上層容器控制平臺的namespace隔離,簡單點說就是docker和k8s均可以在同一個節(jié)點上操作同一個containerd囊扳,且相互隔離不可見吩翻。如此可以預留選擇傳統k8s+docker組合時刻,保留將來切換成k8s+containerd組合的可能性锥咸,進而為自己的框架保持演進的靈活性狭瞎。