天天看點

docker 原理之runC(3)

轉自http://www.cnblogs.com/yanjingnan/p/6473831.html

Docker, Containerd, RunC :

從 Docker 1.11 開始, docker 容器運作已經不是簡單地通過 Docker Daemon 來啟動, 而是內建了Container, RunC 等多個元件.

Docker 服務啟動之後, 可以看到系統上啟動了 Docker, Docker-container 等程序. 以下介紹 docker(1.11 版本之後每個部分的功能和作用.)

OCI 标準

Linux基金會于2015年6月成立OCI(Open Container Initiative)組織,旨在圍繞容器格式和運作時制定一個開放的工業化标準。該組織一成立便得到了包括谷歌、微軟、亞馬遜、華為等一系列雲計算廠商的支援。而runC就是Docker貢獻出來的,按照該開放容器格式标準(OCF, Open Container Format)制定的一種具體實作。

docker 子產品結構

從Docker 1.11之後,Docker Daemon被分成了多個子產品以适應OCI标準。

docker 原理之runC(3)

docker daemon : 獨立成單獨二進制程式.

docker 1.8 之前, 啟動會指令:

docker 1.8 之後, 啟動指令變成了 :

$ docker daemon
           

docker 1.11 開始, 啟動指令變成了 :

$ dockerd
           

containerd

containerd 是運用 runC(或者任何與 OCI 相容的程式)來管理容器,通過 gRPC 暴露功能的簡易守護程序。相比于 Docker Engine,暴露容器相關的 CRUD 接口使用成熟的 HTTP API,Docker Engine 不僅能暴露容器,還能暴露鏡像、資料卷、網絡、建構等。

containerd 是容器技術标準化之後的産物, 為了能夠相容 OCI 标準, 将容器運作時及其管理功能從 Docker Daemon 剝離.

理論上, 即使不運作 dockerd 也能直接通過 containerd 來管理容器.(當然, containerd 本身也隻是一個守護程序, 容器的實際運作時由 runC 控制.)

container(已開源), 其主要職責是鏡像管理(鏡像, 元資訊等), 容器執行(調用最終運作時元件執行).

container 向上為 docker daemon 提供了 gRPC 接口, 使得 docker daemon 屏蔽下面的結構變化, 確定原有接口向下相容. 向下通過 container-shim 結合 runC, 使得引起可以獨立更新, 避免之前 docker daemon 更新會導緻所有容器不可用的問題.(見上面 docker_mod_arch 圖)

docker 原理之runC(3)
docker , container , container-shim 之間的關系, 可以通過啟動一個 docekr 容器觀察之間的管理.

① 啟動一個容器:
    $ docker run -d alpine sleep 
② 檢視docker daemon 的pid
    $ ps aux |grep dockerd  # 1480
③ 檢視程序之間的父子關系
    $ pstree -l -a -A 
        dockerd -H fd://
          |-docker-containe -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc
          |   |-docker-containe b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626 /var/run/docker/libcontainerd/b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626 docker-runc
          |   |   |-sleep 
          |   |   `*[{docker-containe}]
          |   `*[{docker-containe}]
          `*[{dockerd}]              

    當 docker daemon 啟動之後, docker 和 docker-container 程序一直存在.
    當啟動容器之後, docker-container 程序(container 元件)會建立 docker-containerd-shim 程序. 其中 b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626 就是要啟動容器的 ID, 最後 docker-containerd-shim 子程序, 液晶是在容器中運作的程序(sleep )

    其中 /var/run/docker/libcontainerd/b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626 裡面内容有 : 
        /var/run/docker/libcontainerd/b9251bcc7a4484662c8b69174d92b3183f0f09a59264b412f14341ebb759626
        ├── config.json         # 容器配置
        ├── init-stderr         # 标準錯誤輸出
        ├── init-stdin          # 标準輸入
        └── init-stdout         # 标準輸出.     
           

RunC

unC 是一種隻專注于運作容器的輕量級工具。如果你了解 Docker Engine 的早期曆史,你就知道它曾經用 LXC 來啟動和管理容器;後來它演變為 “libcontainer”。“libcontainer” 是一段與 cgroup 和 namespace 這些 Linux 核心互動的代碼,這些核心是容器建構的基石。

簡言之,runC 基本上是一種無需進入 Docker Engine,直接控制 libcontainer 的小型指令行工具,是一種管理和運作 OCI 容器的單機二進制.

OCI 定義了容器運作時标準, runC 是 Docker 按照 開放容器格式标準(OCF, Open Container Format) 制定的一種具體實作.

runC 是從 Docker 的 libcontainer 中遷移而來的, 實作了容器啟停,資源隔離等功能. Docker 預設提懂了 docekr-runc 實作, 事實上, 通過 containerd 的瘋轉, 可以在 Docker daemon 啟動的時候指定 runC 的實作.

可以通過在啟動 docker daemon 時, 增加 --add-runtime 參數來選擇其他的 runC 實作.
    $ docker daemon --add-runtime "custom=/usr/local/bin/my-runc-replacement"
           

runC 特征 :

1. 支援所有的Linux namespaces,包括user namespaces。目前user namespaces尚未包含。
2. 支援Linux系統上原有的所有安全相關的功能,包括Selinux、 Apparmor、seccomp、cgroups、capability drop、pivot_root、 uid/gid dropping等等。目前已完成上述功能的支援。
3. 支援容器熱遷移,通過CRIU技術實作。目前功能已經實作,但是使用起來還會産生問題。
4. 支援Windows 10 平台上的容器運作,由微軟的工程師開發中。目前隻支援Linux平台。
5. 支援Arm、Power、Sparc硬體架構,将由Arm、Intel、Qualcomm、IBM及整個硬體制造商生态圈提供支援。
6. 計劃支援尖端的硬體功能,如DPDK、sr-iov、tpm、secure enclave等等。
7. 生産環境下的高性能适配優化,由Google工程師基于他們在生産環境下的容器部署經驗而貢獻。
           

example : 通過 docker 一些指令, 實作不使用 docker daemon 直接運作一個鏡像.

① 建立容器标準包, 由 container 的 bundle 子產品實作, 将 docker 鏡像轉換成容器标準包
    $ mkdir my_container
    $ cd my_container
    $ mkdir rootfs
    $ docker export $(docker create busybox) | tar -C rootfs -xvf -

    上述指令, 将 busybox 鏡像解壓縮到指定的 rootfs 目錄中. 如果本地不存在 busybox 進香港, containerd 會通過 distribution 子產品去遠端倉庫拉取.

② 建立配置檔案
    $ docker-runc spec

    # 會生成一個 config.json 的配置檔案, 該檔案和 docker 容器的配置檔案類似, 主要包含容器挂載資訊, 平台資訊, 程序資訊等容器啟動以來的所有資料.

③ 通過 runc 指令來啟動容器
    $ apt install runc -y
    $ runc run busybox
           

docker-proxy

docker 的端口轉發工具. 實作容器與主機的端口映射.

示例 :

$ docker run -itd -p : busybox /bin/sh 

$ ps aux |grep docker       # 注意檢視 docker-proxy 的端口對應.

    root              ?        Ssl  月   : docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc

    root               ?        Sl   :   : /usr/bin/docker-proxy -proto tcp -host-ip  -host-port  -container-ip  -container-port 

    root              ?        Sl   :   : docker-containerd-shim fb8a54ea5d7483ca353c95ed91cba3f2e18ce4b2af286bbc6c3412b /var/run/docker/libcontainerd/fb8a54ea5d7483ca353c95ed91cba3f2e18ce4b2af286bbc6c3412b docker-runc

docker-proxy 指令行

$ docker-proxy --help
    Usage of docker-proxy:
      -container-ip string
            container ip
      -container-port int
            container port (default )
      -host-ip string
            host ip
      -host-port int
            host port (default )
      -proto string
            proxy protocol (default "tcp")
           

繼續閱讀