本文最后更新于 2025-07-13,文章内容可能已经过时。

CPU 配额

Docker 使用 cgroup 来管理容器使用的 CPU、内存、磁盘资源限额。

权重方式

--cpu-shares ​或者 -c​参数可以为容器设置指定的权重值。容器默认的权重值为 1024。当多个容器竞争 CPU 资源时,权重越高的容器将获得更多的 CPU 调度时间。

例如容器 A 的权重值为 1024,容器 B 的权重值为 512,则容器 A 与容器 B 在 CPU 资源竞争时,容器 A 所获得的 CPU 调度时间是容器 B 的两倍。

cgroup 只有多个容器同一时间在竞争同一个 CPU 资源时,CPU 配额才会生效。

启动一个容器,然后将其 cpu 配额设置为 512。

docker run -it --cpu-shares 512 busybox /bin/sh

在容器内部使用 cat /sys/fs/cgroup/cpu/cpu.shares​查看 CPU 配额

核心控制

使用 --cpuset 使容器绑定到特定的 CPU 内核和内存节点上运行

--cpuset-cpus

--cpuset-mems

当两个容器使用 --cpuset 分别绑到了不同 CPU 上,例如容器 A 绑到 cpu1、容器 B 绑到 cpu2 上,由于容器 A 和容器 B 不会争夺同一个 CPU 资源,所以设置的 CPU 配额并不会生效,只有两个容器绑到同一个 CPU 时,CPU 配额才会生效。

压测

创建两个容器,分别为容器 container​A 和容器 container​B,两个容器都绑定 cpu0 和 cpu1,其中容器 A 的 CPU 权重为 1024、容器 B 的 CPU 权重为 512。

前提是服务器或者本地虚拟机 cpu 核心数要多于一个(建议 2 核以上,因为后面压测两个 cpu 时,如果你只有 2 核,那就会卡死😂),可以使用 lscpu 查看当前服务器的 cpu 核数

CPU(s):                   4
  On-line CPU(s) list:    0-3

也可以使用 top 命令,然后按 1️⃣键显示 CPU 信息

docker run -itd --name containerA --cpu-shares 1024 --cpuset-cpus 0,1 alpine /bin/sh
docker run -itd --name containerB --cpu-shares 512 --cpuset-cpus 0,1 alpine /bin/sh

先进入 containerB 容器安装 stress-ng(alpine 中没有 stress,所以用 stress-ng) 压测工具,容器 A 也重复这步。

docker exec -it containerB /bin/sh
apk update
apk add stress-ng

分别在两个容器中运行 stress-ng 进行压测。

stress-ng --cpu 2 --timeout 30000s

我们可以看到 CPU0 和 CPU1 跑满了,但是其他 CPU 没有受到影响。

在进程中出现了 4 条关于 stress-ng 的进程,我们可以使用 cat /proc/PID(替换为具体的PID)/cgroup​命令查看进程所属容器,例如

cid=$(cat /proc/PID(替换为具体的PID)/cgroup | grep 'docker' | awk -F/ '{print $3}')
docker ps --no-trunc --format '{{.ID}} {{.Names}}' | grep "$cid"

可以使用一个脚本实现输出,创建一个 pid2name.sh 文件,内容如下

#!/bin/bash

# 获取 stress-ng-cpu 进程列表
ps -eo pid,comm,%cpu --no-headers | awk '$2=="stress-ng-cpu"{print $1, $3}' | while read pid cpu; do
  # 提取容器 ID(Docker cgroup)
  cid=$(awk -F/ '/docker/{print $3}' /proc/$pid/cgroup 2>/dev/null)

  # 如果找到了容器 ID
  if [ -n "$cid" ]; then
    # 获取容器名
    cname=$(docker ps -a --no-trunc --format '{{.ID}} {{.Names}}' | grep "$cid" | awk '{print $2}')
  else
    cname="host"  # 非容器进程
  fi

  echo "PID: $pid | CPU: $cpu% | Container: $cname"
done

输出结果如下

PID: 438781 | CPU: 65.2% | Container: containerA
PID: 438782 | CPU: 65.5% | Container: containerA
PID: 438138 | CPU: 32.4% | Container: containerB
PID: 438139 | CPU: 32.4% | Container: containerB

可以看到 containerA 容器的 CPU 使用率始终为 containerB 的两倍

内存控制

docker 可以使用 --memory 或者 -m 参数实现容器内存使用量的控制

例如:

docker run -itd --name containerA -m 512m alpine /bin/sh

containerA 容器只能使用 512M 的内存。

IO 控制

--device-write-bps {设备名:值}​ 限制容器的写速度。

--device-read-bps {设备名:值}​限制容器的读速度。单位可以是 kb、mb、gb