RunC简介
RunC 是什么?
RunC 是⼀个轻量级的⼯具,它是⽤来运⾏容器的,只⽤来做这⼀件事,并且这⼀件事要做好。我们可以认为它就是个命令⾏⼩⼯具,可以不⽤通过docker 引擎,直接运⾏容器。事实上,runC 是标准化的产物,它根据 OCI 标准来创建和运⾏容器。⽽组织,旨在围绕容器格式和运⾏时制定⼀个开放的⼯业化标准。
安装 runC
RunC 是⽤ golang 创建的项⽬,因此编译它之前需要在本地安装 golang 的开发环境。Golang 的安装请参考《》⼀⽂,这⾥不再赘述。
安装 libseccomp-dev
RunC 默认的编译配置是⽀持 seccomp 的,所以我们需要先安装 libseccomp-dev:
$ sudo apt install libseccomp-dev
seccomp 的全称为 secure computing mode,即安全计算模型,这是 Linux 内核提供的功能。我们可以通过它来限制容器中进程的⾏为。关于seccomp 的更多内容,请参考。
获取 runC 的代码
先创建 $GOPATH/src/github ⽬录:
$ mkdir -p $HOME/go/src/github
通过 go get 命令就可以从 github 上下载到 runC 的代码,但是要保证事先安装了 git:
$ go get github/opencontainers/runc
然后进⼊ $HOME/go/src/github/opencontainers/runc ⽬录,并 checkout 最新的稳定状态的代码 tag v1.0.0-rc5:
$ cd $HOME/go/src/github/opencontainers/runc
$ git checkout v1.0.0-rc5
查看代码当前的状态:
$ git status
v1.0.0-rc5 是当前最新的版本。
编译并安装
$ make
$ sudo make install
如上图所⽰,runC 被安装在了 /usr/local/sbin/runc ⽬录。
可以通过 -v 选项查看⼀下版本号:
$ runc -v
⾄此,runC 就算是安装成功了。
准备 OCI bundle
RunC 是运⾏容器的运⾏时,它负责利⽤符合标准的⽂件等资源运⾏容器,但是它不包含 docker 那样的镜像管理功能。所以要⽤ runC 运⾏容器,我们先得准备好容器的⽂件系统。所谓的 OCI bundle 就是指容器的⽂件系统和⼀个 config.json ⽂件。有了容器的⽂件系统后我们可以通过 runc spec 命令来⽣成 config.json ⽂件。使⽤ docker 可轻松的⽣成容器的⽂件系统,因为 runC 本来就是 docker 贡献给社区的嘛!
下⾯我们准备⼀个运⾏ busybox 容器所需的⽂件系统:
$ docker pull busybox
$ mkdir -p /tmp/mycontainer/rootfs
$ cd /tmp/mycontainer
$ docker export $(docker create busybox) | tar -C rootfs -xvf -
现在 rootfs ⽬录下就是 busybox 镜像的⽂件系统,然后⽣成 config.json ⽂件:
$ runc spec
如果直接使⽤⽣成的 config.json,接下来的演⽰不会太流畅,所以简单起见,我们稍微修改⼀下刚刚⽣成的 config.json ⽂件。就是把 "terminal": true 改为 false,把 "args": ["sh"] 改为 "args": ["sleep", "30"]:
理解容器状态转移
在运⾏ busybox 容器前让我们先来看看 OCI 都定义了哪⼏种容器状态,以及这些状态是如何转移的。先看容器的状态:creating:使⽤ create 命令创建容器,这个过程称为创建中。
created:容器已经创建出来,但是还没有运⾏,表⽰镜像⽂件和配置没有错误,容器能够在当前平台上运⾏。
running:容器⾥⾯的进程处于运⾏状态,正在执⾏⽤户设定的任务。
stopped:容器运⾏完成,或者运⾏出错,或者 stop 命令之后,容器处于暂停状态。这个状态,容器还有很多信息保存在平台中,并没有完全被删除。
paused:暂停容器中的所有进程,可以使⽤ resume 命令恢复这些进程的执⾏。
下图则是对容器不同状态间转移的⼀个粗略描述:
RunC 命令
要想了解 runC 都能⼲什么,最好是通过它提供的命令来操作容器。下⾯是笔者整理的 runC 命令的主要使⽤场景。
查看帮助
$ runc -h
查看⼦命令的帮助
$ runc help subcommand
使⽤ create 命令创建容器
进⼊到 /tmp/mycontainer ⽬录中:
$ cd /tmp/mycontainer
然后创建名为 mybusybox 的容器:
$ sudo runc create mybusybox
使⽤ list 命令查看当前存在的容器
$ sudo runc list
使⽤ state 命令查看容器的状态
$ sudo runc state mybusybox
注意图中的 "status": "created",当通过 create 成功创建了容器后,容器的状态就是 "created"。
使⽤ ps 命令看看容器内运⾏的进程
$ sudo runc ps mybusybox
此时 mybusybox 容器内有⼀个名为 init 的进程在运⾏。
使⽤ start 命令执⾏容器中定义的任务
$ sudo runc start
使⽤ start 命令启动容器后,让我们再⽤ ps 命令看看容器内运⾏了什么进程:
此时我们在 config.json 中定义的 sleep 进程在运⾏。再⽤ state 命令看看容器此时的状态,此时已经变成了 running!
使⽤ exec 命令在容器中执⾏命令
通过 exec 命令我们可以在处于 created 状态和 running 状态的容器中执⾏命令:
$ sudo runc exec mybusybox ls
当容器中的⽤户任务结束后,容器会变成 stopped 状态,这时就不能再通过 exec 执⾏其它的命令了。
使⽤ delete 命令删除容器
我们可以通过 delete 命令删除容器,当然,⼀般情况下是删除 stopped 状态的容器:
$ sudo runc delete mybusybox
使⽤ run 命令创建并运⾏容器
就像 docker run 命令⼀样,它会创建容器并运⾏容器中的命令:
$ sudo runc run mybusybox
当容器中的命令退出后容器随即被删除。
使⽤ kill 命令停⽌容器中的任务
如果要停⽌⼀个容器中正在运⾏的任务,可以使⽤ kill 命令:
$ sudo runc kill mybusybox
默认它会优雅的结束容器中的进程,但是碰到特殊情况,你就得使⽤终极信号 9:
$ sudo runc kill mybusybox 9
使⽤ pause 命令暂停容器中的所有进程
我们先启动容器 mybusybox,然后⽤ pause 命令暂停它:
$ sudo runc pause mybusybox
执⾏ pause 命令后,容器的状态由 running 变成了 paused。然后我们再通过 resume 命令恢复容器中进程的执⾏:$ sudo runc resume mybusybox
此时容器的状态⼜恢复到了 running。
使⽤ events 命令获取容器的资源使⽤情况
events 命令能够向我们报告容器事件及其资源占⽤的统计信息:
$ sudo runc events mybusybox
rootless containers
container容器用法前⾯我们运⾏的所有命令都是以 root 权限执⾏的。能不能以普通⽤户的权限运⾏容器呢?答案是可以的,并被称为 rootless。要想以 rootless 的⽅式运⾏容器,需要我们在⽣成容器的配置⽂件时就为 spec 命令指定 rootless 参数:
$ runc spec --rootless
并且在运⾏容器时通过 --root 参数指定⼀个存放容器状态的路径:
$ runc --root /tmp/runc run mybusybox
容器的热迁移操作
RunC ⽀持容器的热迁移操作,所谓热迁移就是将⼀个容器进⾏ checkpoint 操作,并获得⼀系列⽂件,使⽤这⼀系列⽂件可以在本机或者其他主机上进⾏容器的 restore ⼯作。这也是 checkpoint  和 restore 两个命令存在的原因。热迁移属于⽐较复杂的操作,⽬前 runC 使⽤了 CRIU 作为热迁移的⼯具。RunC 主要是调⽤ CRIU(Checkpoint and Restore in Userspace)来完成热迁移操作。CIRU 负责冻结进程,并将作为⼀系列⽂件存储在硬盘上。并负责使⽤这些⽂件还原这个被冻结的进程。
总结
RunC 作为标准化容器运⾏时的⼀个实现⽬前已经被 docker 内置为默认的容器运⾏时。相信随着 runC ⾃⾝的成熟和完善会有越来越多的⼤⼚把runC 作为默认的容器运⾏时。
参考:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。