一、Containerd介绍
早在2016年3月,Docker 1.11的Docker Engine里就包含了containerd,而现在则是把containerd从Docker Engine里彻底剥离出来,作为一个独立的开源项目独立发展,目标是提供一个更加开放、稳定的容器运行基础设施。和原先包含在Docker Engine里containerd相比,独立的containerd将具有更多的功能,可以涵盖整个容器运行时管理的所有需求。
containerd并不是直接面向最终用户的,而是主要用于集成到更上层的系统里,比如Swarm, Kubernetes, Mesos等容器编排系统。
containerd以Daemon的形式运行在系统上,通过暴露底层的gRPC API,上层系统可以通过这些API管理机器上的容器。
每个containerd只负责一台机器,Pull镜像,对容器的操作(启动、停止等),网络,存储都是由containerd完成。具体运行容器由runC负责,实际上只要是符合OCI规范的容器都可以支持。
对于容器编排服务来说,运行时只需要使用containerd+runC,更加轻量,容易管理。
独立之后containerd的特性演进可以和Docker Engine分开,专注容器运行时管理,可以更稳定。
1、Containerd前世今生
2013年docker公司在推出docker产品后,由于其对全球技术产生了一定的影响力,Google公司明显感觉到自己公司内部所使用的Brog系统江湖地位受到的威胁,希望Docker公司能够与自己联合打造一款开源的容器运行时作为Docker核心依赖,但Docker公司拒绝了;接着Google公司联合RedHat、IBM等公司说服Docker公司把其容器核心技术libcontainer捐给中立社区(OCI,Open Container Intiative),并更名为runC。
为了进一步遏制Docker在未来技术市场影响力,避免在容器市场上Docker一家独大,Google公司带领导RedHat、IBM等成立了CNCF(Cloud Native Computing Fundation)基金会,即云原生计算基金会。CNCF的目标很明确,既然在容器应用领域无法与Docker相抗衡,那就做Google更有经验的技术市场------大规模容器编排应用场景,Google公司把自己内部使用的Brog系统开源------Kubernetes,也就是我们今天所说的云原生技术生态。
2016年Docker公司推出了Docker Swarm,意在一统Docker生态,让Docker既可以实现容器应用管理,也可以实现大规模容器编排,经过近1年左右时间的市场验证后,发现在容器编排方面无法独立抗衡kubernetes,所以Docker公司于2017年正式宣布原生支持Kubernetes,至此,Docker在大规模容器编排应用市场败下阵来,但是Docker依然不甘心失败,把Docker核心依赖Containerd捐给了CNCF,依此说明Docker依旧是一个PaaS平台。
2020年CNCF基金会宣布Kubernetes 1.20版本将不再仅支持Docker容器管理工具,此事的起因主要也与Docker捐给CNCF基金会的Containerd有关,早期为了实现Kubernetes能够使用Docker实现容器管理,专门在Kubernetes组件中集成一个shim(垫片)技术,用来将Kubernetes容器运行时接口(CRI,Container Runntime Interface)调用翻译成Docker的API,这样就可以很好地使用Docker了,但是随着Kubernetes在全球技术市场的广泛应用,有更多的容器管理工具的出现,它们都想能够借助于Kubernetes被用户所使用,所以就提出标准化容器运行时接口,只要适配了这个接口就可以集成到Kubernetes生态当中,所以Kubernetes取消了对shim的维护,并且由于Containerd技术的成功,可以实现无缝对接Kubernetes,所以接下来Kubernetes容器运行时的主角是Containerd。
2、Containerd内部架构
1、架构图
Containerd的定位是专注于容器生命周期的管理,相比于Docker来说Containerd的职能定位更加清晰,从架构上也更加精简。Containerd同样采用Daemon(守护进程)方式运行于操作系统中,通过unix domain docket对外暴露gRPC API。Containerd负责镜像的管理,但不包含镜像构建,除此之外还负责存储及网络方面的管理以及容器的创建,Containerd具体的运行仍然是底层的容器运行时来负责,例如runc。runc默认作为Containerd底层的容器运行时。下图是一个内部架构图。
Containerd 采用标准的 C/S 架构
- 服务端通过 GRPC 协议提供稳定的 API
- 客户端通过调用服务端的 API 进行高级的操作
为了实现解耦,Containerd 将不同的职责划分给不同的组件,每个组件就相当于一个子系统(subsystem)。连接不同子系统的组件被称为模块。
Containerd 两大子系统为:
- Bundle : 在 Containerd 中,Bundle 包含了配置、元数据和根文件系统数据,你可以理解为容器的文件系统。而 Bundle 子系统允许用户从镜像中提取和打包 Bundles。
- Runtime : Runtime 子系统用来执行 Bundles,比如创建容器。 其中,每一个子系统的行为都由一个或多个模块协作完成(架构图中的 Core 部分)。每一种类型的模块都以插件的形式集成到 Containerd 中,而且插件之间是相互依赖的。 例如,上图中的每一个长虚线的方框都表示一种类型的插件,包括 Service Plugin、Metadata Plugin、GC Plugin、Runtime Plugin 等,其中 Service Plugin 又会依赖 Metadata Plugin、GC Plugin 和 Runtime Plugin。每一个小方框都表示一个细分的插件,例如 Metadata Plugin 依赖 Containers Plugin、Content Plugin 等。
那么Containerd在监控或者说是可观测性方面,是通过metrics接口直接提供各组件的性能指标,可被Promethues直接采集,符合其数据格式。
Containerd还支持对namespace的直接操纵,以不同namespace划分容器,不同的namespace中可以存在相同的容器名称。如果你是安装Docker CE那么默认为安装Containerd的,困为Docker是依赖Containerd的。那么此时会创建一个默认的namespace叫moby。这个名称是不是很熟悉,moby就是我们之前的故事中的由开源的docker更名后的项目名称。那么此时所创建的容器都属于这个moby的namespace中。
架构缩略图
Containerd 被分为三个大块:Storage、Metadata 和 Runtime
2、CRI支持
Containerd作为CNCF孵化项目,已经从CNCF宣布毕业。CNCF的存在主要目的是打造一个以kubernetes为中心的云原生生态,在kubernetes成为业界的事实标准后,为了使得更具扩展与灵活性,也为了促进生态建设,使得kubernetes更加的易于集成,就推出了一系列规范,如CRI(容器运行时接口)、CSI(容器存储接口)、CNI(容器网络接口)。那么要想与kubernetes对接,那么就必须遵循这些规范来实现这些接口。Docker本身是不支持CRI的那么前期的kubernetes一直在kubelet中增加的一个docker-shim的东西,用于来将CRI调用翻译成适用于dockerd的API调用,也就是说kubernetes一直用docker-shim来适配docker。那么Containerd开源进入CNCF后,就实现的CRI,可以被docker直接调用。减少了调用链的复杂度。
我们先来看一下kubelet在使用不同的容器管理器时,对底层oci运行时的调用链,比如对runc的调用,如下所示。
如上图所示,在使用docker管理容器时,调用链最长,这即降低了性能也增加了问题排查的复杂度。
而在使用containerd时,对于cri的实现,是基于插件化的,使用cri-containerd以插件方式集成在containerd内部,减少了调用链的长度。
那么这里你可能会问还有一cri-o是什么,好像更轻量。cri-o是轻量级的容器管理器,专门为kubernetes而设计的,站在cri-o的角度来说,用户如果使用kubernetes那么就不需要单独去操作主机中的容器,一切都交由kubernetes,那么对于具体容器的管理,就由cri-o来负责,因此cri-o没有为用户留有太多的交互式功能,而是以API形式接受kubernetes的调用。
3、常用插件
Content Plugin : 提供对镜像中可寻址内容的访问,所有不可变的内容都被存储在这里。
Snapshot Plugin : 用来管理容器镜像的文件系统快照。镜像中的每一个 layer 都会被解压成文件系统快照,类似于 Docker 中的 graphdriver。
Metrics : 暴露各个组件的监控指标。
二、安装Containerd
操作系统环境为centos7.9
1、YUM方式安装
1、获取YUM源
获取阿里云YUM源
# wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
查看YUM源中Containerd软件
# yum list | grep containerd
containerd.io.x86_64 1.6.15-3.1.el7 @docker-ce-stable
2、使用yum命令安装
安装Containerd.io软件,即可安装Containerd
# yum install docker-ce-20.10.* docker-ce-cli-20.10.* containerd -y
# yum -y install containerd # 或者单独安装
3、验证安装及启动服务
使用rpm -qa命令查看是否安装
# rpm -qa | grep containerd
containerd.io-1.6.15-3.1.el7.x86_64
设置containerd服务启动及开机自启动
# systemctl enable containerd
# systemctl start containerd
查看containerd服务启动状态
# systemctl status containerd
● containerd.service - containerd container runtime
Loaded: loaded (/usr/lib/systemd/system/containerd.service; disabled; vendor preset: disabled)
Active: active (running) since Sun 2023-01-29 16:54:02 CST; 1 weeks 0 days ago # 此行第二列及第三列表示其正在运行状态
Docs: https://containerd.io
Main PID: 924 (containerd)
Tasks: 38
Memory: 94.5M
CGroup: /system.slice/containerd.service
├─ 924 /usr/bin/containerd
├─23168 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 252adcb68b692999c3ae3d4bee0f4d079c7d054e2228ff5add07172dbaab607d -address /run/containerd/containerd.sock
└─23192 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 1edad37e41585df010068ccb4216c7b543aa2b665e6d18a57b6f452b63536395 -address /run/containerd/containerd.sock
......
4、验证可用性
安装Containerd时ctr命令亦可使用,ctr命令主要用于管理容器及容器镜像等。
使用ctr命令查看Containerd客户端及服务端相关信息。
# ctr version
Client:
Version: 1.6.15
Revision: 5b842e528e99d4d4c1686467debf2bd4b88ecd86
Go version: go1.18.9
Server:
Version: 1.6.15
Revision: 5b842e528e99d4d4c1686467debf2bd4b88ecd86
UUID: 4c7ced0b-a969-4652-a836-4c8bcbc42554
2、二进制方式安装
1、获取安装包
Containerd的Github地址:https://github.com/containerd/containerd
在GitHub上发布了两个包containerd-1.6.16-linux-amd64.tar.gz这个包只包含Containerd核心组件,不包含Runc以及cri、cni等,需要提前安装。如果是单独安装的话,建议使用第二个包cri-containerd-cni-1.6.16-linux-amd64.tar.gz,包含runc和k8s里的所需要的相关文件,k8s集群里需要用到此包。虽然包含runC,但是依赖系统中的seccomp(安全计算模式,是一种限制容器调用系统资源的模式。)
下载完成之后呢,上传至主机中,然后将压缩包内文件解压至系统各目录中,命令如下
# wget https://mirror.ghproxy.com/https://github.com/containerd/containerd/releases/download/v1.6.16/cri-containerd-cni-1.6.16-linux-amd64.tar.gz
# tar Cxf / cri-containerd-cni-1.6.16-linux-amd64.tar.gz
2、安装并测试可用性
1、升级软件依赖
系统默认安装的 libseccomp 是 2.3.1 版本,该版本已经不能满足我们这里的版本的 Containerd 了(从 1.5.7 版本开始就不兼容了),需要 2.4 以上的版本,所以我们需要重新安装一个高版本的 libseccomp。
方法一:单独升级libseccomp版本
注意:因为chrony 依赖 libseccomp,卸载 libseccomp 时候,需要先卸载 chrony 在去卸载 libseccomp,然后再去安装chrony。
# rpm -e libseccomp-2.3.1-4.el7.x86_64 --nodeps # centos7 默认版本
# wget http://rpmfind.net/linux/centos/8-stream/BaseOS/x86_64/os/Packages/libseccomp-2.5.1-1.el8.x86_64.rpm
# rpm -e chrony-3.4-1.el7.x86_64 # 卸载 chrony
# rpm -ivh libseccomp-2.5.1-1.el8.x86_64.rpm
# yum install chrony -y
# systemctl enable chronyd && systemctl start chronyd
方法二:安装runC(推荐)
由于二进制包中提供的runC默认需要系统中安装seccomp支持,需要单独安装,且不同版本runC对seccomp版本要求一致,所以建议单独下载runC 二进制包进行安装,里面包含了seccomp模块支持。
# wget https://mirror.ghproxy.com/https://github.com/opencontainers/runc/releases/download/v1.1.4/runc.amd64
# mv runc.amd64 /usr/sbin/runc
# chmod +x /usr/sbin/runc
# runc -v
runc version 1.1.4
commit: v1.1.4-0-g5fd4c4d1
spec: 1.0.2-dev
go: go1.17.10
libseccomp: 2.5.4
2、生成默认配置文件
生成containerd默认配置文件,配置文件默认存放位置在/etc/containerd,命令如下
# mkdir /etc/containerd
# containerd config default | tee /etc/containerd/config.toml
执行以下命令启动containerd守护进程
# systemctl enable containerd --now
可以使用ctr这个自带的CLI工具检查一下版本信息
# ctr version
3、配置优化
1、镜像加速及私有仓库
我们在使用docker时通常需要配置一个镜像加速地址,一般是通过/etc/docker/daemon.json来更改,那么在使用Containerd时,怎么更改呢?这里不用担心Containerd也是支持镜像加速的,而且是可以支持对多个仓库分别配置加速地址,这一点比docker要强大。
Containerd的默认配置在/etc/containerd/config.toml中如果你是安装docker-ce时做为依赖安装的的Contaierd那么这个配置只是非常简单的一些值,那么你可以通过以下命令来查看完整的默认配置
containerd config default
从输出中找到如下字段,在registry.mirors处就是镜像加速的配置,现在默认只有一个加速的仓库地址是默认的docker.io,该仓库对应的加速地址在endpoint中配置。
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://registry-1.docker.io"]
然后找到上面字段中所说的registry.mirrors字段,将docker.io的endpoint更改为你的阿里云或者其他平台商提供镜像加速地址。当然你可以增加其他的镜像仓库并为它们配置加速,例如k8s.gcr.io,更改如下所示
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = ""
[plugins."io.containerd.grpc.v1.cri".registry.auths]
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."harbor.example.com".tls]
insecure_skip_verify = true # 跳过证书认证
[plugins."io.containerd.grpc.v1.cri".registry.configs."harbor.example.com".auth]
username = "admin"
password = "Harbor12345"
[plugins."io.containerd.grpc.v1.cri".registry.headers]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://docker.mirrors.ustc.edu.cn","http://hub-mirror.c.163.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
endpoint = ["https://gcr.mirrors.ustc.edu.cn"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint = ["https://gcr.mirrors.ustc.edu.cn/google-containers"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
endpoint = ["https://quay.mirrors.ustc.edu.cn"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.example.com"]
endpoint = ["https://harbor.example.com"]
registry.mirrors."xxx":表示需要配置 mirror 的镜像仓库。例如,registry.mirrors."docker.io" 表示配置 docker.io 的 mirror。
endpoint : 表示提供 mirror 的镜像加速服务地址。
推送容器镜像至Harbor
# ctr images tag docker.io/library/nginx:latest
# ctr images push --platform linux/amd64 --plain-http harbor.example.com/library/nginx:latest
说明:
- 先tag再push
- 因为我们harbor是http协议,不是https协议,所以需要加上
--plain-http
2、配置Containerd所需的内核
# cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
3、配置Containerd所需的模块
此操作是为了解决:使用containerd管理容器生命周期
# cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
加载模块
# modprobe -- overlay
# modprobe -- br_netfilter
4、将Containerd的Cgroup改为Systemd
找到containerd.runtimes.runc.options,添加SystemdCgroup = true(如果已存在直接修改,否则会报错)
# vim /etc/containerd/config.toml
114 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
115 BinaryName = ""
116 CriuImagePath = ""
117 CriuPath = ""
118 CriuWorkPath = ""
119 IoGid = 0
120 IoUid = 0
121 NoNewKeyring = false
122 NoPivotRoot = false
123 Root = ""
124 ShimCgroup = ""
125 SystemdCgroup = true # false 改为 true
5、将sandbox_image的Pause镜像改成符合自己版本的地址
61 sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.6" # 根据实际修改
6、配置crictl客户端连接的运行时位置
# cat > /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
pull-image-on-create: false
EOF
三、Containerd命令
docker使用docker images命令管理镜像
单机containerd使用ctr images命令管理镜像,containerd本身的CLI,images简称i
k8s中containerd使用crictl images命令管理镜像,Kubernetes社区的专用CLI工具
1、ctr 命令
1、Containerd镜像管理命令
获取命令帮助
# ctr --help
NAME:
ctr -
__
_____/ /______
/ ___/ __/ ___/
/ /__/ /_/ /
\___/\__/_/
containerd CLI
USAGE:
ctr [global options] command [command options] [arguments...]
VERSION:
1.6.15
DESCRIPTION:
ctr is an unsupported debug and administrative client for interacting
with the containerd daemon. Because it is unsupported, the commands,
options, and operations are not guaranteed to be backward compatible or
stable from release to release of the containerd project.
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
获取命令帮助
# ctr i
NAME:
ctr images - manage images
USAGE:
ctr images command [command options] [arguments...]
COMMANDS:
check check existing images to ensure all content is 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
delete, del, remove, rm remove one or more images by reference
tag tag an image
label set and clear labels for an image
convert convert an image
OPTIONS:
--help, -h show help
2、查看镜像
# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
3、下载镜像
containerd支持oci标准的镜像,所以可以直接使用docker官方或dockerfile构建的镜像
# ctr i pull --all-platforms docker.io/library/nginx:alpine # --platform 选项指定对应平台的镜像(推荐)
说明:这里ctr命令pull镜像时,不能直接把镜像名字写成nginx:alpine
查看已下载容器镜像
# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
docker.io/library/nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 15.9 MiB linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -
4、镜像挂载
方便查看镜像中包含的内容,把已下载的容器镜像挂载至当前文件系统
# ctr i mount docker.io/library/nginx:alpine /mnt
sha256:a71c46316a83c0ac8c2122376a89b305936df99fa354c265f5ad2c1825e94167
/mnt
# ls /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 unmount /mnt # 卸载
5、镜像导出
把容器镜像导出
# ctr i export --all-platforms nginx.img docker.io/library/nginx:alpine
说明:
--all-platforms,导出所有平台镜像,本版本为1.6版本,1.4版本不需要添加此选项。
查看已导出容器镜像
# ls -lh nginx.img
-rw-r--r-- 1 root root 105M Feb 6 14:51 nginx.img
注意:如果拉取镜像使用的是以下命令,导出时可能会出现错误
# ctr i pull docker.io/library/nginx:alpine
# ctr i export --all-platforms nginx.img docker.io/library/nginx:alpine
ctr: content digest sha256:91a6fa58c8700c7dbf9bf2d64540f1d529caab5e3f1b850c27c0a65782c07c36: not found
6、镜像删除
删除指定容器镜像
# ctr i rm docker.io/library/nginx:alpine
docker.io/library/nginx:alpine
# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
7、镜像导入
导入容器镜像
# ctr i import nginx.img
unpacking docker.io/library/nginx:alpine
(sha256:da9c94bec1da829ebd52431a84502ec471c8e548ffb2cedbf36260fd9bd1d4d3)...done
8、修改镜像tag
把docker.io/library/nginx:alpine 修改为 nginx:alpine
# ctr i tag docker.io/library/nginx:alpine nginx:alpine
nginx:alpine
查看修改后的容器镜像
# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
docker.io/library/nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 15.9 MiB linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -
nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 15.9 MiB linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -
修改后对容器镜像做检查比对
# ctr i check
REF TYPE DIGEST STATUS SIZE UNPACKED
docker.io/library/nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 complete (8/8) 15.9 MiB/15.9 MiB true
nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 complete (8/8) 15.9 MiB/15.9 MiB true
2、Containerd容器管理
1、获取命令帮助
1、获取创建静态容器命令帮助
# ctr container --help
NAME:
ctr containers - manage containers
USAGE:
ctr containers command [command options] [arguments...]
COMMANDS:
create create container
delete, del, remove, rm delete one or more existing containers
info get info about a container
list, ls list containers
label set and clear labels for a container
checkpoint checkpoint a container
restore restore a container from checkpoint
OPTIONS:
--help, -h show help
说明:
使用ctr container create
命令创建容器后,容器并没有处于运行状态,其只是一个静态的容器。这个 container 对象只是包含了运行一个容器所需的资源及配置的数据结构,例如: namespaces、rootfs 和容器的配置都已经初始化成功了,只是用户进程(本案例为nginx)还没有启动。需要使用ctr tasks
命令才能获取一个动态容器。
2、获取动态容器命令帮助
# ctr run --help
NAME:
ctr run - run a container
USAGE:
ctr run [command options] [flags] Image|RootFS ID [COMMAND] [ARG...]
OPTIONS:
--rm remove the container after running
--null-io send all IO to /dev/null
--log-uri value log uri
--detach, -d detach from the task after it has started execution
--fifo-dir value directory used for storing IO FIFOs
--cgroup value cgroup path (To disable use of cgroup, set to "" explicitly)
--platform value run image for specific platform
--cni enable cni networking for the container
--runc-binary value specify runc-compatible binary
--runc-root value specify runc-compatible root
--runc-systemd-cgroup start runc with systemd cgroup manager
--uidmap container-uid:host-uid:length run inside a user namespace with the specified UID mapping range; specified with the format container-uid:host-uid:length
--gidmap container-gid:host-gid:length run inside a user namespace with the specified GID mapping range; specified with the format container-gid:host-gid:length
--remap-labels provide the user namespace ID remapping to the snapshotter via label options; requires snapshotter support
--cpus value set the CFS cpu quota (default: 0)
--cpu-shares value set the cpu shares (default: 1024)
--snapshotter value snapshotter name. Empty value stands for the default value. [$CONTAINERD_SNAPSHOTTER]
--snapshotter-label value labels added to the new snapshot for this container.
--config value, -c value path to the runtime-specific spec config file
--cwd value specify the working directory of the process
--env value specify additional container environment variables (e.g. FOO=bar)
--env-file value specify additional container environment variables in a file(e.g. FOO=bar, one per line)
--label value specify additional labels (e.g. foo=bar)
--annotation value specify additional OCI annotations (e.g. foo=bar)
--mount value specify additional container mount (e.g. type=bind,src=/tmp,dst=/host,options=rbind:ro)
--net-host enable host networking for the container
--privileged run privileged container
--read-only set the containers filesystem as readonly
--runtime value runtime name (default: "io.containerd.runc.v2")
--runtime-config-path value optional runtime config path
--tty, -t allocate a TTY for the container
--with-ns value specify existing Linux namespaces to join at container runtime (format '<nstype>:<path>')
--pid-file value file path to write the task's pid
--gpus value add gpus to the container
--allow-new-privs turn off OCI spec's NoNewPrivileges feature flag
--memory-limit value memory limit (in bytes) for the container (default: 0)
--device value file path to a device to add to the container; or a path to a directory tree of devices to add to the container
--cap-add value add Linux capabilities (Set capabilities with 'CAP_' prefix)
--cap-drop value drop Linux capabilities (Set capabilities with 'CAP_' prefix)
--seccomp enable the default seccomp profile
--seccomp-profile value file path to custom seccomp profile. seccomp must be set to true, before using seccomp-profile
--apparmor-default-profile value enable AppArmor with the default profile with the specified name, e.g. "cri-containerd.apparmor.d"
--apparmor-profile value enable AppArmor with an existing custom profile
--rdt-class value name of the RDT class to associate the container with. Specifies a Class of Service (CLOS) for cache and memory bandwidth management.
--rootfs use custom rootfs that is not managed by containerd snapshotter
--no-pivot disable use of pivot-root (linux only)
--cpu-quota value Limit CPU CFS quota (default: -1)
--cpu-period value Limit CPU CFS period (default: 0)
--rootfs-propagation value set the propagation of the container rootfs
说明:
使用ctr run
命令可以创建一个静态容器并使其运行。一步到位运行容器。
2、查看容器
container表示静态容器,可用c缩写代表container
# ctr container ls
CONTAINER IMAGE RUNTIME
3、查看任务
task表示容器里跑的进程, 可用t缩写代表task
# ctr task ls
TASK PID STATUS
4、创建静态容器
# ctr c create docker.io/library/nginx:alpine nginx1
# ctr c ls
CONTAINER IMAGE RUNTIME
nginx1 docker.io/library/nginx:alpine io.containerd.runc.v2
查看容器详细信息
# ctr c info nginx1
5、静态容器启动为动态容器
启动task,即表时在容器中运行了进程,即为动态容器。
# ctr task start -d nginx1
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
说明:
-d表示daemon或者后台的意思,否则会卡住终端
查看容器所在宿主机进程,是以宿主机进程的方式存在的
# ctr task ls
TASK PID STATUS
nginx1 61641 RUNNING
查看容器的进程(都是物理机的进程)
# ctr task ps nginx1
PID INFO
61641 -
61676 -
61677 -
物理机查看到相应的进程
# ps -ef | grep 61641
root 61641 61620 0 15:39 ? 00:00:00 nginx: master process nginx -g daemon off;
101 61676 61641 0 15:39 ? 00:00:00 nginx: worker process
101 61677 61641 0 15:39 ? 00:00:00 nginx: worker process
root 61856 58177 0 15:43 pts/0 00:00:00 grep --color=auto 61641
6、进入容器操作
# ctr task exec --exec-id 1 nginx1 /bin/sh
ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
curl 127.0.0.1 # 访问本地提供的web服务
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
100 615 100 615 0 0 1026k 0 --:--:-- --:--:-- --:--:-- 600k
说明:
为exec进程设定一个id,可以随意输入,只要保证唯一即可,也可使用$RANDOM变量。
7、直接运行一个动态容器
# ctr run -d --net-host docker.io/library/nginx:alpine nginx2
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
说明:
- -d 代表dameon,后台运行
- --net-host 代表容器的IP就是宿主机的IP(相当于docker里的host类型网络)
查看已运行容器
# ctr c ls
CONTAINER IMAGE RUNTIME
nginx2 docker.io/library/nginx:alpine io.containerd.runc.v2
查看已运行容器中运行的进程,既tasks
# ctr tasks ls
TASK PID STATUS
nginx2 62836 RUNNING
进入容器
# ctr task exec --exec-id 1 -t nginx2 /bin/sh
/ # ifconfig
br-be72c0dee4b1 Link encap:Ethernet HWaddr 02:42:6A:DF:E5:79
inet addr:172.19.0.1 Bcast:172.19.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:9107 errors:0 dropped:0 overruns:0 frame:0
TX packets:14856 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:4171681 (3.9 MiB) TX bytes:1183127 (1.1 MiB)
docker0 Link encap:Ethernet HWaddr 02:42:F6:FE:F3:D9
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:69518 errors:0 dropped:0 overruns:0 frame:0
TX packets:75565 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3142249 (2.9 MiB) TX bytes:738654677 (704.4 MiB)
eth0 Link encap:Ethernet HWaddr 00:16:3E:0D:3E:45
inet addr:192.168.0.174 Bcast:192.168.0.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:3171915 errors:0 dropped:0 overruns:0 frame:0
TX packets:2795891 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1964872517 (1.8 GiB) TX bytes:2815022583 (2.6 GiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:17966 errors:0 dropped:0 overruns:0 frame:0
TX packets:17966 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:61339427 (58.4 MiB) TX bytes:61339427 (58.4 MiB)
vethf9e4a99 Link encap:Ethernet HWaddr CA:7A:39:59:01:05
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:9107 errors:0 dropped:0 overruns:0 frame:0
TX packets:14856 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:4299179 (4.0 MiB) TX bytes:1183127 (1.1 MiB)
/ # echo "nginx2" > /usr/share/nginx/html/index.html # 为容器中运行的网站添加网站文件
/ # exit
# curl 127.0.0.1 # 在宿主机上访问网站
nginx2
8、暂停容器
查看容器状态
# ctr tasks ls
TASK PID STATUS
nginx2 62836 RUNNING
暂停容器
# ctr tasks pause nginx2
再次查看容器状态,看到其状态为PAUSED,表示停止
# ctr tasks ls
TASK PID STATUS
nginx2 62836 PAUSED
9、恢复容器
使用resume命令恢复容器
# ctr tasks resume nginx2
# ctr tasks ls
TASK PID STATUS
nginx2 62836 RUNNING
10、停止容器
# ctr tasks --help
NAME:
ctr tasks - manage tasks
USAGE:
ctr tasks command [command options] [arguments...]
COMMANDS:
attach attach to the IO of a running container
checkpoint checkpoint a container
delete, del, remove, rm delete one or more tasks
exec execute additional processes in an existing container
list, ls list tasks
kill signal a container (default: SIGTERM)
pause pause an existing container
ps list processes for container
resume resume a paused container
start start a container that has been created
metrics, metric get a single data point of metrics for a task with the built-in Linux runtime
OPTIONS:
--help, -h show help
使用kill命令停止容器中运行的进程,既为停止容器
# ctr tasks kill nginx2
查看容器停止后状态,STATUS为STOPPED
# ctr tasks ls
TASK PID STATUS
nginx1 61641 RUNNING
nginx2 62836 STOPPED
11、删除容器
必须先停止tasks或先删除task,再删除容器
# ctr tasks delete nginx2
查看静态容器,确认其还存在于系统中
# ctr c ls
CONTAINER IMAGE RUNTIME
nginx2 docker.io/library/nginx:alpine io.containerd.runc.v2
删除容器
# ctr c delete nginx2
12、监控容器资源消耗情况
# ctr task metrics nginx1
ID TIMESTAMP
nginx1 2023-02-06 08:51:45.230533687 +0000 UTC
METRIC VALUE
memory.usage_in_bytes 3497984
memory.limit_in_bytes 9223372036854771712
memory.stat.cache 0
cpuacct.usage 45130196
cpuacct.usage_percpu [22352586 22777610]
pids.current 3
pids.limit 0
2、nerdctl
Containerd由于面向的是上层的编排系统,而在与用户的直接交互上并不是很友好,其自带的ctr为一个CLI工具,类似使用docker命令,但是该ctr工具并不友好,单单是创建一个容器都异常复杂,那么除此之外还有一个crictl,这个工具其实也并不友好,这就造成人们在切换到Containerd后,在进行单机调试时,可能一时间无法适应,找不到合适的CLI工具来与Containerd进行交互,那么为了解决这个问题,官方又推出了一个新的CLI,该工具比以往都要强大,它的使用方式与docker几乎无差别,甚至还扩展了一些Docker不具备的功能,这个工具就是nerdctl。你甚至可以将它取个别名alias nerdctl=’docker’就直接把它当docker来使用。
nerdctl在github上的地址:https://github.com/containerd/nerdctl
你可以从上面找到最新的release版本,官方提供了两个版本,一个是只包含nerdctl这个工具,而另一个full(完整版)版本,包含了containerd、runc、cni、BuildKit等。如果在你的环境中已经有Containerd了那么你只需安装nerdctl这个工具也可以。
如果你是只安装nerdctl这个工具,那么命令如下
wget https://mirror.ghproxy.com/https://github.com/containerd/nerdctl/releases/download/v1.2.0/nerdctl-1.2.0-linux-amd64.tar.gz
tar Cxf /usr/local/bin nerdctl-1.2.0-linux-amd64.tar.gz
如果你选择完整版安装,那么命令如下
wget https://mirror.ghproxy.com/https://github.com/containerd/nerdctl/releases/download/v1.2.0/nerdctl-full-1.2.0-linux-amd64.tar.gz
tar Cxf /usr/local nerdctl-full-1.2.0-linux-amd64.tar.gz
安装完成之后,可以尝试着查看一下该工具的帮助信息,命令如下
nerdctl --help
1、nerdctl管理
查看namespace
nerdctl namespace ls
查看network信息
nerdctl network ls
这里需要说明的是,Containerd是使用cni来进行网络管理的,因此如果在没有安装cni情况下执行该命令会报cni未安装的错误提示。
你可以从完整版的数据包中找到这些cni介质,当然你也可以单独下载。
假如,你从完整版中获取cni,那么你需要将安装包解压至一个目录,例如/tmp/nerdctl,然后将cni复制到/opt/cni/bin目录中即可
tar -xf nerdctl-full-1.2.0-linux-amd64.tar.gz -C /tmp/nerdctl
cp /tmp/nerdctl/libexec/cni/* /opt/cni/bin/
2、运行容器
nerdctl run -d --name nginx -p 8080:80 nginx:1.19.6
你可基于namespace来创建容器,例如在test命名空间中创建一个nginx容器
ctr ns create test
nerdctl -n test run -d --name nginx -p 8080:80 nginx:1.19.6
镜像也是基于namespace,也就是说假设你的默认namespace是moby,那么你在这个空间中查看的镜像,与test空间中可能会不同,如果你在test中pull了一个新镜像,那么在moby空间将不可见,除非使用-n test声明查看的命名空间。
3、构建镜像
实际上一般构建镜像,与运行容器的可能会分别处于不同的环境中,这样在职能上的划分,可避免混合任务带来的风险。那么nerdctl这个工具并不具备构建镜像的能力,而需要借助其他服务来完成,如果你需要构建镜像,那么可以使用buildkit来完成。
buildkit可以从nerdctl-full的包中获得,也可以单独下载安装,例如,我这里直接从nerdctl-full这个包中获取。安装命令如下
cd /tmp/nerdctl
cp build* /usr/local/bin/
cp lib/systemd/system/buildkit.service /usr/lib/systemd/system/
systemctl enable buildkit --now
那么你可以像使用docker时一样来构建自己的镜像,执行命令只过是将docker换成nerdctl即可。
准备Dockerfile文件,内容如下
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
然后执行构建,命令如下
nerdctl build -t python-web:latest .
构建完成后,可以查看镜像,命令如下
nerdctl images
另外nerdctl 还可以直接像compose一样来读取docker-compose文件完成容器的部署
nerdctl compose -d -f docker-compose.yaml
总体而言,nerdctl让人又仿佛回到了使用docker命令时,那样熟悉而又流畅的操作容器的感觉。弥补了ctr命令在交互上的不足。
3、Containerd NameSpace管理
containerd中namespace的作用为:隔离运行的容器,可以实现运行多个容器。
查看命令帮助
# ctr namespace --help
NAME:
ctr namespaces - manage namespaces
USAGE:
ctr namespaces command [command options] [arguments...]
COMMANDS:
create, c create a new namespace
list, ls list namespaces
remove, rm remove one or more namespaces
label set and clear labels for a namespace
OPTIONS:
--help, -h show help
列出已有namespace
# ctr ns ls
NAME LABELS
default
moby
创建namespace
# ctr ns create nginx
# ctr ns ls
NAME LABELS
default
moby
nginx # 此命名空间为新添加的
删除namespace
# ctr ns rm nginx
nginx
# ctr ns ls
NAME LABELS
default
moby
在指定namespace中下载容器镜像
# ctr -n web images pull docker.io/library/nginx:latest
在指定namespace中创建静态容器
# ctr -n web container create docker.io/library/nginx:latest nginxapp
查看在指定namespace中创建的容器
# ctr -n web c ls
CONTAINER IMAGE RUNTIME
nginxapp docker.io/library/nginx:latest io.containerd.runc.v2
四、Containerd Network管理
默认Containerd管理的容器仅有lo网络,无法访问容器之外的网络,可以为其添加网络插件,使用容器可以连接外网。CNI(Container Network Interface)
Containerd默认是使用cni插件来建立容器网络的,因此需要额外配置cni,首先需要先创建一个cni网络默认配置,cni网络默认配置文件位于/etc/cni/net.d/
cat > /etc/cni/net.d/10-cni-net.conflist << EOF
{
"cniVersion": "0.4.0",
"name": "cni-net",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"promiscMode": true,
"ipam": {
"type": "host-local",
"ranges": [
[{
"subnet": "172.18.1.0/24"
}]
],
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
},
{
"type": "portmap",
"capabilities": {"portMappings": true}
}
]
}
EOF
1、创建CNI网络
1、获取CNI工具源码
# wget https://mirror.ghproxy.com/https://github.com/containernetworking/cni/archive/refs/tags/v1.1.2.tar.gz
查看已下载cni工具源码包
# tar zxf v1.1.2.tar.gz
# mv cni-1.1.2 cni
# cd cni/
# ls
cnitool CODE-OF-CONDUCT.md CONTRIBUTING.md CONVENTIONS.md DCO Documentation go.mod go.sum GOVERNANCE.md libcni LICENSE logo.png MAINTAINERS pkg plugins README.md RELEASING.md ROADMAP.md scripts SPEC.md test.sh
2、获取CNI Plugins(CNI插件)
准备容器网络配置文件,用于为容器提供网关、IP地址等。
创建名为mynet的网络,其中包含名为cni0的网桥
# vim /etc/cni/net.d/10-mynet.conf
{
"cniVersion": "1.0.0",
"name": "mynet",
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "10.66.0.0/16",
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
}
# vim /etc/cni/net.d/99-loopback.conf
{
"cniVerion": "1.0.0",
"name": "lo",
"type": "loopback"
}
3、生成CNI网络
安装jq
# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
# yum -y install jq
# cd cni/scripts/
# ls
docker-run.sh exec-plugins.sh priv-net-run.sh release.sh
执行脚本文件,基于/etc/cni/net.d/目录中的*.conf配置文件生成容器网络
# CNI_PATH=/home/cni-plugins ./priv-net-run.sh echo "Hello World"
在宿主机上查看是否生成容器网络名为cni0的网桥
# ip a s
......
5: cni0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state
DOWN group default qlen 1000
link/ether 36:af:7a:4a:d6:12 brd ff:ff:ff:ff:ff:ff
inet 10.66.0.1/16 brd 10.66.255.255 scope global cni0
valid_lft forever preferred_lft forever
inet6 fe80::34af:7aff:fe4a:d612/64 scope link
valid_lft forever preferred_lft forever
在宿主机上查看其路由表情况
# ip route
default via 192.168.10.2 dev ens33 proto dhcp metric 100
10.66.0.0/16 dev cni0 proto kernel scope link src 10.66.0.1
192.168.10.0/24 dev ens33 proto kernel scope link src 192.168.10.164 metric
100
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1
五、Containerd容器数据持久化存储
实现把宿主机目录挂载至Containerd容器中,实现容器数据持久化存储
# ctr container create docker.io/library/busybox:latest busybox3 --mount type=bind,src=/tmp,dst=/hostdir,options=rbind:rw
说明:
创建一个静态容器,实现宿主机目录与容器挂载
src=/tmp 为宿主机目录
dst=/hostdir 为容器中目录
评论区