一、RunC
RunC 是一个轻量级的工具,它是用来运行容器的,它就是个命令行工具(CLI),可以不用通过 docker 引擎,直接创建、启动、停止容器等。
RunC 是标准化的产物,它根据 OCI (Open Container Initiative) 标准来创建和运行容器。RunC 是一个低级的容器运行时。容器运行时是负责容器进程的创建、启动、停止、移动和删除的管理工具。它提供了一种标准化的方式来打包、分发和运行应用程序,使得应用程序可以在不同的环境中可靠地运行。
自从 2013 年 docker 发布之后,docker 项目逐渐成为了一个庞然大物。为了能够降低项目维护的成本,内部代码能够回馈社区,他们于 2014 年开源了 libcontainer,docker 公司将 libcontainer 的实现移动到 runC 并捐赠给了 OCI。在 2016 年,docker 开源并将 containerd 捐赠给了 CNCF。
OCI (open container Initiative) 容器规范:
- Runtime Spec
- Image format Spect
ctr cli ---grpc---> containerd ---exec---> containerd-shim-runc ---exec---> runc
crictl 与 kubelet ---CRI---> containerd ---exec---> containerd-shim-runc ---exec---> runc
RunC 希望提供一个“ OCI 包”,它只是一个根文件系统和一个 config.json 文件。而不是 Podman 或 Docker 那样有“镜像”概念,所以不能只执行 runc run nginx:latest
这样来启动一个容器。
Runc 符合 OCI 规范(具体来说,是 runtime-spec ),这意味着它可以使用 OCI 包并从中运行一个容器。值得重申的是,这些 bundle 并不是“容器镜像”,它们要简单得多。层、标签、容器注册表和存储库等功能,所有这些都不是 OCI 包甚至运行时规范的一部分。
根据 OCI Runtime 规范,Linux ABI 下的应用程序会期望 Linux 环境提供以下特殊的文件系统:
- /proc 文件夹,挂载 proc 文件系统
- /sys 文件夹,挂载 sysfs 文件系统
- /dev/pts 文件夹,挂载 devpts 文件系统
- /dev/shm 文件夹,挂载 tmpfs 文件系统
二、容器状态
OCI 都定义了哪几种容器状态:
- creating:使用 create 命令创建容器,这个过程称为创建中。
- created:容器已经创建出来,但是还没有运行,表示镜像文件和配置没有错误,容器能够在当前平台上运行。
- running:容器里面的进程处于运行状态,正在执行用户设定的任务。
- stopped:容器运行完成,或者运行出错,或者 stop 命令之后,容器处于暂停状态。这个状态,容器还有很多信息保存在平台中,并没有完全被删除。
- paused:暂停容器中的所有进程,可以使用 resume 命令恢复这些进程的执行。
三、准备 OCI bundle
RunC 是运行容器的运行时,它负责利用符合标准的文件等资源运行容器,但是它不包含 docker 那样的镜像管理功能。
所以要用 runC 运行容器,我们先得准备好容器的文件系统。所谓的 OCI bundle 就是指容器的文件系统和一个 config.json 文件。
有了容器的文件系统后我们可以通过 runc spec 命令来生成 config.json 文件。使用 docker 可轻松的生成容器的文件系统。
准备一个运行 busybox 容器所需的文件系统:
zxm@zxm-pc:~$ docker pull busybox:1.35.0
zxm@zxm-pc:~$ docker create --name busybox_1 busybox:1.35.0
zxm@zxm-pc:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b3d365c57f04 busybox:1.35.0 "sh" 3 seconds ago Created busybox_1
zxm@zxm-pc:~$ docker export busybox_1 -o busybox_1.tar
zxm@zxm-pc:~$ mkdir -p mycontainer/rootfs/
zxm@zxm-pc:~$ tar -xvf busybox_1.tar -C mycontainer/rootfs/
现在 rootfs 目录下就是 busybox 镜像的文件系统,然后使用 runc spec 生成 config.json 文件:
zxm@zxm-pc:~$ ls mycontainer/rootfs/
bin dev etc home lib lib64 proc root sys tmp usr var
zxm@zxm-pc:~/mycontainer$ ls
rootfs
zxm@zxm-pc:~/mycontainer$ runc spec
zxm@zxm-pc:~/mycontainer$ ls
config.json rootfs
如果直接使用生成的 config.json,接下来的演示不会太流畅,所以简单起见,我们稍微修改一下刚刚生成的 config.json 文件。就是把 "terminal": true 改为 false,把 "args": ["sh"] 改为 "args": ["sleep", "30"]:
zxm@zxm-pc:~/mycontainer$ cat config.json
{
"ociVersion": "1.0.2-dev",
"process": {
"terminal": false,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"sleep", "30"
],
...
...
}
}
四、RunC 命令
1.创建容器
使用 create 命令创建容器
sudo runc create <container_name>
zxm@zxm-pc:~/mycontainer$ sudo runc create mybusybox
2.查看容器
使用 list 命令查看当前存在的容器
zxm@zxm-pc:~/mycontainer$ sudo runc list
ID PID STATUS BUNDLE CREATED OWNER
mybusybox 12475 created /home/zxm/mycontainer 2024-07-07T09:04:06.921387816Z root
2.查看状态
使用 state 命令查看容器的状态
zxm@zxm-pc:~/mycontainer$ sudo runc state mybusybox
{
"ociVersion": "1.0.2-dev",
"id": "mybusybox",
"pid": 12475,
"status": "created",
"bundle": "/home/zxm/mycontainer",
"rootfs": "/home/zxm/mycontainer/rootfs",
"created": "2024-07-07T09:04:06.921387816Z",
"owner": ""
}
3.查看容器内进程
使用 ps 命令看看容器内运行的进程
zxm@zxm-pc:~/mycontainer$ sudo runc ps mybusybox
UID PID PPID C STIME TTY TIME CMD
root 12475 1538 0 17:04 ? 00:00:00 runc init
ps 查看:
zxm@zxm-pc:~$ ps -ef
zxm 1538 1 0 7月07 ? 00:00:01 /lib/systemd/systemd --user
root 12475 1538 0 7月07 ? 00:00:00 runc init
...
3.启动容器任务
使用 start 命令执行容器中定义的任务
容器状态变为 running,过段时间变为 stopped
zxm@zxm-pc:~/mycontainer$ sudo runc start mybusybox
zxm@zxm-pc:~/mycontainer$ sudo runc ps mybusybox
UID PID PPID C STIME TTY TIME CMD
root 12475 1538 0 17:04 ? 00:00:00 sleep 30
zxm@zxm-pc:~/mycontainer$ sudo runc state mybusybox
{
"ociVersion": "1.0.2-dev",
"id": "mybusybox",
"pid": 12475,
"status": "running",
"bundle": "/home/zxm/mycontainer",
"rootfs": "/home/zxm/mycontainer/rootfs",
"created": "2024-07-07T09:04:06.921387816Z",
"owner": ""
}
zxm@zxm-pc:~/mycontainer$ sudo runc state mybusybox
{
"ociVersion": "1.0.2-dev",
"id": "mybusybox",
"pid": 0,
"status": "stopped",
"bundle": "/home/zxm/mycontainer",
"rootfs": "/home/zxm/mycontainer/rootfs",
"created": "2024-07-07T09:04:06.921387816Z",
"owner": ""
}
ps 查看:
zxm@zxm-pc:~$ ps -ef
zxm 1538 1 0 7月07 ? 00:00:01 /lib/systemd/systemd --user
root 12475 1538 0 7月07 ? 00:00:00 sleep 30
...
4.执行容器命令
使用 exec 命令在容器中执行命令
zxm@zxm-pc:~/mycontainer$ sudo runc exec mybusybox ls
bin
dev
etc
home
lib
lib64
proc
root
sys
tmp
usr
var
5.删除容器
使用 delete 命令删除容器
zxm@zxm-pc:~/mycontainer$ sudo runc list
ID PID STATUS BUNDLE CREATED OWNER
mybusybox 0 stopped /home/zxm/mycontainer 2024-07-07T09:04:06.921387816Z root
zxm@zxm-pc:~/mycontainer$ sudo runc delete mybusybox
zxm@zxm-pc:~/mycontainer$ sudo runc list
ID PID STATUS BUNDLE CREATED OWNER
6.创建并运行容器
使用 run 命令创建并运行容器,当容器中的命令退出后容器随即被删除。
zxm@zxm-pc:~/mycontainer$ sudo runc run mybusybox
7.停止容器中的任务
使用 kill 命令停止容器中的任务
zxm@zxm-pc:~$ sudo runc kill mybusybox
默认它会优雅的结束容器中的进程,但是碰到特殊情况,你就得使用终极信号 9:
zxm@zxm-pc:~$ sudo runc kill mybusybox 9
8.暂停容器进程
执行 pause 命令后,容器的状态由 running 变成了 paused
zxm@zxm-pc:~$ sudo runc pause mybusybox
9.恢复容器进程
通过 resume 命令恢复容器中进程的执行,此时容器的状态又恢复到了 running
zxm@zxm-pc:~$ sudo runc resume mybusybox