Containerd到底是干啥的?

參考文獻(xiàn):
https://www.cnblogs.com/sparkdev/p/9063042.html
https://github.com/containerd/containerd/blob/master/docs/getting-started.md
我們可以把 docker 抽象為下圖所示的結(jié)構(gòu)(此圖來自互聯(lián)網(wǎng)):

image

從圖中可以看出,
docker 對容器的管理和操作基本都是通過 containerd 完成的。

1、那么,containerd 是什么呢?

Containerd 是一個工業(yè)級標(biāo)準(zhǔn)的容器運(yùn)行時,它強(qiáng)調(diào)簡單性、健壯性和可移植性
Containerd 可以在宿主機(jī)中管理完整容器生命周期

  • 容器鏡像傳輸存儲
  • 容器的執(zhí)行管理
  • 存儲網(wǎng)絡(luò)等。

詳細(xì)點(diǎn)說,Containerd 負(fù)責(zé)干下面這些事情:

  • 管理容器的生命周期(從創(chuàng)建容器到銷毀容器)
  • 拉取/推送容器鏡像
  • 存儲管理(管理鏡像及容器數(shù)據(jù)的存儲)
  • 調(diào)用 runC 運(yùn)行容器(與 runC 等容器運(yùn)行時交互)
  • 管理容器網(wǎng)絡(luò)接口及網(wǎng)絡(luò)

注意:Containerd 被設(shè)計(jì)成嵌入到一個更大的系統(tǒng)中,而不是直接由開發(fā)人員或終端用戶使用。

2、為什么需要containerd

我們可以從下面幾點(diǎn)來理解為什么需要獨(dú)立的 containerd:

  • 繼續(xù)從整體 docker 引擎中分離出的項(xiàng)目(開源項(xiàng)目的思路)
  • 可以被 Kubernets CRI 等項(xiàng)目使用(通用化)
  • 為廣泛的行業(yè)合作打下基礎(chǔ)(就像 runC 一樣)

重復(fù)一遍
Containerd 被設(shè)計(jì)成嵌入到一個更大的系統(tǒng)中,而不是直接由開發(fā)人員或終端用戶使用。所以 containerd 具有宏大的愿景(此圖來自互聯(lián)網(wǎng)):

image

當(dāng) containerd 和 runC 成為標(biāo)準(zhǔn)化容器服務(wù)的基石后,
上層的應(yīng)用就可以直接建立在 containerd 和 runC 之上。
上圖中展示的容器平臺都已經(jīng)支持 containerd 和 runC 的組合了,相信接下來會有更多類似的容器平臺出現(xiàn)。

3、Containerd的技術(shù)方向和目標(biāo)

簡潔的基于 gRPC 的 API 和 client library

  • 完整的 OCI 支持(runtimeimage spec)
  • 同時具備穩(wěn)定性和高性能的定義良好的容器核心功能
  • 一個解耦的系統(tǒng)(讓 image、filesystem、runtime 解耦合),實(shí)現(xiàn)插件式的擴(kuò)展和重用

下圖展示了 containerd 的架構(gòu)(此圖來自互聯(lián)網(wǎng)):

image

在架構(gòu)設(shè)計(jì)和實(shí)現(xiàn)方面,核心開發(fā)人員在他們的博客里提到了通過反思 graphdriver 的實(shí)現(xiàn),他們將 containerd 設(shè)計(jì)成了 snapshotter 的模式,這也使得 containerd 對于 overlay 文件系、snapshot 文件系統(tǒng)的支持比較好。

storage、metadata 和 runtime 的三大塊劃分非常清晰,通過抽象出 events 的設(shè)計(jì),containerd 也得以將網(wǎng)絡(luò)層面的復(fù)雜度交給了上層處理,僅提供 network namespace 相關(guān)的一些接口添加和配置 API。
這樣做的好處無疑是巨大的,保留最小功能集合的純粹和高效,而將更多的復(fù)雜性及靈活性交給了插件及上層系統(tǒng)。

4、安裝并運(yùn)行containerd

在從概念上對 containerd 有所了解之后,讓我們安裝最新版的 containerd 并實(shí)際把玩一下。
本文的演示環(huán)境為 centos7。
注意:containerd 需要調(diào)用 runC,所以在安裝 containerd 之前請先安裝 runC。RunC 的安裝請參考筆者博文《RunC到底是干啥的》。
http://www.lxweimin.com/p/2f6296190049

4.1、下載并解壓containerd程序

從 github 上下載 containerd 包(https://github.com/containerd/containerd/releases),
當(dāng)前的最新版本為 v1.3.0。
不過我們使用v1.1.0測試即可(https://github.com/containerd/containerd/tags?after=v1.2.0-beta.1),
然后把下載到的壓縮包解壓到 /usr/local 目錄下:

tar -zxvf containerd-1.1.0.linux-amd64.tar.gz

當(dāng)前 containerd 的安裝包中一共有五個文件,通過上面的命令它們被安裝到了 /usr/local/bin 目錄中:

  • containerd:即容器的運(yùn)行時,以 gRPC 協(xié)議的形式提供滿足 OCI 標(biāo)準(zhǔn)的 API
  • containerd-release 和 containerd-stress:分別是 containerd 項(xiàng)目的發(fā)行版發(fā)布工具以及壓力測試工具
  • containerd-shim:這是每一個容器的運(yùn)行時載體,我們在 docker 宿主機(jī)上看到的 shim 也正是代表著一個個通過調(diào)用 containerd 啟動的 docker 容器。
  • ctr:它是一個簡單的 CLI 接口,用作 containerd 本身的一些調(diào)試用途,投入生產(chǎn)使用時還是應(yīng)該配合docker 或者 cri-containerd 部署
image

4.2、生成containerd配置文件

Containerd 的配置文件默認(rèn)為 /etc/containerd/config.toml。
這里我們可以通過命令來生成一個默認(rèn)的配置文件:

mkdir /etc/containerd
containerd config default > /etc/containerd/config.toml

對于演示來說,這個默認(rèn)的配置已經(jīng)足夠了。

4.3、將containerd服務(wù)交給systemd運(yùn)行,需要配置文件

創(chuàng)建文件 containerd.service:

touch /lib/systemd/system/containerd.service

編輯其內(nèi)容如下:

[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd
Delegate=yes
KillMode=process
LimitNOFILE=1048576
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity

[Install]
WantedBy=multi-user.target

執(zhí)行下面的命令啟動 containerd 服務(wù)并查看服務(wù)的狀態(tài):

systemctl daemon-reload
systemctl enable containerd.service
systemctl start containerd.service
systemctl status containerd.service

至此 containerd 已經(jīng)安裝成功!

image

image

5、演示demo

可以使用類似 runC 的方式運(yùn)行容器,也就是使用現(xiàn)成的客戶端工具 ctr,由于用法與 runC 非常相似,所以這里不再贅述。
Containerd 還提供了 client package 用于在代碼中集成 containerd 客戶端,
下面的 demo 就采用 golang 和 client package 在代碼中訪問 containerd 服務(wù)來創(chuàng)建并運(yùn)行容器!

5.1、鏈接containerd服務(wù)

創(chuàng)建 main.go 文件,內(nèi)容如下:

package main

import (
    "log"
    "github.com/containerd/containerd"
)

func main() {
    if err := redisExample(); err != nil {
        log.Fatal(err)
    }
}

func redisExample() error {
    client, err := containerd.New("/run/containerd/containerd.sock")
    if err != nil {
        return err
    }
    defer client.Close()
    return nil
}

上面代碼中使用默認(rèn)的 containerd 套接字創(chuàng)建了一個客戶端對象。
因?yàn)?containerd daemon 通過 gRPC 協(xié)議提供服務(wù),所以我們需要創(chuàng)建一個用于調(diào)用客戶端方法的上下文。
在創(chuàng)建上下文之后,我們還應(yīng)該為我們的 demo 設(shè)置一個 namespace,創(chuàng)建單獨(dú)的 namespace 可以與用戶的資源進(jìn)行隔離以免發(fā)生沖突:

ctx := namespaces.WithNamespace(context.Background(), "demo")

5.2、拉取redis鏡像

在創(chuàng)建客戶端對象后我們就可以從 dockerhub 上拉取容器鏡像了,這里我們拉取一個 redis 鏡像:

image, err := client.Pull(ctx, "docker.io/library/redis:alpine", containerd.WithPullUnpack)
if err != nil {
    return err
}

使用客戶端的 Pull 方法從 dockerhub 上拉取 redis 鏡像,這個方法支持 Opts 模式,所以我們可以指定 containerd.WithPullUnpackso 讓下載完成后直接把鏡像解壓縮為一個snapshotter作為即將運(yùn)行的容器的rootfs

5.3、創(chuàng)建OCI Spec和容器

有了 rootfs 還需要運(yùn)行 OCI 容器所需的 OCI runtime spec,我們通過 NewContainer 方法可以使用默認(rèn)的 OCI runtime spec 直接創(chuàng)建容器對象。
當(dāng)然,也可以通過 Opts 模式的參數(shù)修改默認(rèn)值:

container, err := client.NewContainer(
    ctx,
    "redis-server",
    containerd.WithImage(image),
    containerd.WithNewSnapshot("redis-server-snapshot", image),
    containerd.WithNewSpec(oci.WithImageConfig(image)),
)
if err != nil {
    return err
}
defer container.Delete(ctx, containerd.WithSnapshotCleanup)

當(dāng)我們?yōu)槿萜鲃?chuàng)建一個 snapshot 時需要提供 snapshot 的 ID及其父鏡像。
通過提供一個單獨(dú)的 snapshot ID,而不是容器 ID,我們可以輕松地在不同的容器中重用現(xiàn)有的 snapshot。
在完成這個示例之后,我們還添加了 defer container.Delete 調(diào)用來刪除容器以及它的快照。

5.4、創(chuàng)建并運(yùn)行容器的task

一個 container 對象只是包含了運(yùn)行一個容器所需的資源及配置的數(shù)據(jù)結(jié)構(gòu),一個容器真正的運(yùn)行起來是由 Task 對象實(shí)現(xiàn)的:

task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio))
if err != nil {
    return err
}
defer task.Delete(ctx)

此時容器的狀態(tài)相當(dāng)于我們在《RunC 簡介》一文中介紹的 "created"。
這意味著 namespaces、rootfs 和容器的配置都已經(jīng)初始化成功了,只是用戶進(jìn)程(這里是 redis-server)還沒有啟動。
在這個時機(jī),我們可以為容器設(shè)置網(wǎng)卡,還可以配置工具來對容器進(jìn)行監(jiān)控等。

5.5、讓運(yùn)行中的task退出

當(dāng)要結(jié)束容器的運(yùn)行時,可以調(diào)用 task.Kill 方法。其實(shí)就是向容器中運(yùn)行的進(jìn)程發(fā)送信號:

// 讓容器先運(yùn)行一會兒
time.Sleep(3 * time.Second)

if err := task.Kill(ctx, syscall.SIGTERM); err != nil {
    return err
}

status := <-exitStatusC
code, exitedAt, err := status.Result()
if err != nil {
    return err
}
fmt.Printf("redis-server exited with status: %d\n", code)

向容器發(fā)送結(jié)束的信號后,代碼等待容器結(jié)束,并輸出返回碼。最后我們刪除 task 對象:

status, err := task.Delete(ctx)

完整的 demo 代碼請參考這里(https://github.com/containerd/containerd/blob/master/docs/getting-started.md)。

6、總結(jié)

可以看出,在容器技術(shù)逐步標(biāo)準(zhǔn)化后,containerd 在相關(guān)的技術(shù)棧中將占據(jù)非常重要的地位,containerd 提供的核心服務(wù)很可能成為底層管理容器的標(biāo)準(zhǔn)。
屆時,更上層的容器化應(yīng)用平臺將直接使用 containerd 提供的基礎(chǔ)服務(wù)。

也就是說,containerd的目標(biāo)是做容器技術(shù)的標(biāo)準(zhǔn),除了runc的功能,還做鏡像的拉取上傳,管理容器網(wǎng)絡(luò)接口及網(wǎng)絡(luò)、鏡像的存儲,容器數(shù)據(jù)的存儲

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