走進docker(04):什麼是容器的runtime?

咱們都知道runc是容器runtime的一個實現,那到底什麼是runtime?包含了哪些內容?linux

容器的runtime和image同樣,也有標準,也由OCI (Open Containers Initiative)負責維護,地址爲Runtime Specification,瞭解runtime標準有利於咱們更好的理解docker和runc的關係,本文將對該標準作一個簡單的解釋。git

規範內容

在Linux平臺上,跟runtime有關的規範主要有四個,分別是Runtime and Lifecycle (runtime.md)Container Configuration file (config.md)Linux Container Configuration (config-linux.md)Linux Runtime (runtime-linux.md) .github

除了這四個以外,還有一個Filesystem Bundle (bundle.md)redis

下面分別介紹這些規範。docker

Filesystem Bundle

上一篇中,已經用過bundle了,hello-world的bundle看起來是這個樣子的:json

dev@debian:~/images$ tree hello-world-bundle
hello-world-bundle
├── config.json
└── rootfs
    └── hello

1 directory, 2 files

bundle中包含了運行容器所須要的全部信息,有了這個bundle後,符合runtime標準的程序(好比runc)就能夠根據bundle啓動容器了。segmentfault

bundle包含一個config.json文件和容器的根文件系統目錄,config.json就是後面要介紹的Container Configuration file,標準要求該配置文件必須叫這個名字,不過對容器的根文件系統目錄沒有要求,只要在config.json裏面將路徑配置正確就能夠了,不過通常約定俗成都叫rootfs。安全

實際使用過程當中,根文件系統目錄可能在其它的地方,只要config.json裏面配置正確的路徑就能夠了,但若是bundle須要打包和其它人分享的話,必須將根文件系統和config.json打包在一塊兒,而且不包含外層的文件夾。bash

Container Configuration file

該規範定義了上面介紹的config.json裏面應該包含哪些內容,字段不少,這裏不一一詳細介紹,只簡單說明一下,完整的示例請參考這裏網絡

  • ociVersion(必須):對應的OCI標準版本

  • root(必須):根文件系統的位置

  • mounts:須要掛載哪些目錄到容器裏面。若是是Linux平臺,這裏面必需要包含/proc、/sys,/dev/pts,/dev/shm這四個目錄

  • process:容器啓動後執行什麼命令

  • hostname:容器的主機名,相關原理可參考UTS namespace (CLONE_NEWUTS)

  • platform(必須):平臺信息,如 amd64 + Linux

  • linux:Linux平臺的特殊配置,這裏包含下面要介紹的Linux Container Configuration裏面的內容

  • hooks:配置容器運行生命週期中會調用的hooks,包括prestart、poststart和poststop,容器的生命週期見後面Runtime and Lifecycle介紹。

  • annotations:容器的註釋,至關於容器標籤,key:value格式

Linux Container Configuration

該規範是Linux平臺上對Container Configuration file的擴展,這部分的內容也包含在上面的config.json文件中。

  • namespaces: namespace相關的配置,相關原理可參考Namespace概述及這些namespace(UTSIPCmountpidnetworkuser 1user 2)。

  • uidMappings,gidMappings:配置主機和容器用戶/組之間的對應關係,原理可參考user namespace

  • devices:設置哪些設備能夠在容器內被訪問到。除了這裏指定的設備外,/dev/null、/dev/zero、/dev/full、/dev/random、/dev/urandom、/dev/tty、/dev/console(若是在process的配置裏面啓動terminal的話)和/dev/ptmx這些設備默認就能在容器內訪問到,即runtime的實現須要默認將這些設備bind到容器內,dev/tty和/dev/ptmx的原理能夠參考TTY/PTS概述

  • cgroupsPath:cgroup的路徑,可參考Cgroup概述

  • resources:Cgroup中具體子項的配置,包括device whitelist, memory, cpu, blockIO, hugepageLimits, network(net_cls cgroupnet_prio cgroup), pids

  • intelRdt:和Intel Resource Director Technology有關

  • sysctl:調整容器運行時的kernel參數,主要是一些網絡參數,由於每一個network namespace都有本身的協議棧,因此能夠修改本身協議棧的參數而不影響別人

  • seccomp:和安全相關的配置,見Seccomp

  • rootfsPropagation:設置Propagation類型。能夠參考Shared subtrees

  • maskedPaths:設置容器內的哪些目錄對用戶不可見

  • readonlyPaths:設置容器內的哪些目錄是隻讀的

  • mountLabel:和Selinux有關。

Runtime and Lifecycle

該規範主要定義了跟容器運行時相關的三部份內容,容器的狀態、容器相關的操做以及容器的生命週期。

容器的狀態

當查詢容器的狀態時,返回的狀態裏面至少包含以下信息:

{
    "ociVersion": "0.2.0",
    "id": "oci-container1",
    "status": "running",
    "pid": 4422,
    "bundle": "/containers/redis",
    "annotations": {
        "myKey": "myValue"
    }
}
  • ociVersion (必須): 建立該容器時使用的OCI runtime的版本

  • id (必須): 容器ID,本機全局惟一

  • status (必須): 容器的運行時狀態,包含以下狀態:

    creating: 建立中
    created: 建立完成
    running: 運行中
    stopped: 運行結束
    
    實現runtime時能夠包含更多的狀態,但不能改變這幾個狀態的含義
  • pid (容器是running狀態時必須): 容器內第一個進程在系統初始pid namespace中的pid,即在容器外面看到的pid

  • bundle (REQUIRED): bundle所在位置的絕對路徑。bundle裏面包含了容器的配置文件和根文件系統。

  • annotations: 容器的註釋,至關於容器標籤,來自於容器的配置文件,key:value格式。

容器相關的操做

該部分定義了一個符合runtime標準的實現(如runc)至少須要實現下面這些命令:

  • state: 返回容器的狀態,包含上面介紹的那些內容.

  • create: 建立容器,這一步執行完成後,容器建立完成,修改bundle中的config.json將再也不對已建立的容器產生影響

  • start: 啓動容器,執行config.json中process部分指定的進程

  • kill: 經過給容器發送信號來中止容器,信號的內容由kill命令的參數指定

  • delete: 刪除容器,若是容器正在運行中,則刪除失敗。刪除操做會刪除掉create操做時建立的全部內容。

容器的生命週期

這裏以runc爲例,說明容器的生命週期

  1. 執行命令runc create建立容器,參數中指定bundle的位置以及容器的ID,容器的狀態變爲creating

  2. runc根據bundle中的config.json,準備好容器運行時須要的環境和資源,但不運行process中指定的進程,這步執行完成以後,表示容器建立成功,修改config.json將再也不對建立的容器產生影響,這時容器的狀態變成created。

  3. 執行命令runc start啓動容器

  4. runc執行config.json中配置的prestart鉤子

  5. runc執行config.json中process指定的程序,這時容器狀態變成了running

  6. runc執行poststart鉤子。

  7. 容器因爲某些緣由退出,好比容器中的第一個進程主動退出,掛掉或者被kill掉等。這時容器狀態變成了stoped

  8. 執行命令runc delete刪除容器,這時runc就會刪除掉上面第2步所作的全部工做。

  9. runc執行poststop鉤子

Linux Runtime

該規範是Linux平臺上對Runtime and Lifecycle的補充,目前該規範很簡單,只要求容器運行起來後,裏面必須創建下面這些軟鏈接:

# ls -l /dev/fd /dev/std*
lrwxrwxrwx    1 root     root            13 May  4 12:32 /dev/fd -> /proc/self/fd
lrwxrwxrwx    1 root     root            15 May  4 12:32 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx    1 root     root            15 May  4 12:32 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx    1 root     root            15 May  4 12:32 /dev/stdout -> /proc/self/fd/1

結束語

簡單點說,docker負責準備runtime的bundle,而runc負責運行該bundle,並管理容器的整個生命週期。

但對於docker來講,並非只要準備好根文件系統和配置文件就能夠了,好比對於網絡,runtime沒有作任何要求,只要在config.json中指定network namespace就好了(不指定就新建一個),而至於這個network namespace裏面有哪些東西則徹底由docker負責,docker須要保證新network namespace裏面有合適的設備來和外界通訊。

參考

相關文章
相關標籤/搜索