容器核心技術–CGroup
接上一個小節,我們來試想這樣一個場景:
一臺宿主機的容器中運行了一個監控服務,但監控服務占用了宿主機全部的 CPU 和內存等資源,導致宿主機上的其他服務和容器都被卡死,無法正常運行。
監控類服務不應占用大量資源,無論是什么原因引起的問題,都不應該影響宿主機的正常使用,否則容器的隔離就沒有意義。Namespace 只能做到系統資源維度的隔離,無法做到硬件資源的控制。我們需要使用一種機制 Cgroup,指定容器應用最大占用多少資源。
Linux cgroups 的全稱是 Linux Control Groups,它是 Linux 內核的特性,主要作用是限制、記錄和隔離進程組(process groups)使用的物理資源(CPU、Memory、IO 等)。
1. CGroup 核心概念
前面說過 CGroup 是用來對進程進行資源管理的,因此 CGroup 需要考慮如何抽象這兩種概念:進程和資源,同時如何組織自己的結構。CGroup 機制中有以下幾個基本概念:
- task:任務,對應于系統中運行的一個實體,下文統稱進程;
- subsystem:子系統,具體的資源控制器(resource class 或者 resource controller),控制某個特定的資源使用;
- cgroup:控制組,一組任務和子系統的關聯關系,表示對這些任務進行怎樣的資源管理策略;
- hierarchy:層級樹,由一系列 CGroup 組成的樹形結構。每個節點都是一個 CGroup ,CGroup 可以有多個子節點,子節點默認會繼承父節點的屬性。系統中可以有多個 hierarchy。
Cgroup 機制非常復雜,上面的名詞了解就好,學習 Docker 暫時還不需要深入研究它。
在 Linux 環境中,我們可以執行 ls -al /sys/fs/cgroup/
查看當前系統的 Cgroup:
我們看到目錄中有若干個子目錄,除了 systemd 目錄,其他的一個子目錄對應一個子系統,子系統功能如下所示。
子系統 | 功能 |
---|---|
blkio | 為塊設備,如硬盤等設備,設定輸入輸出限制 |
cpu | 設置 cgroup 中進程的 CPU 被調度的策略 |
cpuacct | 統計 cgroup 中進程的 CPU 占用 |
cpuset | 設置 cgroup 中進程可以使用的 CPU 和內存 |
devices | 控制 cgroup 中進程對設備的訪問 |
freezer | 掛起或者恢復 cgroup 中的進程 |
hugetlb | 用于控制 cgroup 中進程的內存占用,這是一個大頁文件系統。 |
memory | 控制 cgroup 中進程的內存占用,并統計內存資源使用情況。 |
net_cls | 將 cgroup 中進程產生的網絡包分類,允許 Linux 流量控制系統識別從具體 cgroup 中生成的數據包。 |
net_prio | 控制 cgroup 中進程的網絡流量的優先級 |
perf_event | 識別任務的 cgroup 成員,可以用來做性能分析 |
pids | 限制 cgroup 及其所有子孫 cgroup 里面能創建的總的進程數量 |
rdma | 限制 RDMA/IB 資源 |
3. 演示:使用 Cgroup 限制進程 CPU 資源占用
在上面的表格中, 你會發現大量出現Cgroup 中的進程這個描述,原因在于我們必須先掛載子系統,將進程納入 Cgroup 組規則中,然后 Cgroup 機制才能控制這個進程。
我們馬上上手嘗試一下,先安裝stress
sudo dnf install https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/s/stress-1.0.4-16
.el7.x86_64.rpm
Tips:我們使用stress 的軟件進行壓力負載測試,stress 會根據設定,執行一系列消耗系統資源的操作,使得系統在一定的負載下運行。
啟動一個壓力負載測試的進程:
# 產生 1個進程,每個進程都反復不停地計算隨機數的平方根
stress -c 1 > /dev/null &
使用top
命令查看資源占用情況
圖中兩個紅框從左到右分別代表壓力測試的進程號是 1816,CPU 占用百分比 99%,說明壓力測試進程正常生效了。
切換到 root 用戶:
sudo su - root
進入 /sys/fs/cgroup/cpu
這個目錄:
cd /sys/fs/cgroup/cpu
創建一個 Cgroup 組,即在當前目錄下創建一個子目錄:
mkdir testcpu
進入 testcpu 目錄:
cd testcpu
查看 cpu.cfs_period_us
代表時間周期總長度:
cat cpu.cfs_period_us # 100000
將 cpu.cfs_quota_us
設為當前 cgroup 在設置的周期長度內所能使用的 CPU 時間 10000,即總周期100000的 10%:
echo 10000 > cpu.cfs_quota_us
將壓力測試的進程添加到 Cgroup 組的規則中,1816 是stress進程 id:
echo 1816 > tasks
top
查看資源占用,發現 stress 進程的 CPU 占用率被壓到了 10%,說明 Cgroups 對于 CPU 的控制起了效果。
3. 思考
試想一下,我們將本節限制 CPU 資源的操作對象,從 stress 這個程序,改換成前一節的 container,就獲得了一個同時限制了硬件資源和系統資源的容器。
4. 小結
通過本節的介紹,我們對 Cgroup 有了直觀的認知。Cgroup 是個非常強大的系統,容器技術需要使用它進行資源的限制,但這不代表著 Cgroup 只能用于容器技術,比如在云服務商的計費系統中,也有它的身影。
或許你會感覺這一節與上一節 Namespace 的內容有些生僻,別擔心,我們介紹 Namespace 和 CGroup 的目的不是去精通他們的底層原理和使用方法,而是要真正認識到:容器的本質就是一個特殊的進程。