1. 程式人生 > 其它 >Docker 原理探索:cgroups

Docker 原理探索:cgroups

簡介

這是 《容器和容器雲》的閱讀筆記,本文主要關於 cgroups。cgroups 提供了物理資源控制的相關機制,可以控制不同子系統上的資源分配,比如 cpu,記憶體等。cgroups 核心有四個概念。任務,指的是程序或者執行緒。控制組,資源控制以組為單位。子系統,資源排程控制器,比如 CPU 子系統可以控制 CPU 時間分配。層級,cgroups 會有層級,系統預設的 cgroups 裡面會包含所有的任務,通過在這個 cgroups 下面建立不同的子 cgroups 來將不同的任務加入到子 cgroups 來實現分組控制。

cgroups 以檔案系統的方式進行操作,通過操作檔案系統可以進行資源限制,優先順序分配,資源統計,任務控制。換言之,cgroups 的使用方式,就是操作目錄那麼簡單。

規則

前面提到了 cgroups 中的四個重要概念:任務,控制組,子系統,層級。下面分析它們相互間的關係。

  1. 同一層級可以附加多個子系統
  2. 一個子系統可以附加到多個層級,當且僅當目標層級只有一個子系統。
  3. 新建一個層級時,所有任務預設加入新建層級的初始化 cgroup。
  4. 任務只能存在於同個層級中的一個 cgroup,能存在於多個層級中的多個 cgroup
  5. fork/clone 子任務的建立,預設加入父任務的 cgroup。

子系統

子系統可以通過下面的命令列舉,在 /sys/fs/cgroup/ 目錄下面,每個目錄對應一個子系統,每個目錄下面的檔案,代表著子系統的控制配置。通過操作這些檔案,就可以控制對應的資源。比如 cpu.shares

這個檔案,可以控制任務在 CPU 上的執行時間權重,預設是 1024,權重越大,被排程到的機會越大。cgroups 的實現原理,本質上是給任務加上鉤子,當涉及某種資源時,就觸發鉤子上附帶的子系統。cgroup 和任務之間是多對多的關係。

(base) percent1@ubuntu:~$ mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)

Docker 和 cgroups

通過下面的命令,可以建立一個在 cpu 子系統下面的控制組,控制組裡面的檔案,都是 cgroups 自動生成的。只要往 cgroup.procs 裡面寫 pid,就可以將程序加入到對應的控制組裡面。

(base) percent1@ubuntu:~/code$ ls /sys/fs/cgroup/
blkio  cpu  cpuacct  cpu,cpuacct  cpuset  devices  freezer  hugetlb  memory  net_cls  net_cls,net_prio  net_prio  perf_event  pids  rdma  systemd  unified
(base) percent1@ubuntu:/sys/fs/cgroup/cpu$ sudo mkdir cg1
[sudo] password for percent1: 
(base) percent1@ubuntu:/sys/fs/cgroup/cpu$ ls cg1   # 下面這些都是系統生成的
cgroup.clone_children  cpuacct.stat   cpuacct.usage_all     cpuacct.usage_percpu_sys   cpuacct.usage_sys   cpu.cfs_period_us  cpu.shares  notify_on_release
cgroup.procs           cpuacct.usage  cpuacct.usage_percpu  cpuacct.usage_percpu_user  cpuacct.usage_user  cpu.cfs_quota_us   cpu.stat    tasks

Docker 和 cgroups:docker 會在 /sys/fs/cgroup/docker 這個控制組下面,為每個容器建立一個子控制組。比如我們可以使用下面的命令,啟動一個容器。根據容器 id,可以找到對應的目錄,並且在 cpu 子目錄裡面,可以看到 cpu.shares 的權重。

# 終端1 繫結一個容器
(base) root@ubuntu:~/code/cmake_cpp_cuda/build# docker run -it --rm --cpu-shares 10000  busybox
/ # 

# 終端2 可以檢視
(base) percent1@ubuntu:/sys/fs/cgroup/cpu$ docker container ls
...  # 根據 container id 找到對應的目錄
(base) percent1@ubuntu:/sys/fs/cgroup/cpu$ cat docker/71f8e3aef5d17b60ecf7c1fedd0a82227bb1ade4b7da88013e4f2a00132e56a2/cpu.shares 
10000

總結

通過上面的簡單探索,對 cgroups 有一個感性的認識。Docker 使用它來資源限制,優先順序分配,資源統計,任務控制等,核心概念有四個:任務,子系統,控制組,cgroups 層級。