RunC 簡介


RunC 是什么?

RunC 是一個輕量級的工具,它是用來運行容器的,只用來做這一件事,並且這一件事要做好。我們可以認為它就是個命令行小工具,可以不用通過 docker 引擎,直接運行容器。事實上,runC 是標准化的產物,它根據 OCI 標准來創建和運行容器。而 OCI(Open Container Initiative)組織,旨在圍繞容器格式和運行時制定一個開放的工業化標准。

安裝 runC

RunC 是用 golang 創建的項目,因此編譯它之前需要在本地安裝 golang 的開發環境。Golang 的安裝請參考《Golang 入門 : 打造開發環境》一文,這里不再贅述。

安裝 libseccomp-dev

RunC 默認的編譯配置是支持 seccomp 的,所以我們需要先安裝 libseccomp-dev:

$ sudo apt install libseccomp-dev

seccomp 的全稱為 secure computing mode,即安全計算模型,這是 Linux 內核提供的功能。我們可以通過它來限制容器中進程的行為。關於 seccomp 的更多內容,請參考 Seccomp security profiles for Docker

獲取 runC 的代碼

先創建 $GOPATH/src/github.com 目錄:

$ mkdir -p $HOME/go/src/github.com

通過 go get 命令就可以從 github 上下載到 runC 的代碼,但是要保證事先安裝了 git:

$ go get github.com/opencontainers/runc

然后進入 $HOME/go/src/github.com/opencontainers/runc 目錄,並 checkout 最新的穩定狀態的代碼 tag v1.0.0-rc5:

$ cd $HOME/go/src/github.com/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

前面我們運行的所有命令都是以 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 作為默認的容器運行時。

參考:
Runc Github
OCI和runc容器標准化和docker
OCI標准和runC原理解讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM