溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

深入解析阿里 PouchContainer 如何實(shí)現(xiàn)容器原地升級(jí)

發(fā)布時(shí)間:2020-08-06 12:41:23 來源:網(wǎng)絡(luò) 閱讀:1323 作者:阿里系統(tǒng)軟件技術(shù) 欄目:建站服務(wù)器

PouchContainer 是阿里巴巴集團(tuán)開源的高效、輕量級(jí)企業(yè)級(jí)富容器引擎技術(shù),擁有隔離性強(qiáng)、可移植性高、資源占用少等特性。可以幫助企業(yè)快速實(shí)現(xiàn)存量業(yè)務(wù)容器化,同時(shí)提高超大規(guī)模下數(shù)據(jù)中心的物理資源利用率。已助力阿里巴巴集團(tuán)實(shí)現(xiàn)在線業(yè)務(wù) 100% 容器化,雙 11 容器規(guī)模達(dá)到百萬級(jí)。

背景
阿里巴巴集團(tuán)內(nèi)部,容器使用方式有很大一部分是富容器模式,像這種基于傳統(tǒng)虛擬機(jī)運(yùn)維模式下的富容器,其中也有一定數(shù)量容器仍然是有狀態(tài)的。有狀態(tài)服務(wù)的更新和升級(jí)是企業(yè)內(nèi)部頻率很高的一個(gè)日常操作,對(duì)于以鏡像為交付的容器技術(shù)來說,服務(wù)的更新和升級(jí),對(duì)應(yīng)的容器操作實(shí)際上是兩步:舊鏡像容器的刪除,以及新鏡像容器的創(chuàng)建。而有狀態(tài)服務(wù)的升級(jí),則要求保證新容器必須繼承舊容器所有的資源,比如網(wǎng)絡(luò)、存儲(chǔ)等信息。下面給出兩個(gè)實(shí)際的業(yè)務(wù)案例來直觀闡述富容器業(yè)務(wù)發(fā)布場(chǎng)景需求:

客戶案例一:某數(shù)據(jù)庫業(yè)務(wù),在第一次創(chuàng)建容器服務(wù)時(shí),會(huì)將遠(yuǎn)程的數(shù)據(jù)下載到本地,作為數(shù)據(jù)庫的初始數(shù)據(jù)。因?yàn)閿?shù)據(jù)庫初始化過程會(huì)比較長(zhǎng),所以在之后可能存在的服務(wù)升級(jí)過程中,新容器需要繼承舊容器的存儲(chǔ)數(shù)據(jù),來降低業(yè)務(wù)發(fā)布的時(shí)間;

客戶案例二:某中間件服務(wù),業(yè)務(wù)采取服務(wù)注冊(cè)的模式,即所有新擴(kuò)容的容器 IP 必須首先注冊(cè)到服務(wù)器列表中,否則新擴(kuò)容業(yè)務(wù)容器不可用。在業(yè)務(wù)容器每次升級(jí)發(fā)布時(shí),需要保證新容器繼承舊容器 IP,否則會(huì)導(dǎo)致新發(fā)布的服務(wù)不可用。

現(xiàn)在很多企業(yè)都是使用 Moby(2017 年 Docker 更名為 Moby) 作為容器引擎,但 Moby 的所有 API 中并沒有一個(gè)接口來對(duì)標(biāo)容器升級(jí)這一操作。而組合 API 的方式,必然會(huì)增加很多 API 請(qǐng)求次數(shù),比如需要請(qǐng)求容器的增刪 API,需要請(qǐng)求 IP 保留的 API 等等,還可能增加升級(jí)操作失敗的風(fēng)險(xiǎn)。

基于以上背景,PouchContainer 在容器引擎層面提供了一個(gè) upgrade 接口,用于實(shí)現(xiàn)容器的原地升級(jí)功能。將容器升級(jí)功能下沉到容器引擎這一層來做,對(duì)于操作容器相關(guān)資源更加方便,并且減少很多 API 請(qǐng)求,讓容器升級(jí)操作變得更加高效。

Upgrade 功能具體實(shí)現(xiàn)
容器底層存儲(chǔ)介紹
PouchContainer 底層對(duì)接的是 Containerd v1.0.3 ,對(duì)比 Moby,在容器存儲(chǔ)架構(gòu)上有很大的差別,所以在介紹 PouchContainer 如何實(shí)現(xiàn)容器原地升級(jí)功能之前,有必要先簡(jiǎn)單介紹一下在 PouchContainer 中一個(gè)容器的存儲(chǔ)架構(gòu):

image.png | center | 600x336.3525091799266

對(duì)比 Moby 中容器存儲(chǔ)架構(gòu),PouchContainer 主要不一樣的地方:

PouchContainer 中沒有了 GraphDriver 和 Layer 的概念,新的存儲(chǔ)架構(gòu)里引入了 Snapshotter 和 Snapshot,從而更加擁抱 CNCF 項(xiàng)目 containerd 的架構(gòu)設(shè)計(jì)。Snapshotter 可以理解為存儲(chǔ)驅(qū)動(dòng),比如 overlay、devicemapper、btrfs 等。Snapshot 為鏡像快照,分為兩種:一種只讀的,即容器鏡像的每一層只讀數(shù)據(jù);一種為可讀寫的,即容器可讀寫層,所有容器增量數(shù)據(jù)都會(huì)存儲(chǔ)在可讀寫 Snapshot 中;

Containerd 中容器和鏡像元數(shù)據(jù)都存儲(chǔ)在 boltdb 中,這樣的好處是每次服務(wù)重啟不需要通過讀取宿主機(jī)文件目錄信息來初始化容器和鏡像數(shù)據(jù),而是只需要初始化 boltdb。

Upgrade 功能需求
每一個(gè)系統(tǒng)和功能設(shè)計(jì)之初,都需要詳細(xì)調(diào)研該系統(tǒng)或功能需要為用戶解決什么疼點(diǎn)。經(jīng)過調(diào)研阿里內(nèi)部使用容器原地升級(jí)功能的具體業(yè)務(wù)場(chǎng)景,我們對(duì) upgrade 功能設(shè)計(jì)總結(jié)了三點(diǎn)要求:

數(shù)據(jù)一致性

靈活性

魯棒性

數(shù)據(jù)一致性指 upgrade 前后需要保證一些數(shù)據(jù)不變:

網(wǎng)絡(luò):升級(jí)前后,容器網(wǎng)絡(luò)配置要保持不變;

存儲(chǔ):新容器需要繼承舊容器的所有 volume ;

Config:新容器需要繼承舊容器的某一些配置信息,比如 Env, Labels 等信息;

靈活性指 upgrade 操作在舊容器的基礎(chǔ)上,允許引入新的配置:

允許修改新容器的 cpu、memory 等信息;

對(duì)新的鏡像,即要支持指定新的 Entrypoint ,也要允許繼承舊容器的 Entrypoint ;

支持給容器增加新的 volume,新的鏡像中可能會(huì)包含新的 volume 信息,在新建容器時(shí),需要對(duì)這部分 volume 信息進(jìn)行解析,并創(chuàng)建新的 volume。

魯棒性是指在進(jìn)行容器原地升級(jí)操作期間,需要對(duì)可能出現(xiàn)的異常情況進(jìn)行處理,支持回滾策略,升級(jí)失敗可以回滾到舊容器。

Upgrade 功能具體實(shí)現(xiàn)
Upgrade API 定義
首先說明一下 upgrade API 入口層定義,用于定義升級(jí)操作可以對(duì)容器的哪些參數(shù)進(jìn)行修改。如下 ContainerUpgradeConfig 的定義,容器升級(jí)操作可以對(duì)容器 ContainerConfig 和 HostConfig 都可以進(jìn)行操作,如果在 PouchContainer github 代碼倉庫的 apis/types 目錄下參看這兩個(gè)參數(shù)的定義,可以發(fā)現(xiàn)實(shí)際上,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 操作,實(shí)際上是在保證網(wǎng)絡(luò)配置和原始 volume 配置不變的前提下,進(jìn)行舊容器的刪除操作,以及使用新鏡像創(chuàng)建新容器的過程,如下給出了 upgrade 操作流程的詳細(xì)說明:

首先需要備份原有容器的所有操作,用于升級(jí)失敗之后,進(jìn)行回滾操作;

更新容器配置參數(shù),將請(qǐng)求參數(shù)中新的配置參數(shù)合并到舊的容器參數(shù)中,使新配置生效;

鏡像 Entrypoint 參數(shù)特殊處理:如果新的參數(shù)中指定了 Entrypoint 參數(shù),則使用新的參數(shù);否則查看舊容器的 Entrypoint ,如果該參數(shù)是通過配置參數(shù)指定,而不是舊鏡像中自帶的,則使用舊容器的 Entrypoint 作為新容器的 Entrypoint ;如果都不是,最后使用新鏡像中的 Entrypoint 最為新創(chuàng)建容器的 Entrypoint 。對(duì)新容器 Entrypoint 這樣處理的原因是為了保持容器服務(wù)入口參數(shù)的連續(xù)性。

判斷容器的狀態(tài),如果是 running 狀態(tài)的容器,首先 stop 容器;之后基于新的鏡像創(chuàng)建一個(gè)新的 Snapshot 作為新容器讀寫層;

新的 Snapshot 創(chuàng)建成功之后,再次判斷舊容器升級(jí)之前的狀態(tài),如果是 running 狀態(tài),則需要啟動(dòng)新的容器,否則不需要做任何操作;

最后進(jìn)行容器升級(jí)清理工作,刪掉舊的 Snapshot,并將最新配置進(jìn)行存盤。

Upgrade 操作回滾
upgrade 操作可能會(huì)出現(xiàn)一些異常情況,現(xiàn)在的升級(jí)策略是在出現(xiàn)異常情況時(shí),會(huì)進(jìn)行回滾操作,恢復(fù)到原來舊容器的狀態(tài),在這里我們需要首先定義一下 升級(jí)失敗情況 :

給新容器創(chuàng)建新的資源時(shí)失敗,需要執(zhí)行回滾操作:當(dāng)給新容器創(chuàng)建新的 Snapshot,Volumes 等資源時(shí),會(huì)執(zhí)行回滾操作;

啟動(dòng)新容器出現(xiàn)系統(tǒng)錯(cuò)誤時(shí),需要執(zhí)行回滾操作:即在調(diào)用 containerd API 創(chuàng)建新的容器時(shí)如果失敗則會(huì)執(zhí)行回滾操作。如果 API 返回正常,但容器內(nèi)的程序運(yùn)行異常導(dǎo)致容器退出的情況,不會(huì)執(zhí)行回滾操作。
如下給出了回滾操作的一個(gè)基本操作:

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())
    }
}

}()
在升級(jí)過程中,如果出現(xiàn)異常情況,會(huì)將新創(chuàng)建的 Snapshot 等相關(guān)資源進(jìn)行清理操作,在回滾階段,只需要恢復(fù)舊容器的配置,然后用恢復(fù)后的配置文件啟動(dòng)一個(gè)新容器既可。

Upgrade 功能演示
使用 ubuntu 鏡像創(chuàng)建一個(gè)新容器:

$ 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 容器的鏡像升級(jí)為 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ò)容、縮容操作一樣也是的一個(gè)高頻操作,但是,不管是在現(xiàn)在的 Moby 社區(qū),還是 Containerd 社區(qū)都沒有一個(gè)與該操作對(duì)標(biāo)的 API,PouchContainer 率先實(shí)現(xiàn)了這個(gè)功能,解決了容器技術(shù)在企業(yè)環(huán)境中有狀態(tài)服務(wù)更新發(fā)布的一個(gè)痛點(diǎn)問題。PouchContainer 現(xiàn)在也在嘗試與其下游依賴組件服務(wù)如 Containerd 保持緊密的聯(lián)系,所以后續(xù)也會(huì)將 upgrade 功能回饋給 Containerd 社區(qū),增加 Containerd 的功能豐富度。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI