专注于大数据及容器云核心技术解密,可提供全栈的大数据+云原生平台咨询方案,请持续关注本套博客。如有任何学术交流,可随时联系。更多内容请关注《数据云技术社区》公众号。

1 OCI标准

- 在2015年6月,由Docker以及其他容器领域的领导者共同建立了围绕容器格式和运行时的开放的工业化标准,即Open Container Initiative(OCI),OCI具体包含两个标准:运行时标准(runtime-spec)和容器镜像标准(image-spec)。
- 容器镜像标准定义了容器镜像的打包形式(pack format)
- 运行时标准定义了如何去运行一个容器。
- 容器运行时(Container Runtime)是指管理容器和容器镜像的软件,当如果不同的运行时只能支持各自的容器,那么显然不利于整个容器技术的发展。
- runC是一个遵循OCI标准的用来运行容器的命令行工具(CLI Tool),它也是一个Runtime的实现。

- runC不仅可以被docker engine使用,它也可以单独使用(它本身就是命令行工具)

2 安装runC
2.1 依赖准备
- Go version 1.6或更高版本
- libseccomp库
yum install libseccomp-devel for CentOS
apt-get install libseccomp-dev for Ubuntu
2.2 编译
# 在GOPATH/src目录创建github.com目录
> go get github.com/opencontainers/runc
> cd $GOPATH/src/github.com/opencontainers/runc
> make
> sudo make install
2.3 运行RunC
- 使用docker export命令将已有镜像导出为OCI Bundle的格式
# create the top most bundle directory
> mkdir /mycontainer
> cd /mycontainer
# create the rootfs directory
> mkdir rootfs
# export busybox via Docker into the rootfs directory
> docker export $(docker create busybox) | tar -C rootfs -xvf -
> ls rootfs
bin dev etc home proc root sys tmp usr var
- 有了root filesystem,还需要config.json,runc spec可以生成一个基础模板
> runc spec
> ls
config.json rootfs
- 创建一个config.json文件,这个文件是一个标准的OCI格式的文件,把 "terminal": true 改为 false,把 "args": ["sh"] 改为 "args": ["sleep", "30"]

{
"ociVersion": "1.0.1-dev",
"process": {
"terminal": fasle,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"sleep","30"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": "/",
"capabilities": {
"bounding": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"effective": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"inheritable": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"permitted": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"ambient": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
]
},
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 1024,
"soft": 1024
}
],
"noNewPrivileges": true
},
"root": {
"path": "rootfs",
"readonly": true
},
"hostname": "runc",
"mounts": [
{
"destination": "/proc",
"type": "proc",
"source": "proc"
},
{
"destination": "/dev",
"type": "tmpfs",
"source": "tmpfs",
"options": [
"nosuid",
"strictatime",
"mode=755",
"size=65536k"
]
},
{
"destination": "/dev/pts",
"type": "devpts",
"source": "devpts",
"options": [
"nosuid",
"noexec",
"newinstance",
"ptmxmode=0666",
"mode=0620",
"gid=5"
]
},
{
"destination": "/dev/shm",
"type": "tmpfs",
"source": "shm",
"options": [
"nosuid",
"noexec",
"nodev",
"mode=1777",
"size=65536k"
]
},
{
"destination": "/dev/mqueue",
"type": "mqueue",
"source": "mqueue",
"options": [
"nosuid",
"noexec",
"nodev"
]
},
{
"destination": "/sys",
"type": "sysfs",
"source": "sysfs",
"options": [
"nosuid",
"noexec",
"nodev",
"ro"
]
},
{
"destination": "/sys/fs/cgroup",
"type": "cgroup",
"source": "cgroup",
"options": [
"nosuid",
"noexec",
"nodev",
"relatime",
"ro"
]
}
],
"linux": {
"resources": {
"devices": [
{
"allow": false,
"access": "rwm"
}
]
},
"namespaces": [
{
"type": "pid"
},
{
"type": "network"
},
{
"type": "ipc"
},
{
"type": "uts"
},
{
"type": "mount"
}
],
"maskedPaths": [
"/proc/kcore",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/sys/firmware",
"/proc/scsi"
],
"readonlyPaths": [
"/proc/asound",
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
}
}
3 RunC 命令
3.1 常用命令
$ runc -h
使用 create 命令创建容器
sudo runc create mybusybox
使用 list 命令查看当前存在的容器
sudo runc list
ID PID STATUS BUNDLE CREATED OWNER
mycontainerid 12068 running /mycontainer 2018-12-25T19:45:37.346925609Z
使用 ps 命令看看容器内运行的进程
sudo runc ps mybusybox

3.2 高级命令
使用 state 命令查看容器的状态
sudo runc state mybusybox
使用 ps 命令看看容器内运行的进程
sudo runc ps mybusybox
使用 start 命令执行容器中定义的任务,使用 start 命令启动容器后,
让我们再用 ps 命令看看容器内运行了什么进程
sudo runc start
使用 exec 命令在容器中执行命令
sudo runc exec mybusybox ls
使用 delete 命令删除容器
sudo runc delete mybusybox
使用 kill 命令停止容器中的任务
sudo runc kill mybusybox
使用 pause 命令暂停容器中的所有进程
sudo runc pause mybusybox
执行 pause 命令后,容器的状态由 running 变成了 paused。然后我们再通过 resume 命令恢复容器中进程的执行
sudo runc resume mybusybox
使用 events 命令获取容器的资源使用情况
sudo runc events mybusybox

前面我们运行的所有命令都是以 root 权限执行的。能不能以普通用户的权限运行容器呢?
答案是可以的,并被称为 rootless。
要想以 rootless 的方式运行容器,需要我们在生成容器的配置文件时就为 spec 命令指定 rootless 参数:
runc spec --rootless
并且在运行容器时通过 --root 参数指定一个存放容器状态的路径:
runc --root /tmp/runc run mybusybox
- 容器的热迁移操作,所谓热迁移就是将一个容器进行 checkpoint 操作,并获得一系列文件,使用这一系列文件可以在本机或者其他主机上进行容器的 restore 工作。这也是 checkpoint 和 restore 两个命令存在的原因。热迁移属于比较复杂的操作。
- 目前 runC 使用了 CRIU 作为热迁移的工具。RunC 主要是调用 CRIU(Checkpoint and Restore in Userspace)来完成热迁移操作。CIRU 负责冻结进程,并将作为一系列文件存储在硬盘上。并负责使用这些文件还原这个被冻结的进程。
4 总结
runC 作为标准化容器运行时的一个实现目前已经被 docker 内置为默认的容器运行时,暂时总结于此。
专注于大数据及容器云核心技术解密,可提供全栈的大数据+云原生平台咨询方案,请持续关注本套博客。如有任何学术交流,可随时联系。更多内容请关注《数据云技术社区》公众号。
