12.3 控制組

控制組 (Cgroups) 是 Linux 核心提供的另一種關鍵機制,主要用於資源的限制和審計。

12.3.1 什麼是控制組

控制組 (Control Groups,簡稱 cgroups) 是 Linux 核心的一個屬性,用於 限制、記錄和隔離 程序組的資源使用 (CPU、記憶體、磁碟 I/O、網路等)。

核心作用:讓多個容器公平共享宿主機資源,防止單個容器耗盡系統資源。

flowchart LR subgraph NoLimit ["無 cgroups 限制"] direction TB subgraph HostRes1 ["宿主機資源"] A["容器 A
佔用所有
記憶體和 CPU"] B["容器 B、C 飢餓"] end end subgraph Limit ["有 cgroups 限制"] direction TB subgraph HostRes2 ["宿主機資源"] direction LR C_A["A
1GB
2核"] C_B["B
1GB
1核"] C_C["C
1GB
1核"] end end

12.3.2 cgroups 的歷史

時間 事件
2006 Google 工程師提出 『process containers』 概念
2007 為避免與 Linux 容器概念混淆,更名為 『control groups』 (cgroups)
2008 Linux 2.6.24(2008年1月)正式合併 cgroups v1
2016 Linux 4.5 引入 cgroups v2
現在 Docker 在宿主機支援 cgroups v2 時會自動使用 v2,否則回退到 v1

12.3.3 cgroups 可以限制的資源

資源型別 子系統 說明
CPU cpu, cpuset CPU 使用時間和核心分配
記憶體 memory 記憶體使用上限和 swap
區塊裝置 I/O blkio 磁碟讀寫速度限制
網路 net_cls, net_prio 網路頻寬優先級
程序數 pids 限制程序/執行緒數量

12.3.4 Docker 中的資源限制

Docker 提供了豐富的引數來設定容器的資源限制,主要包括記憶體、CPU、磁碟 I/O 等。

記憶體限制

## 限制容器最多使用 512MB 記憶體

$ docker run -m 512m myapp

## 限制記憶體 + swap

$ docker run -m 512m --memory-swap 1g myapp

## 軟限制(超過時警告,不會 OOM Kill)

$ docker run --memory-reservation 256m myapp
引數 說明
-m / --memory 硬限制 (超過會 OOM Kill)
--memory-swap 記憶體 + swap 總限制
--memory-reservation 軟限制 (記憶體競爭時生效)
--oom-kill-disable 停用 OOM Killer (謹慎使用)

CPU 限制

## 限制使用 1.5 個 CPU 核心

$ docker run --cpus=1.5 myapp

## 限制使用 CPU 0 和 1

$ docker run --cpuset-cpus="0,1" myapp

## 設定 CPU 使用權重(相對值,預設 1024)

$ docker run --cpu-shares=512 myapp
引數 說明
--cpus 限制 CPU 核心數 (如 1.5)
--cpuset-cpus 繫結到特定 CPU 核心
--cpu-shares CPU 時間片權重 (相對值)
--cpu-period / --cpu-quota 精細控制 CPU 配額

磁碟 I/O 限制

## 限制裝置寫入速度為 10MB/s

$ docker run --device-write-bps /dev/sda:10mb myapp

## 限制裝置讀取速度

$ docker run --device-read-bps /dev/sda:10mb myapp

## 限制 IOPS

$ docker run --device-write-iops /dev/sda:100 myapp

程序數限制

## 限制最多 100 個程序

$ docker run --pids-limit=100 myapp

12.3.5 檢視容器資源使用

## 實時監控所有容器的資源使用

$ docker stats
CONTAINER ID   NAME    CPU %   MEM USAGE / LIMIT   MEM %   NET I/O        BLOCK I/O
abc123         web     0.50%   45.5MiB / 512MiB    8.89%   1.2kB / 0B     0B / 0B
def456         db      2.30%   256MiB / 1GiB       25.00%  5.6kB / 3.2kB  4.1MB / 2.3MB

## 檢視特定容器

$ docker stats mycontainer

## 檢視容器的 cgroup 設定

$ docker inspect mycontainer --format '{{json .HostConfig}}' | jq

12.3.6 資源限制的效果

記憶體超限

## 啟動限制 100MB 記憶體的容器

$ docker run -m 100m stress --vm 1 --vm-bytes 200M

## 容器會被 OOM Killer 殺死

$ docker ps -a
CONTAINER ID   STATUS                      NAMES
abc123         Exited (137) 5 seconds ago  hopeful_darwin

## 137 = 128 + 9,表示被 SIGKILL(9) 殺死

...

CPU 限制驗證

## 不限制 CPU

$ docker run --rm stress --cpu 4

## 佔滿所有 CPU

## 限制為 1 個核心

$ docker run --rm --cpus=1 stress --cpu 4

## 只能使用約 100% CPU(1 個核心)

...

12.3.7 cgroups v1 vs v2

屬性 cgroups v1 cgroups v2
層級結構 多層級 (每個資源單獨) 統一層級
管理複雜度 複雜 簡化
資源分配 基於層級 基於子樹
PSI (壓力監控)
rootless 容器 部分支援 完整支援

Docker 對 cgroups v2 的支援

Docker 20.10+ 開始支援 cgroups v2(如果系統支援),提供更好的效能和資源隔離。如果需要明確控制或回退到 v1,可以透過 Docker 守護程序設定檔案 /etc/docker/daemon.json 修改 cgroup-driver 引數:

{
  "cgroup-driver": "systemd"
}

常見的 cgroup-driver 值包括 systemd (推薦) 和 cgroupfs。重啟 Docker 守護程序後生效。

檢查系統使用的版本

## 檢視 cgroup 版本

$ mount | grep cgroup
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)

## 如果顯示 cgroup2 表示 v2

## 或者

$ cat /proc/filesystems | grep cgroup
nodev   cgroup
nodev   cgroup2

12.3.8 在 Compose 中設定限制

在 Compose 中設定限制設定如下:

services:
  web:
    image: nginx
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

12.3.9 最佳實踐

在使用 Cgroups 限制資源時,遵循一些最佳實踐可以避免潛在的問題。

1. 始終設定記憶體限制

## 防止 OOM 影響宿主機

$ docker run -m 1g myapp

2. 為關鍵應用設定 CPU 保證

$ docker run --cpus=2 --cpu-shares=2048 critical-app

3. 監控資源使用

## 配合 Prometheus + cAdvisor 監控

$ docker run -d --name cadvisor \
    -v /:/rootfs:ro \
    -v /var/run:/var/run:ro \
    -v /sys:/sys:ro \
    -v /var/lib/docker:/var/lib/docker:ro \
    ghcr.io/google/cadvisor

第 102 页,共 196 页
使用 mdPress 构建