Kubernetes v1.24 之前的版本直接集成了 Docker Engine 的一个组件,名为 dockershim [用于调用Docker]。 这种特殊的直接整合不再是 Kubernetes 的一部分 (这次删除被作为 v1.20 发行版本的一部分宣布)。 这意味Kubernetes从版本1.24开始就弃用Docker作为容器运行时,取而代之的是更加轻量级的Containerd。
containerd可用作 Linux 和 Windows 的守护进程。它管理其主机系统的完整容器生命周期,从图像传输和存储到容器执行和监督,再到低级存储到网络附件等等。
【Docker名噪一时,捐出runC】2013年docker公司在推出docker产品后,由于其对全球技术产生了一定的影响力,Google公司明显感觉到自己公司内部所使用的Brog系统江湖地位受到的威胁,希望Docker公司能够与自己联合打造一款开源的容器运行时作为Docker核心依赖,但Docker公司拒绝了;接着Google公司联合RedHat、IBM等公司说服Docker公司把其容器核心技术libcontainer
捐给OCI(Open Container Intiative),并更名为runC
。
【CNCF成立,kubernetes被迫开源】为了进一步遏制Docker在未来技术市场影响力,避免在容器市场上Docker一家独大,Google公司带领RedHat、IBM等成立了CNCF(Cloud Native Computing Fundation)基金会,即云原生计算基金会。CNCF的目标很明确,既然在容器应用领域无法与Docker相抗衡,那就做Google更有经验的技术市场——大规模容器编排应用场景。Google公司把自己内部使用的Brog系统开源——Kubernetes,也就是我们今天所说的云原生技术生态。
【Docker妥协,贡献出Containerd】2016年Docker公司推出了Docker Swarm,意在一统Docker生态,让Docker既可以实现容器应用管理,也可以实现大规模容器编排,经过近1年左右时间的市场验证后,发现在容器编排方面无法独立抗衡kubernetes,所以Docker公司于2017年正式宣布原生支持Kubernetes。至此,Docker在大规模容器编排应用市场败下阵来,但是Docker依然不甘心失败,把Docker核心依赖Containerd捐给了CNCF,依此说明Docker依旧是一个PaaS平台。
【k8s宣布不支持Docker,Containerd成为CRI主角】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。
早在2016年3月,Docker 1.11的Docker Engine里就包含了containerd,而现在则是把containerd从Docker Engine里彻底剥离出来,作为一个独立的开源项目独立发展,目标是提供一个更加开放、稳定的容器运行基础设施。
和原先包含在Docker Engine里containerd相比,独立的containerd将具有更多的功能,可以涵盖整个容器运行时管理的所有需求。另外独立之后containerd的特性演进可以和Docker Engine分开,专注容器运行时管理,可以更稳定。
Containerd是一个工业标准的容器运行时,重点是它简洁,健壮,便携,在Linux和window上可以作为一个守护进程运行,它可以管理主机系统上容器的完整的生命周期:镜像传输和存储,容器的执行和监控,低级别的存储和网络。
每个containerd只负责一台机器,Pull镜像,对容器的操作(启动、停止等),网络,存储都是由containerd完成。具体运行容器由runC负责,实际上只要是符合OCI规范的容器都可以支持。
Containerd和docker不同,containerd重点是集成在大规模的系统中,例如kubernetes、Swarm、Mesos等【对于容器编排服务来说,运行时只需要使用containerd+runC,更加轻量,容易管理。】。Containerd 被设计成嵌入到一个更大的系统中,而不是直接由开发人员或终端用户使用。
Containerd的特点:
Containerd的作用:
使用 bucketbench 对 Docker、crio 和 Containerd 的性能测试结果,包括启动、停止和删除容器,以比较它们所耗的时间,可以发现Containerd 在各个方面都表现良好,总体性能优于 Docker 和 crio。
Containerd 采用标准的 C/S 架构:服务端通过 GRPC 协议提供稳定的 API;客户端通过调用服务端的 API 进行高级的操作。
为了实现解耦,Containerd 将不同的职责划分给不同的组件,每个组件就相当于一个子系统(subsystem)。连接不同子系统的组件被称为模块。
Containerd 被分为三个大块: Storage 、 Metadata 和 Runtime。
Containerd 两大子系统为:
Bundle : 在 Containerd 中,Bundle 包含了配置、元数据和根文件系统数据,你可以理解为 容器的文件系统。而 Bundle 子系统允许用户从镜像中提取和打包 Bundles。
Runtime : Runtime 子系统用来执行 Bundles,比如创建容器。其中,每一个子系统的行为都由一个或多个模块协作完成(架构图中的 Core 部分)。
containerd
是一个高级容器运行时,又名容器管理器。简单来说,它是一个守护进程,在单个主机上管理完整的容器生命周期:创建、启动、停止容器、拉取和存储镜像、配置挂载、网络等。
ctr
是作为 containerd 项目的一部分提供的命令行客户端。该ctr界面 [显然] 与 Docker CLI不兼容,乍一看,可能看起来不太用户友好。因为它的主要受众是测试守护进程的容器开发人员。ctr + containerd比docker + dockerd更接近实际的容器。
nerdctl
是一个相对较新的containerd命令行客户端。与ctr不同,nerdctl的目标是用户友好和docker兼容。在某种程度上,nerdctl + containerd可以无缝地替代docker + dockerd。
crictl
是一个命令行客户端,用于 [kubernetes] CRI兼容的容器运行时。引入 Kubernetes 容器运行时接口 (CRI)以使 Kubernetes 容器运行时不可知。Kubernetes节点代理kubelet实现了 CRI客户端 API,可以使用任何实现 CRI 服务器 API的容器运行时来管理其节点上的容器和 Pod。
containerd官网:https://containerd.io/
containerd官方安装步骤:https://github.com/containerd/containerd/blob/main/docs/getting-started.md
下载好相应的安装部署包【所有安装包都可在github上进行下载】如下:
$ ll
-rw-r--r-- 1 root root 118639 Sep 2 08:32 cni-1.1.2.tar.gz # cni工具源码包[注意要与cni插件兼容]# cni工具1.1.2兼容cni插件1.0.0
-rw-r--r-- 1 root root 36336160 Sep 1 13:49 cni-plugins-linux-amd64-v1.0.0.tgz #cni插件
-rw-r--r-- 1 root root 44458241 Sep 1 13:20 containerd-1.6.8-linux-amd64.tar.gz #containerd
-rw-r--r-- 1 root root 10685899 Sep 1 14:36 nerdctl-0.22.2-linux-amd64.tar.gz #nerdctl
-rw-r--r-- 1 root root 9431456 Sep 1 13:58 runc.amd64 #runC
$ tar Cxzvf /usr/local containerd-1.6.8-linux-amd64.tar.gz
将containerd服务设置卫开机启动,先配置为系统服务
$ vim /etc/systemd/system/containerd.service
内容如下:
$ cat /etc/systemd/system/containerd.service
# Copyright The containerd Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target
[Service]
#uncomment to enable the experimental sbservice (sandboxed) version of containerd/cri integration
#Environment="ENABLE_CRI_SANDBOXES=sandboxed"
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd
Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
# 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
LimitNOFILE=infinity
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
将containerd服务设置卫开机启动。
$ systemctl enable --now containerd
# 验证
$ ctr version
Client:
Version: v1.6.8
Revision: 9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6
Go version: go1.17.13
Server:
Version: v1.6.8
Revision: 9cd3357b7fd7218e4aec3eae239db1f68a5a6ec6
UUID: 87222662-9eb1-44cb-998a-689c9efce638
至此,containerd安装完成。
由于二进制包中提供的runC默认需要系统中安装seccomp支持,需要单独安装,且不同版本runC 对seccomp版本要求一致,所以建议单独下载runC二进制包进行安装,里面包含了seccomp模块支持。
$ install -m 755 runc.amd64 /usr/local/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
$ mkdir -p /home/cni-plugins
$ tar Cxzvf /home/cni-plugins cni-plugins-linux-amd64-v1.0.0.tgz
## 该二进制文件是静态构建的,可以在任何 Linux 发行版上运行
# cni工具1.1.2兼容cni插件1.0.0
$ mkdir -p /home/cni-tools
$ tar Cxzvf /home/cni-tools cni-1.1.2.tar.gz
完成。
ctr是作为 containerd 项目的一部分提供的命令行客户端。
该ctr界面 [显然] 与 Docker CLI不兼容,乍一看,可能看起来不太用户友好。显然,它的主要受众是测试守护进程的容器开发人员。但是,由于它最接近实际的 containerd API,因此它可以作为一种很好的探索手段——通过检查可用命令,可以大致了解 containerd可以做什么和不可以做什么。
$ ctr --help
NAME:
ctr -
__
_____/ /______
/ ___/ __/ ___/
/ /__/ /_/ /
\___/\__/_/
containerd CLI
USAGE:
ctr [global options] command [command options] [arguments...]
VERSION:
v1.6.8
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 images pull --all-platforms docker.io/library/nginx:alpine
# --all-platforms 指定所有平台镜像
# --platform 指定系统平台
$ ctr images pull --platform linux/amd64 docker.io/library/nginx:latest
# 查看镜像
$ ctr images ls
# 挂载镜像
$ ctr images mount docker.io/library/nginx:alpine /mnt
$ ls /mnt
$ umount /mnt
# 镜像导出,并保存为nginx.img文件
$ ctr i export --all-platforms nginx.img docker.io/library/nginx:alpine
$ ls -l
-rw-r--r-- 1 root root 70138368 Sep 2 16:33 nginx.img
# 镜像导入
$ ctr images import nginx.img
# 镜像打tag
$ ctr images tag docker.io/library/nginx:alpine nginx:alpine
# 镜像对比
$ ctr images check
# 创建【静态】容器
# 该命令创建容器后,容器并没有处于运行状态,其只是一个静态的容器。这个container对象只是包含了运行一个容器所需的资源及配置的数据结构,例如: namespaces、rootfs 和容器的配置都已经初始化成功了,只是用户进程(本案例为nginx)还没有启动。需要使用`ctr tasks`命令才能获取一个动态容器。
$ ctr container create docker.io/library/nginx:alpine testnginx1
# 启动【动态】容器 创建容器和任务子命令分离
$ ctr task start -d testnginx1
# 直接运行一个动态容器【容器的IP就是宿主机的IP】
# ctr运行命令实际上是ctr容器创建+ ctr任务启动的快捷方式
$ ctr run -d --net-host docker.io/library/nginx:alpine testnginx2
# 查看【静态】容器
$ ctr container ls
# 查看【动态】容器
$ ctr task ps testnginx1
PID INFO
64574 -
64613 -
64614 -
64615 -
64616 -
# 物理机上查看
$ ps -ef | grep nginx
root 64574 64553 0 16:41 ? 00:00:00 nginx: master process nginx -g daemon off;
101 64613 64574 0 16:41 ? 00:00:00 nginx: worker process
101 64614 64574 0 16:41 ? 00:00:00 nginx: worker process
101 64615 64574 0 16:41 ? 00:00:00 nginx: worker process
101 64616 64574 0 16:41 ? 00:00:00 nginx: worker process
# 进入容器
$ ctr task exec --exec-id 1 testnginx2 sh
# 查看网卡
ifconfig
ens33 Link encap:Ethernet HWaddr 00:0C:29:32:CC:B0
inet addr:192.168.168.201 Bcast:192.168.168.255 Mask:255.255.255.0
inet6 addr: fe80::63d5:da66:d3db:fa1c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:476940 errors:0 dropped:0 overruns:0 frame:0
TX packets:595381 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:175687016 (167.5 MiB) TX bytes:149770479 (142.8 MiB)
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)
# 为容器中运行的网站添加网站文件
echo "hello nginx2" > /usr/share/nginx/html/index.html
# 在容器里访问
curl 127.0.0.1
# 退出容器
exit
# 在宿主机上访问
$ curl 192.168.168.201
hello nginx2
# 暂停容器
$ ctr task pause testnginx2
# 恢复容器
$ ctr task resume testnginx2
# 停止容器
$ ctr task kill testnginx2
# 删除动态容器【必须先停止】
$ ctr task delete testnginx2
# 删除静态容器
$ ctr container delete testnginx2
containerd中namespace的作用为:隔离运行的容器,可以实现运行多个容器。
# 拉取镜像
$ ctr namespace --help
# 创建命名空间
$ ctr ns create testns
# 查看命名空间
$ ctr ns ls
# 在命名空间中进行镜像、容器等相关操作
$ ctr -n testns images pull docker.io/library/nginx:latest
$ ctr -n testns images ls
$ ctr -n testns container create docker.io/library/nginx:latest
$ ctr -n testns container ls
# 删除命名空间
$ ctr ns rm testns
默认Containerd管理的容器仅有lo网络,无法访问容器之外的网络,可以为其添加网络插件,使用容器可以连接外网,CNI(Container Network Interface)
cni插件和cni工具包已经在前面第二章节已经部署完毕。
# cni插件目录
$ cd /home/cni-plugins
# cni工具包目录
$ cd /home/cni-tools/cni-1.1.2
# cni工具1.1.2兼容cni插件1.0.0
$ vim /etc/cni/net.d/10-mynet.conf
$ vim /etc/cni/net.d/99-loopback.conf
$ cat /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"
}
]
}
}
$ cat /etc/cni/net.d/99-loopback.conf
{
"cniVerion": "1.0.0",
"name": "lo",
"type": "loopback"
}
# 获取epel源
$ wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
#安装jq【jq是一个'出色'的'针对-->JSON处理器'的命令行】
$ yum -y install jq
# 进入cni工具目录
$ cd /home/cni-tools/cni-1.1.2
# 执行脚本文件,基于/etc/cni/net.d/目录中的*.conf配置文件生成容器网络
# CNI_PATH是cni插件安装的目录
$ CNI_PATH=/home/cni-plugins ./priv-net-run.sh echo "Hello World"
# cni插件和cni工具包版本要兼容,否则可能会报错如下:
mynet : error executing ADD: {
"code": 1,
"msg": "incompatible CNI versions",
"details": "config is \"1.0.0\", plugin supports [\"0.1.0\" \"0.2.0\" \"0.3.0\" \"0.3.1\" \"0.4.0\"]"
}
#安装成功后,在宿主机上查看是否生成容器网络名为cni0的网桥
$ ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
...
7: cni0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 6a:32:bc:eb:0f:23 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::6832:bcff:feeb:f23/64 scope link
valid_lft forever preferred_lft forever
$ ctr images pull docker.io/library/busybox:latest
$ ctr run -d docker.io/library/busybox:latest busybox
$ ctr tasks exec --exec-id $RANDOM -t busybox sh
/ # ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
#获取容器进程ID及其网络命名空间
$ pid=$(ctr tasks ls | grep busybox | awk '{print $2}') && echo $pid
39287
$ netnspath=/proc/$pid/ns/net && echo $netnspath
/proc/39287/ns/net
# 进入目录为指定容器添加网络配置
$ cd /home/cni-tools/cni-1.1.2/scripts/
$ CNI_PATH=/home/cni-plugins ./exec-plugins.sh add $pid $netnspath
# 验证
# 进入容器确认是否添加网卡信息
$ ctr tasks exec --exec-id $RANDOM -t busybox sh
/ # ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
3: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 5a:36:90:c1:33:b1 brd ff:ff:ff:ff:ff:ff
inet 10.66.0.4/16 brd 10.66.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5836:90ff:fec1:33b1/64 scope link
valid_lft forever preferred_lft forever
# 在容器中ping容器宿主机IP地址
/ # ping -c 2 192.168.168.201
PING 192.168.168.201 (192.168.168.201): 56 data bytes
64 bytes from 192.168.168.201: seq=0 ttl=64 time=0.067 ms
64 bytes from 192.168.168.201: seq=1 ttl=64 time=0.070 ms
--- 192.168.168.201 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.067/0.068/0.070 ms
# 在容器中ping容器宿主机IP地址
/ # ping -c 2 192.168.168.2
PING 192.168.168.2 (192.168.168.2): 56 data bytes
64 bytes from 192.168.168.2: seq=0 ttl=127 time=0.141 ms
64 bytes from 192.168.168.2: seq=1 ttl=127 time=0.324 ms
--- 192.168.168.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.141/0.232/0.324 ms
# 在容器中ping容器宿主机IP地址
/ # ping -c 2 192.168.168.202
PING 192.168.168.201 (192.168.168.202): 56 data bytes
64 bytes from 192.168.168.202: seq=0 ttl=64 time=0.067 ms
64 bytes from 192.168.168.202: seq=1 ttl=64 time=0.070 ms
--- 192.168.168.202 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.067/0.068/0.070 ms
# 在容器中开启httpd服务
/ # echo "containerd net web test" > /tmp/index.html
/ # httpd -h /tmp
/ # wget -O - -q 127.0.0.1
containerd net web test
/ # exit
#在宿主机访问容器提供的httpd服务
$ curl 10.66.0.4
containerd net web test
实现把宿主机目录挂载至Containerd容器中,实现容器数据持久化存储。
# 创建一个静态容器,实现宿主机目录与容器挂载,src=/tmp 为宿主机目录 dst=/hostdir 为容器中目录
$ ctr container create docker.io/library/busybox:latest busybox3 --mount type=bind,src=/tmp,dst=/hostdir,options=rbind:rw
# 运行用户进程
$ ctr tasks start -d busybox3 bash
$ ctr t ls
TASK PID STATUS
busybox 39287 RUNNING
busybox3 105003 RUNNING
# 进入容器,查看是否挂载成功
$ ctr tasks exec --exec-id $RANDOM -t busybox3 sh
/ # ls /hostdir/
ks-script-GSRMK8 vmware-root_6389-1958486695
systemd-private-cc74dd8802f0428490924757e690c750-chronyd.service-9TDICh vmware-root_6511-1689719547
vmware-root_6359-1949639453 yum.log
# 向容器中挂载目录中添加文件
/ # echo "hello world" > /hostdir/test.txt
/ # ls /hostdir/
ks-script-GSRMK8 vmware-root_6389-1958486695
systemd-private-cc74dd8802f0428490924757e690c750-chronyd.service-9TDICh vmware-root_6511-1689719547
test.txt yum.log
vmware-root_6359-1949639453
# 在宿主机上查看被容器挂载的目录中是否添加了新的文件,已添加表明被容器挂载成功,并可以读写此目录中内容。
$ cat /tmp/test.txt
hello world
目前Containerd主要任务还在于解决容器运行时的问题,对于其周边生态还不完善,所以有时需要借助:Docker结合Containerd来实现Docker完整的功能应用。
Docker安装与使用教程:https://blog.csdn.net/qq_41822345/article/details/107123094
docker运行的容器默认在moby命名空间下。
# 安装docker
$ yum install docker
# 启动docker
$ systemctl start docker
# 运行一个容器
$ docker run -d nginx:latest
$ docker ps
# 查看ctr命令下的namespace,发现多了一个moby命名空间。moby即为docker使用的命名空间。
$ ctr namespace ls
NAME LABELS
default
k8s.io
moby
# 查看moby命名空间下的容器和任务
$ ctr -n moby container ls
$ ctr -n moby tasks ls