18.2 控制組

控制組 (Cgroups) 是 Linux 容器機制的另外一個關鍵元件。如果說命名空間 (Namespace) 決定了容器能 看到 什麼,那麼控制組就決定了容器能 使用 多少資源。

在安全領域中,資源的不可用性本身就是一種安全威脅。控制組負責實現資源的審計和限制,這對於抵禦資源耗盡型攻擊(如拒絕服務攻擊 DoS)至關重要。

18.2.1 為什麼資源限制關乎安全?

預設情況下,Docker 容器對系統資源的使用是沒有限制的:一個容器理論上可以使用宿主機所有的 CPU 計算能力、吃光所有的記憶體、耗盡所有的系統 PID。

想象一下以下場景:

  • 一個惡意使用者向你暴露在公網的應用發起海量併發請求。
  • 應用程式邏輯中存在記憶體洩漏漏洞。
  • 駭客在入侵容器後,在裡面執行了挖礦木馬程式。

如果沒有 Cgroups 的限制,某個容器內的異常行為(或惡意攻擊)將會榨乾宿主機的資源,導致宿主機上其他健康的容器甚至 Docker 守護程序自身因為 OOM(Out Of Memory)崩潰或 CPU 飢餓而停止回應。

18.2.2 核心資源限制實戰

為了確保多租戶平台(如公有或私有的 PaaS 平台)的穩定性,或者在生產環境防止服務級聯故障,我們要養成在啟動容器時 顯式宣告資源上限 的習慣。

1. 記憶體限制

限制記憶體可以防止應用程式因記憶體洩漏或惡意載荷導致宿主機 OOM。

關鍵引數:

  • -m, --memory="":硬限制,容器可使用的最大記憶體量。
  • --memory-swap="":限制容器可使用的記憶體與 Swap 總量。

實戰範例:

限制容器最多只能使用 512MB 記憶體,並且停用 Swap(將 memory 和 memory-swap 設定成一樣的值即可):

$ docker run -d \
  --name web_app \
  --memory="512m" \
  --memory-swap="512m" \
  nginx:alpine

如果該容器內的應用嘗試分配超過 512MB 的記憶體,該程序將會被核心的 OOM Killer 殺掉,但絕不會波及到宿主機的其他部分。

2. CPU 限制

限制 CPU 可以防止個別計算密集型的容器壟斷 CPU 時間片,保證系統的排程公平性。

關鍵引數:

  • --cpus=<value>:指定容器可以使用的 CPU 核心數量(可以是小數)。
  • -c, --cpu-shares=0:軟限制,設定容器使用 CPU 的相對權重(預設是 1024)。

實戰範例:

限制容器最多使用 1.5 個 CPU 核心的算力:

$ docker run -d \
  --name worker_app \
  --cpus="1.5" \
  busybox \
  md5sum /dev/urandom

即使上面的指令是一個死迴圈的雜湊計算程序,容器也永遠無法吃滿雙核 CPU 系統的全部算力。

3. 程序數限制

程序炸彈(Fork Bomb)是一種典型的拒絕服務攻擊方式,它透過不斷 fork() 新進程來耗盡系統的程序表條目,導致系統無法建立任何新任務。

關鍵引數:

  • --pids-limit=<number>:限制容器內允許建立的最大程序數。

實戰範例:

一個常規的 Web 服務程序數通常在幾十到上百之間。我們可以設定一個合理的上限來防範 Fork 炸彈:

$ docker run -d \
  --name app_service \
  --pids-limit=100 \
  python:alpine python app.py

當容器內的程序總數達到 100 時,任何嘗試派生新進程的操作都會失敗並回傳 Resource temporarily unavailable,從而挫敗相關的攻擊行為。

18.2.3 最佳實踐建議

在生產環境中,不僅要在單機使用 Docker 指令時設定這些引數,更應當在叢集編排工具中將資源配額制度化。

例如,在 Kubernetes 中,強烈建議為每個 Pod 設定 requestslimits

resources:
  requests:
    memory: "256Mi"
    cpu: "250m"
  limits:
    memory: "512Mi"
    cpu: "500m"

透過 Cgroups 的資源邊界控制,你可以從根本上切斷一條導致整個系統雪崩的脆弱鏈路。這也進一步使得 Docker 以及容器技術成為了現代高可用服務的基礎設施首選。

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