1. 介绍
-
Containerd是什么?在
Containerd官网我们可以看到一个很简单明白的解析,一个工业级的容器运行时,着重于简单性,健壮性和可移植性;通俗点来说:如果你需要开发一个容器编排工具或者要简单地运行一个容器服务,有我就足够了;容器运行时: 是一个允许进程在上面运行的一个独立且隔离的虚拟环境 -
Containerd是如何诞生的?Containerd是脱胎于Docker这个软件的,它的诞生也是由于Docker公司的商业模式一直处于摇摆。起初Docker的出现直接吊打了其他容器技术一家独大,连Google也幸免不了,于是Google想着联合一起退出一个容器运行时作为Docker的底层依赖,但Docker公司并不愿意合作。在此之后,Docker为了进一步扩大影响力将libcontainer捐赠给了(OCI,Open Container Intiative)。以至于后面
Google为了与之抗衡联合了几位行业巨头成立(CNCF,Cloud Native Computing Fundation)想着在底层玩不过就在编排层来抢占市场,后面就上演了前几年的Docker Swarm和Kubernetes之争,结局大家也知道Docker Swarm全面败北。Docker公司并不甘心只当一个底层的容器运行时,于是花了大力气把自己的核心(Contaienrd)依赖剥离出来捐给了CNCF,只为了标榜自己是一个PaaS平台,这波骚操作让一众巨头们都看不懂。 当初让你一起玩你不玩,现在还捐出来了。Kubernetes为了表示自己的中立性,故而直接搞了容器运行时标准化(CRI, Container Runtime Interface),后面为了继续突出Docker的重要性继而搞了各种shim来转换接口。其实研究过Containerd的同学们都知道,Containerd完全是可以独立运行容器的况且Kubernetes搞了CNI来应对容器的复杂网络需求。这样做只是为了等待Containerd羽翼丰满之时。大家也知道
Kubernetes自v1.20后弃用Docker,总而言之Docker这个技术是成功的且开创了一个时代。
2. Containerd 的架构
先来一张常见的架构图:
可以看到Containerd是一个C/S模式的,由containerd client通过containerd提供的GRPC接口进行操作。
Containerd是有不同总类的Plugin组成的如上图看到,Services层即Services Plugin类型,以此类推MetaData Plugin,Content Plugin, Snapshotter Plugin,Runtime Plugin。总之每一个核心模块就是会有一个或多个类型的Plugin组成,如果想知道更多containerd的源码分析可以留意后续推出的文章.
3. Containerd 的安装
大家都比较清楚golang的程序特性,安装起来还是及其方便的。
-
下载安装
cd /usr/local/src wget https://github.com/containerd/containerd/releases/download/v1.4.4/containerd-1.4.4-linux-amd64.tar.gz tar xvf containerd-1.4.4-linux-amd64.tar.gz cd containerd-1.4.4 copy -av bin/* /usr/local/bin/ -
生成配置文件,配置文件可能看起来比较复杂,但暂时先不太关注,其实都是在配置plugin的参数,这些参数更多的需要跟着源码一起解析;
mkdir -p /etc/container containerd config default > /etc/containerd/config.toml -
配置一个镜像加速地址,找到"docker.io" 把endpoint换一下
cat config.toml ... [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://dockerhub.mirrors.nwafu.edu.cn"] ... -
在
config.toml文件中,有两个不同的存储路径,一个用来保存持久化数据,一个用来保存运行时状态。后面推出的文章聊到snapshotter,content等源码内容时再详细介绍。root = "/var/lib/containerd" state = "/run/containerd" -
oom_score, 这个是linux 在内存不足的时候对分数高得分的进程发起kill信号,如果作为生产的容器节点,我们需要保证
contaienrd不会被杀死;oom 取值范围-1000到1000oom_score = -999 -
启动
containerd, 输入containerd即可-> containerd-> ctr version Client: Version: v1.4.1 Revision: c623d1b36f09f8ef6536a057bd658b3aa8632828 Go version: go1.13.15 Server: Version: v1.4.1 Revision: c623d1b36f09f8ef6536a057bd658b3aa8632828 UUID: 2539c5fb-cf92-4dd5-8d77-2f1c39e6959d
4. ctr 的使用
-
先看看
ctr命令总预览,一些比较不好理解的,如content,snaphoster,shim等子模块,我们放到后面源码分析的文章中时来说说,这样会更好理解;-> ctr -h COMMANDS: plugins, plugin provides information about containerd plugins version print the client and server versions containers, c, container manage containers content manage content events, event display containerd events images, image, i manage images leases manage leases namespaces, namespace, ns manage namespaces pprof provide golang pprof outputs for containerd run run a container snapshots, snapshot manage snapshots tasks, t, task manage tasks install install a new package oci OCI tools shim interact with a shim directly help, h Shows a list of commands or help for one command GLOBAL OPTIONS: --debug enable debug output in logs --address value, -a value address for containerd's GRPC server (default: "/run/containerd/containerd.sock") [$CONTAINERD_ADDRESS] --timeout value total timeout for ctr commands (default: 0s) --connect-timeout value timeout for connecting to containerd (default: 0s) --namespace value, -n value namespace to use with commands (default: "default") [$CONTAINERD_NAMESPACE] --help, -h show help --version, -v print the version从命令的子模块看来,
containerd还是偏向于更专注容器的本身,比如网络模块就没见到身影,所以它更适合开发者或者说程序去使用它,而docker明显对人会更加的友好易用。 -
plugins, 查看插件的支持,下面可以看到我的系统不支持btrfs、devmapper和zfs这三种snapshotter。> ctr plugins ls TYPE ID PLATFORMS STATUS io.containerd.content.v1 content - ok io.containerd.snapshotter.v1 aufs linux/amd64 ok io.containerd.snapshotter.v1 btrfs linux/amd64 error io.containerd.snapshotter.v1 devmapper linux/amd64 error io.containerd.snapshotter.v1 native linux/amd64 ok io.containerd.snapshotter.v1 overlayfs linux/amd64 ok io.containerd.snapshotter.v1 zfs linux/amd64 error io.containerd.metadata.v1 bolt - ok io.containerd.differ.v1 walking linux/amd64 ok io.containerd.gc.v1 scheduler - ok io.containerd.service.v1 introspection-service - ok io.containerd.service.v1 containers-service - ok io.containerd.service.v1 content-service - ok io.containerd.service.v1 diff-service - ok io.containerd.service.v1 images-service - ok io.containerd.service.v1 leases-service - ok io.containerd.service.v1 namespaces-service - ok io.containerd.service.v1 snapshots-service - ok io.containerd.runtime.v1 linux linux/amd64 ok io.containerd.runtime.v2 task linux/amd64 ok io.containerd.monitor.v1 cgroups linux/amd64 ok io.containerd.service.v1 tasks-service - ok io.containerd.internal.v1 restart - ok io.containerd.grpc.v1 containers - ok io.containerd.grpc.v1 content - ok io.containerd.grpc.v1 diff - ok io.containerd.grpc.v1 events - ok io.containerd.grpc.v1 healthcheck - ok io.containerd.grpc.v1 images - ok io.containerd.grpc.v1 leases - ok io.containerd.grpc.v1 namespaces - ok io.containerd.internal.v1 opt - ok io.containerd.grpc.v1 snapshots - ok io.containerd.grpc.v1 tasks - ok io.containerd.grpc.v1 version - ok io.containerd.grpc.v1 cri linux/amd64 ok
4.1 images
-> ctr i -h
NAME:
ctr images - manage images
USAGE:
ctr images command [command options] [arguments...]
COMMANDS:
check check that an image has all content available locally
export export images
import import images
list, ls list images known to containerd
mount mount an image to a target path
unmount unmount the image from the target
pull pull an image from a remote
push push an image to a remote
remove, rm remove one or more images by reference
tag tag an image
label set and clear labels for an image
OPTIONS:
--help, -h show help
- 可以看到很多和
docker类似的命令, 下面先下载镜像
-> ctr i pull docker.io/library/nginx:alpine
- 将镜像挂载到目录上
-> ctr i mount docker.io/library/nginx:alpine /mnt
-> tree /mnt
/mnt
├── bin
├── dev
├── docker-entrypoint.d
├── docker-entrypoint.sh
├── etc
├── home
├── lib
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin
├── srv
├── sys
├── tmp
├── usr
└── var
- 将镜像从目录上卸载
-> ctr i unmounnt /mnt
4.2 containers
- 创建容器
-> ctr c create docker.io/library/nginx:alpine nginx
-
创建容器还有比较多的参数,比如
--mount指定挂载目录,--privileged特权容器,--with-ns指定一个存在的linux namespace并且加入他等,更多可以-h查看。 -
list容器, 后面有些模块的该参数都是类似的效果就不再展示了
-> ctr c ls
checkpoint和restore参数其实都是通过runc去提供的一种容器快照功能,保存容器当前状态或恢复当前状态。
4.3 tasks
- 前面create container 从源码上看到其实只是保存了需要配置的信息并未有任何启动的动作,直至你使用
tasks模块,它类似在管理容器进程的模块。
-> ctr task start -d nginx
-> ctr task ls
TASK PID STATUS
nginx 26046 RUNNING
- 它也可以直接创建并运行容器,因为
run子模块其实就是先container create, 然后调用tasks run进行启动
-> ctr run -d docker.io/library/nginx:alpine nginx
- 进入容器,
--exec-id随便指定一个唯一id即可,其实exec子模块的功能,大部分是有runtime实现的,其实就是runc。
-> ctr task exec --exec-id 0 -t nginx sh
- 暂停容器,这里的暂停容器是由
runc提供的,其实就是通过cgroup的freezer(/sys/fs/cgroup/freezer)让进程冻结,不让其使用计算资源,进程状态会变成不可中断。
-> ctr task pause nginx
- 恢复容器,也是一样 只是处于不同状态的进程,
cgroup的freezer会让进程解冻
-> ctr task resume nginx
想了解更多可以参考,我之前写的runc的源码分析文章:了解一下
tasks模块并没有stop功能,我们只能把容器kill掉(说到这我也好奇docker是怎么stop容器的,后面寻找到答案再补上链接)
-> ctr task kill nginx
- 使用情况
-> ctr task metrics nginx
ID TIMESTAMP
nginx 2021-03-22 14:19:25.763395731 +0000 UTC
METRIC VALUE
memory.usage_in_bytes 3293184
memory.limit_in_bytes 9223372036854771712
memory.stat.cache 0
cpuacct.usage 173628987
cpuacct.usage_percpu [96660488 76968499]
pids.current 3
pids.limit 0
- 查看容器中的所有进程PID
-> ctr t ps nginx
PID INFO
26046 -
26087 -
26088 -
4.4 其他子模块
-
有些子模块在本篇文章不在详解使用方式及作用,留待后面的文章进行源码分析时的入口;
content内容寻址,可以修改镜像内容snapshots镜像层的操作
-
events可以监听到containerd内的所有事件,这是在内部实现的一套事件机制,需要事件机制的程序可以借鉴下。
-> ctr events
-
pprof这个熟悉go语言的都应该知道这是个性能监控, 需要在config.toml下的设置debug的socket路径,然后重启服务后就可以使用pprof的命令 -
oci这个模块主要是展示OCI的规范参数,就是文中开头提到过的OCI,这些规范都会在代码层面有体现;
-> ctr oci spec
shim这个模块不是标准的使用containerd client进行连接,而是通过ttrpc这中低内存的grpc客户端直接拼接出一个容器的连接地址进行连接。它的功能其实在tasks模块下都有,因为它最终远程调用也是tasks模块的service plugin。
最后
经历了6小时终于肝完了,在坚持坚持,还有很多坑要填。
后面陆续还有几篇关于containerd的源码分析文章,加油吧~~
肝完就可以进军kubernetes,底层要扎实推进,上层建筑才稳当;