写点什么

终于可以像使用 Docker 一样丝滑地使用 Containerd 了!

2021 年 4 月 21 日

终于可以像使用 Docker 一样丝滑地使用 Containerd 了!

有追求的工程师一般都是有技术洁癖的,云原生的世界更是如此,Kubernetes 虽然制定了容器运行时接口(CRI)标准,但早期能用的容器运行时只有 Docker,而 Docker 又不适配这个标准,于是给 Docker 开了后门,花了大量的精力去适配它。后来有了更多的容器运行时可以选择后,Kubernetes 就不得不重新考量要不要继续适配 Docker 了,因为每次更新 Kubelet 都要考虑与 Docker 的适配问题。



标准这个东西就是这样,我定好标准,你兼容了就一起玩,不兼容就拜拜,它就像两个人在一起的底线,你可以重,你可以丑,你也可以不完善,但是你不兼容标准就真的不能一起玩了,于是 Kubernetes 就把 Docker 踢出了群聊。



最终 Kubernetes 选择了 Containerd,时至今日 Containerd 已经变成一个工业级的容器运行时了,它足够简单、健壮,可移植性也很强。


现有 CLI 的不足


虽然 Docker 能干的事情,现在 Containerd 都能干,但 Containerd 还有一个非常明显的缺陷:CLI 不够友好。它无法像 Docker 和 Podman 一样通过一条简单的命令启动一个容器,它的两个 CLI 工具 ctr[1] 和 crictl[2] 都无法实现这么一件非常简单的需求,而这个需求是大多数人都需要的,我总不能为了在本地测试容器而专门部署一个 Kubernetes 集群吧?



ctr 的设计对人类不太友好,例如缺少以下这些和 Docker 类似的功能:


  • docker run -p <PORT>

  • docker run --restart=always

  • 通过凭证文件 ~/.docker/config.json 来拉取镜像

  • docker logs


除此之外还有一个 CLI 工具叫 crictl,和 ctr 一样不太友好。

为了解决这个痛点,Containerd 官方推出了一个新的 CLI 叫 nerdctl[3]。nerdctl 的使用体验和 docker 一样顺滑,例如:


🐳  → nerdctl run -d -p 8080:80 --name=nginx --restart=always nginx
复制代码


nerdctl 只是 docker 的复制品?


nerdctl 的目标并不是单纯地复制 docker 的功能,它还实现了很多 docker 不具备的功能,例如延迟拉取镜像(lazy-pulling[4])、镜像加密(imgcrypt[5])等。



延迟拉取镜像功能可以参考这篇文章:Containerd 使用 Stargz Snapshotter 延迟拉取镜像[6]


虽然这些功能预计最终也会在 Docker 中实现,但可能需要几个月甚至几年的时间[7],因为 Docker 目前的设计只使用一小部分 Containerd 子系统。将来 Docker 有可能重构代码以使用完整的 Containerd,但目前还没看到什么实质性进展。所以 Containerd 社区决定创建一个新的 CLI 来更友好地使用 Containerd


nerdctl 试用


你可以从 nerdctl 的 release[8] 中下载最新的可执行文件,每一个版本都有两种可用的发行版:


  • nerdctl-<VERSION>-linux-amd64.tar.gz : 只包含 nerdctl。

  • nerdctl-full-<VERSION>-linux-amd64.tar.gz : 包含了 nerdctl 和相关依赖组件(containerd, runc, CNI, …)。


如果你已经安装了 Containerd,只需要选择前一个发行版,否则就选择完整版。


安装好 nerdctl 后,就可以使用 nerdctl 来运行容器了:


🐳  → nerdctl run -d -p 80:80 --name=nginx --restart=always nginx:alpine
docker.io/library/nginx:alpine:                                                   resolved       |++++++++++++++++++++++++++++++++++++++|index-sha256:d33e9e24389d7d8b90fe2bcc2dd1bc09b4d235e916ba9d5d9a71cf52e340edb6:    done           |++++++++++++++++++++++++++++++++++++++|manifest-sha256:c1f4e1974241c3f9ddb2866b2bf8e7afbceaa42dae82aabda5e946d03f054ed2: done           |++++++++++++++++++++++++++++++++++++++|config-sha256:bfad9487e175364fd6315426feeee34bf5e6f516d2fe6a4e9b592315e330828e:   done           |++++++++++++++++++++++++++++++++++++++|layer-sha256:29d3f97df6fd99736a0676f9e57e53dfa412cf60b26d95008df9da8197f1f366:    done           |++++++++++++++++++++++++++++++++++++++|layer-sha256:9aae54b2144e5b2b00c610f8805128f4f86822e1e52d3714c463744a431f0f4a:    done           |++++++++++++++++++++++++++++++++++++++|layer-sha256:a5f0adaddd5456b7c5a3753ab541b5fad750f0a6499a15f63571b964eb3e2616:    done           |++++++++++++++++++++++++++++++++++++++|layer-sha256:5df810e1c460527fe400cdd2cab62228f5fb3da0f2dce86a6a6c354972f19b6e:    done           |++++++++++++++++++++++++++++++++++++++|layer-sha256:345aee38d3533398e0eb7118e4323a8970f7615136f2170dfb2b0278bbd9099d:    done           |++++++++++++++++++++++++++++++++++++++|layer-sha256:e6a4c36d7c0e358e5fc02ccdac645b18b85dcfec09d4fb5f8cbdc187ce9467a0:    done           |++++++++++++++++++++++++++++++++++++++|elapsed: 5.7 s                                                                    total:  9.4 Mi (1.6 MiB/s)27b55e0b18b10c4c8f34e3ba709614e7b1760a75db061d2ce5183e8b1101ce09
复制代码

查看创建的容器:

🐳  → nerdctl ps
CONTAINER ID    IMAGE                             COMMAND                   CREATED          STATUS    PORTS                 NAMES3b5faa266a43    docker.io/library/nginx:alpine    "/docker-entrypoint.…"    3 minutes ago    Up        0.0.0.0:80->80/tcp    nginx
复制代码

和 Docker 一样,Containerd 也有一个子命令 network

🐳  → nerdctl network ls
NETWORK ID    NAME               FILE0             bridge              k8s-pod-network    /etc/cni/net.d/10-calico.conflist              host              none
复制代码

来看下默认的 bridge 配置:

🐳  → nerdctl network inspect bridge[    {        "CNI": {            "cniVersion": "0.4.0",            "name": "bridge",            "nerdctlID": 0,            "plugins": [                {                    "type": "bridge",                    "bridge": "nerdctl0",                    "isGateway": true,                    "ipMasq": true,                    "hairpinMode": true,                    "ipam": {                        "type": "host-local",                        "routes": [                            {                                "dst": "0.0.0.0/0"                            }                        ],                        "ranges": [                            [                                {                                    "subnet": "10.4.0.0/24",                                    "gateway": "10.4.0.1"                                }                            ]                        ]                    }                },                {                    "type": "portmap",                    "capabilities": {                        "portMappings": true                    }                },                {                    "type": "firewall"                },                {                    "type": "tuning"                }            ]        },        "NerdctlID": 0    }]
复制代码

可以看到 network 子命令背后还是 CNI 在运作,与 docker network 子命令原理不同。


构建镜像


nerdctl 也可以和 buildkit 结合使用来构建容器镜像,需要先下载 buildkit 的可执行文件:

🐳  → wget https://github.com/moby/buildkit/releases/download/v0.8.2/buildkit-v0.8.2.darwin-amd64.tar.gz
复制代码

将其解压到 $PATH 中:

🐳  → tar -C /usr/local/ -zxvf buildkit-v0.8.2.linux-amd64.tar.gz
复制代码

编写 systemd unit 文件:

# /etc/systemd/system/buildkit.service[Unit]Description=BuildKitDocumentation=https://github.com/moby/buildkit
[Service]ExecStart=/usr/local/bin/buildkitd --oci-worker=false --containerd-worker=true
[Install]WantedBy=multi-user.target
复制代码

启用 buildkit.service 并设置开机自动运行:

🐳  → systemctl enable --now buildkit.service
复制代码

下面以 KubeSphere[9] 项目为例,展示如何使用 nerdctl 来构建镜像。

首先克隆 KubeSphere 官方仓库:

🐳  → git clone --depth=1 https://github.com.cnpmjs.org/kubesphere/kubesphere.git
复制代码

进入仓库目录,编译二进制文件:

🐳  → cd kubesphere🐳  → make ks-apiserver
复制代码

将二进制文件拷贝到 Dockerfile 目录:

🐳  → cp bin/cmd/ks-apiserver build/ks-apiserver
复制代码

进入 Dockerfile 目录,修改 Dockerfile:

# Copyright 2020 The KubeSphere Authors. All rights reserved.# Use of this source code is governed by an Apache license# that can be found in the LICENSE file.FROM alpine:3.11
ARG HELM_VERSION=v3.5.2
RUN apk add --no-cache ca-certificates# install helmRUN wget https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz && \    tar xvf helm-${HELM_VERSION}-linux-amd64.tar.gz && \    rm helm-${HELM_VERSION}-linux-amd64.tar.gz && \    mv linux-amd64/helm /usr/bin/ && \    rm -rf linux-amd64# To speed up building process, we copy binary directly from make# result instead of building it again, so make sure you run the# following command first before building docker image#   make ks-apiserver#COPY  ks-apiserver /usr/local/bin/
EXPOSE 9090CMD ["sh"]
复制代码

构建镜像:

🐳  → cd build/ks-apiserver
🐳  → nerdctl build -t ks-apiserver .[+] Building 22.6s (9/9) FINISHED => [internal] load build definition from Dockerfile                                                                                                                                0.0s => => transferring dockerfile: 812B                                                                                                                                                0.0s => [internal] load .dockerignore                                                                                                                                                   0.0s => => transferring context: 2B                                                                                                                                                     0.0s => [internal] load metadata for docker.io/library/alpine:3.11                                                                                                                      1.0s => [1/4] FROM docker.io/library/alpine:3.11@sha256:bf5fa774f08a9ed2cb301e522b769d43d48124315a4ec50eae3228d03b9dc558                                                                7.9s => => resolve docker.io/library/alpine:3.11@sha256:bf5fa774f08a9ed2cb301e522b769d43d48124315a4ec50eae3228d03b9dc558                                                                0.0s => => sha256:9b794450f7b6db7c944ba1f4161edb68cb535052fe7db8ac06e613516c4a658d 2.10MB / 2.82MB                                                                                     21.4s => => extracting sha256:9b794450f7b6db7c944ba1f4161edb68cb535052fe7db8ac06e613516c4a658d                                                                                           0.1s => [internal] load build context                                                                                                                                                   1.0s => => transferring context: 115.87MB                                                                                                                                               1.0s => [2/4] RUN apk add --no-cache ca-certificates                                                                                                                                    2.7s => [3/4] RUN wget https://get.helm.sh/helm-v3.5.2-linux-amd64.tar.gz &&     tar xvf helm-v3.5.2-linux-amd64.tar.gz &&     rm helm-v3.5.2-linux-amd64.tar.gz &&     mv linux-amd64  4.7s => [4/4] COPY  ks-apiserver /usr/local/bin/                                                                                                                                        0.2s => exporting to oci image format                                                                                                                                                   5.9s => => exporting layers                                                                                                                                                             4.6s => => exporting manifest sha256:d7eb2a90496678d11ac5c363b7743ffe2b8e23e7071b94556a5e3231f50f5a6e                                                                                   0.0s => => exporting config sha256:8eb6a5187ce958e76c8d37e18221d88f25b48dd7e6672021d0fce21bb071f284                                                                                     0.0s => => sending tarball                                                                                                                                                              1.3sunpacking docker.io/library/ks-apiserver:latest (sha256:d7eb2a90496678d11ac5c363b7743ffe2b8e23e7071b94556a5e3231f50f5a6e)...doneunpacking overlayfs@sha256:d7eb2a90496678d11ac5c363b7743ffe2b8e23e7071b94556a5e3231f50f5a6e (sha256:d7eb2a90496678d11ac5c363b7743ffe2b8e23e7071b94556a5e3231f50f5a6e)...done
复制代码

查看构建好的镜像:

🐳  → nerdctl images
REPOSITORY                                                   TAG       IMAGE ID        CREATED          SIZEalpine                                                       3.11      bf5fa774f08a    3 seconds ago    2.7 MiBks-apiserver                                                 latest    d7eb2a904966    6 minutes ago    57.7 MiB
复制代码

关于 nerdctl 的更多用法,可以参考官方仓库的 README[10]


总结


从行业趋势来看,Docker 已经和 Kubernetes 社区渐行渐远,以 Containerd 为代表的实现了 CRI 接口的容器运行时将会受到 Kubernetes 的青睐。但纯粹使用 Containerd 还是有诸多困扰,比如不方便通过 CLI 来创建管理容器,有了 nerdctl 这个 CLI 工具,就就可以填补 Containerd 易用性的空缺,让你在单机上也能愉快地使用 Containerd。

脚注

[1]ctr: https://github.com/containerd/containerd/tree/master/cmd/ctr

[2]crictl: https://github.com/kubernetes-sigs/cri-tools

[3]nerdctl: https://github.com/containerd/nerdctl

[4]lazy-pulling: https://github.com/containerd/nerdctl/blob/master/docs/stargz.md

[5]imgcrypt: https://github.com/containerd/imgcrypt

[6]Containerd 使用 Stargz Snapshotter 延迟拉取镜像: https://fuckcloudnative.io/posts/startup-containers-in-lightning-speed-with-lazy-image-distribution-on-containerd/

[7]可能需要几个月甚至几年的时间: https://github.com/moby/moby/pull/41002

[8]nerdctl 的 release: https://github.com/containerd/nerdctl/releases

[9]KubeSphere: https://github.com/kubesphere/kubesphere

[10]官方仓库的 README: https://github.com/containerd/nerdctl



头图:Unsplash

作者:米开朗基杨

原文:https://mp.weixin.qq.com/s/Bjn0s5qRh2H9I__mAYh4jg

原文:终于可以像使用 Docker 一样丝滑地使用 Containerd 了!

来源:KubeSphere 云原生 - 微信公众号 [ID:gh_f5606464ef2f]

转载:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2021 年 4 月 21 日 16:063226

评论 1 条评论

发布
用户头像
🐳 →
这个是什么
2021 年 04 月 25 日 10:01
回复
没有更多了
发现更多内容

ARTS-WEEK6

一周思进

ARTS 打卡计划

简述CAP理论

lei Shi

Go:Stringer命令,通过代码生成提高效率

陈思敏捷

go golang stringer

智慧4S店解决方案发布,看英特尔如何引领汽车销售行业变革

最新动态

昆明市成立两大“高端”中心,区块链赋能生物医药和高原特色农业

CECBC区块链专委会

进程、线程基础知识全家桶,30 张图一套带走

小林coding

Linux 操作系统 计算机基础 进程 进程线程区别

负载均衡方式

羽球

负载均衡

redis系列之——高可用(主从、哨兵、集群)

诸葛小猿

redis redis集群 redis哨兵 redis主从

每周学习总结 - 架构师培训 5 期

Damon

数据驱动 vs 关键字驱动:对UI自动化测试框架搭建的探索

Winfield

DevOps 敏捷 自动化测试

抽象工厂模式

Leetao

Python 面试 设计模式

时间去哪了?

escray

ARTS打卡 第7周

引花眠

ARTS 打卡计划

Cache解决算法 Charles断点调试breakpoint John 易筋 ARTS 打卡 Week 08

John(易筋)

ARTS 打卡计划

MySQL实战45讲总结

`

MySQL

ARTS打卡 - Week 07

teoking

程序的机器级表示-程序的编码

引花眠

计算机基础

Mysql插入百万条数据

Java小咖秀

MySQL 运维 数据

看动画学算法之:排序-插入排序

程序那些事

Java 数据结构 算法 插入排序

ARTS打卡-06

Geek_yansheng25

SpringBoot 入门:03 - 统一请求返回

封不羁

Java spring springboot

设计模式(1)—什么是设计模式?设计模式的六大原则是什么?

爱嘤嘤嘤斯坦

Java 程序员 编程语言 设计模式 23种设计模式

低代码与无代码

lidaobing

低代码 无代码开发

观智能化浪潮如何改变产业链创新

CECBC区块链专委会

一致性hash算法及标准差验证

Damon

【计算机网络】如何实现可靠数据传输?

烫烫烫个喵啊

编程核心能力之抽象

顿晓

抽象 编程日课

极客时间 - 架构师培训 - 6 期作业

Damon

【计算机网络】为什么要三次握手四次挥手?

烫烫烫个喵啊

TCP 计算机网络

ARTS WEEK5

紫枫

ARTS 打卡计划

分布式系统设计理念这么难学?

架构师修行之路

架构 分布式

终于可以像使用 Docker 一样丝滑地使用 Containerd 了!-InfoQ