PouchContainer 是阿里巴巴集團(tuán)開源的高效、輕量級企業(yè)級富容器引擎技術(shù),擁有隔離性強(qiáng)、可移植性高、資源占用少等特性??梢詭椭髽I(yè)快速實現(xiàn)存量業(yè)務(wù)容器化,同時提高超大規(guī)模下數(shù)據(jù)中心的物理資源利用率。已助力阿里巴巴集團(tuán)實現(xiàn)在線業(yè)務(wù) 100% 容器化,雙 11 容器規(guī)模達(dá)到百萬級。
創(chuàng)新互聯(lián)服務(wù)項目包括蘭溪網(wǎng)站建設(shè)、蘭溪網(wǎng)站制作、蘭溪網(wǎng)頁制作以及蘭溪網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,蘭溪網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到蘭溪省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!背景
阿里巴巴集團(tuán)內(nèi)部,容器使用方式有很大一部分是富容器模式,像這種基于傳統(tǒng)虛擬機(jī)運(yùn)維模式下的富容器,其中也有一定數(shù)量容器仍然是有狀態(tài)的。有狀態(tài)服務(wù)的更新和升級是企業(yè)內(nèi)部頻率很高的一個日常操作,對于以鏡像為交付的容器技術(shù)來說,服務(wù)的更新和升級,對應(yīng)的容器操作實際上是兩步:舊鏡像容器的刪除,以及新鏡像容器的創(chuàng)建。而有狀態(tài)服務(wù)的升級,則要求保證新容器必須繼承舊容器所有的資源,比如網(wǎng)絡(luò)、存儲等信息。下面給出兩個實際的業(yè)務(wù)案例來直觀闡述富容器業(yè)務(wù)發(fā)布場景需求:
客戶案例一:某數(shù)據(jù)庫業(yè)務(wù),在第一次創(chuàng)建容器服務(wù)時,會將遠(yuǎn)程的數(shù)據(jù)下載到本地,作為數(shù)據(jù)庫的初始數(shù)據(jù)。因為數(shù)據(jù)庫初始化過程會比較長,所以在之后可能存在的服務(wù)升級過程中,新容器需要繼承舊容器的存儲數(shù)據(jù),來降低業(yè)務(wù)發(fā)布的時間;
客戶案例二:某中間件服務(wù),業(yè)務(wù)采取服務(wù)注冊的模式,即所有新擴(kuò)容的容器 IP 必須首先注冊到服務(wù)器列表中,否則新擴(kuò)容業(yè)務(wù)容器不可用。在業(yè)務(wù)容器每次升級發(fā)布時,需要保證新容器繼承舊容器 IP,否則會導(dǎo)致新發(fā)布的服務(wù)不可用。
現(xiàn)在很多企業(yè)都是使用 Moby(2017 年 Docker 更名為 Moby) 作為容器引擎,但 Moby 的所有 API 中并沒有一個接口來對標(biāo)容器升級這一操作。而組合 API 的方式,必然會增加很多 API 請求次數(shù),比如需要請求容器的增刪 API,需要請求 IP 保留的 API 等等,還可能增加升級操作失敗的風(fēng)險。
基于以上背景,PouchContainer 在容器引擎層面提供了一個 upgrade 接口,用于實現(xiàn)容器的原地升級功能。將容器升級功能下沉到容器引擎這一層來做,對于操作容器相關(guān)資源更加方便,并且減少很多 API 請求,讓容器升級操作變得更加高效。
Upgrade 功能具體實現(xiàn)
容器底層存儲介紹
PouchContainer 底層對接的是 Containerd v1.0.3 ,對比 Moby,在容器存儲架構(gòu)上有很大的差別,所以在介紹 PouchContainer 如何實現(xiàn)容器原地升級功能之前,有必要先簡單介紹一下在 PouchContainer 中一個容器的存儲架構(gòu):
image.png | center | 600x336.3525091799266
對比 Moby 中容器存儲架構(gòu),PouchContainer 主要不一樣的地方:
PouchContainer 中沒有了 GraphDriver 和 Layer 的概念,新的存儲架構(gòu)里引入了 Snapshotter 和 Snapshot,從而更加擁抱 CNCF 項目 containerd 的架構(gòu)設(shè)計。Snapshotter 可以理解為存儲驅(qū)動,比如 overlay、devicemapper、btrfs 等。Snapshot 為鏡像快照,分為兩種:一種只讀的,即容器鏡像的每一層只讀數(shù)據(jù);一種為可讀寫的,即容器可讀寫層,所有容器增量數(shù)據(jù)都會存儲在可讀寫 Snapshot 中;
Containerd 中容器和鏡像元數(shù)據(jù)都存儲在 boltdb 中,這樣的好處是每次服務(wù)重啟不需要通過讀取宿主機(jī)文件目錄信息來初始化容器和鏡像數(shù)據(jù),而是只需要初始化 boltdb。
Upgrade 功能需求
每一個系統(tǒng)和功能設(shè)計之初,都需要詳細(xì)調(diào)研該系統(tǒng)或功能需要為用戶解決什么疼點(diǎn)。經(jīng)過調(diào)研阿里內(nèi)部使用容器原地升級功能的具體業(yè)務(wù)場景,我們對 upgrade 功能設(shè)計總結(jié)了三點(diǎn)要求:
數(shù)據(jù)一致性
靈活性
魯棒性
數(shù)據(jù)一致性指 upgrade 前后需要保證一些數(shù)據(jù)不變:
網(wǎng)絡(luò):升級前后,容器網(wǎng)絡(luò)配置要保持不變;
存儲:新容器需要繼承舊容器的所有 volume ;
Config:新容器需要繼承舊容器的某一些配置信息,比如 Env, Labels 等信息;
靈活性指 upgrade 操作在舊容器的基礎(chǔ)上,允許引入新的配置:
允許修改新容器的 cpu、memory 等信息;
對新的鏡像,即要支持指定新的 Entrypoint ,也要允許繼承舊容器的 Entrypoint ;
支持給容器增加新的 volume,新的鏡像中可能會包含新的 volume 信息,在新建容器時,需要對這部分 volume 信息進(jìn)行解析,并創(chuàng)建新的 volume。
魯棒性是指在進(jìn)行容器原地升級操作期間,需要對可能出現(xiàn)的異常情況進(jìn)行處理,支持回滾策略,升級失敗可以回滾到舊容器。
Upgrade 功能具體實現(xiàn)
Upgrade API 定義
首先說明一下 upgrade API 入口層定義,用于定義升級操作可以對容器的哪些參數(shù)進(jìn)行修改。如下 ContainerUpgradeConfig 的定義,容器升級操作可以對容器 ContainerConfig 和 HostConfig 都可以進(jìn)行操作,如果在 PouchContainer github 代碼倉庫的 apis/types 目錄下參看這兩個參數(shù)的定義,可以發(fā)現(xiàn)實際上,upgrade 操作可以修改舊容器的所有相關(guān)配置。
// ContainerUpgradeConfig ContainerUpgradeConfig is used for API "POST /containers/upgrade".
// It wraps all kinds of config used in container upgrade.
// It can be used to encode client params in client and unmarshal request body in daemon side.
//
// swagger:model ContainerUpgradeConfig
type ContainerUpgradeConfig struct {
ContainerConfig
// host config
HostConfig *HostConfig `json:"HostConfig,omitempty"`
}
Upgrade 詳細(xì)操作流程
容器 upgrade 操作,實際上是在保證網(wǎng)絡(luò)配置和原始 volume 配置不變的前提下,進(jìn)行舊容器的刪除操作,以及使用新鏡像創(chuàng)建新容器的過程,如下給出了 upgrade 操作流程的詳細(xì)說明:
首先需要備份原有容器的所有操作,用于升級失敗之后,進(jìn)行回滾操作;
更新容器配置參數(shù),將請求參數(shù)中新的配置參數(shù)合并到舊的容器參數(shù)中,使新配置生效;
鏡像 Entrypoint 參數(shù)特殊處理:如果新的參數(shù)中指定了 Entrypoint 參數(shù),則使用新的參數(shù);否則查看舊容器的 Entrypoint ,如果該參數(shù)是通過配置參數(shù)指定,而不是舊鏡像中自帶的,則使用舊容器的 Entrypoint 作為新容器的 Entrypoint ;如果都不是,最后使用新鏡像中的 Entrypoint 最為新創(chuàng)建容器的 Entrypoint 。對新容器 Entrypoint 這樣處理的原因是為了保持容器服務(wù)入口參數(shù)的連續(xù)性。
判斷容器的狀態(tài),如果是 running 狀態(tài)的容器,首先 stop 容器;之后基于新的鏡像創(chuàng)建一個新的 Snapshot 作為新容器讀寫層;
新的 Snapshot 創(chuàng)建成功之后,再次判斷舊容器升級之前的狀態(tài),如果是 running 狀態(tài),則需要啟動新的容器,否則不需要做任何操作;
最后進(jìn)行容器升級清理工作,刪掉舊的 Snapshot,并將最新配置進(jìn)行存盤。
Upgrade 操作回滾
upgrade 操作可能會出現(xiàn)一些異常情況,現(xiàn)在的升級策略是在出現(xiàn)異常情況時,會進(jìn)行回滾操作,恢復(fù)到原來舊容器的狀態(tài),在這里我們需要首先定義一下 升級失敗情況 :
給新容器創(chuàng)建新的資源時失敗,需要執(zhí)行回滾操作:當(dāng)給新容器創(chuàng)建新的 Snapshot,Volumes 等資源時,會執(zhí)行回滾操作;
啟動新容器出現(xiàn)系統(tǒng)錯誤時,需要執(zhí)行回滾操作:即在調(diào)用 containerd API 創(chuàng)建新的容器時如果失敗則會執(zhí)行回滾操作。如果 API 返回正常,但容器內(nèi)的程序運(yùn)行異常導(dǎo)致容器退出的情況,不會執(zhí)行回滾操作。
如下給出了回滾操作的一個基本操作:
defer func() {
if !needRollback {
return
}
// rollback to old container.
c.meta = &backupContainerMeta
// create a new containerd container.
if err := mgr.createContainerdContainer(ctx, c); err != nil {
logrus.Errorf("failed to rollback upgrade action: %s", err.Error())
if err := mgr.markStoppedAndRelease(c, nil); err != nil {
logrus.Errorf("failed to mark container %s stop status: %s", c.ID(), err.Error())
}
}
}()
在升級過程中,如果出現(xiàn)異常情況,會將新創(chuàng)建的 Snapshot 等相關(guān)資源進(jìn)行清理操作,在回滾階段,只需要恢復(fù)舊容器的配置,然后用恢復(fù)后的配置文件啟動一個新容器既可。
Upgrade 功能演示
使用 ubuntu 鏡像創(chuàng)建一個新容器:
$ pouch run --name test -d -t registry.hub.docker.com/library/ubuntu:14.04 top
43b75002b9a20264907441e0fe7d66030fb9acedaa9aa0fef839ccab1f9b7a8f
$ pouch ps
Name ID Status Created Image Runtime
test 43b750 Up 3 seconds 3 seconds ago registry.hub.docker.com/library/ubuntu:14.04 runc
將 test 容器的鏡像升級為 busybox :
$ pouch upgrade --name test registry.hub.docker.com/library/busybox:latest top
test
$ pouch ps
Name ID Status Created Image Runtime
test 43b750 Up 3 seconds 34 seconds ago registry.hub.docker.com/library/busybox:latest runc
如上功能演示,通過 upgrade 接口,直接將容器的鏡像替換為新的鏡像,而其他配置都沒有變化。
總結(jié)
在企業(yè)生產(chǎn)環(huán)境中,容器 upgrade 操作和容器擴(kuò)容、縮容操作一樣也是的一個高頻操作,但是,不管是在現(xiàn)在的 Moby 社區(qū),還是 Containerd 社區(qū)都沒有一個與該操作對標(biāo)的 API,PouchContainer 率先實現(xiàn)了這個功能,解決了容器技術(shù)在企業(yè)環(huán)境中有狀態(tài)服務(wù)更新發(fā)布的一個痛點(diǎn)問題。PouchContainer 現(xiàn)在也在嘗試與其下游依賴組件服務(wù)如 Containerd 保持緊密的聯(lián)系,所以后續(xù)也會將 upgrade 功能回饋給 Containerd 社區(qū),增加 Containerd 的功能豐富度。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。