2. Docker 资源限制基础:CPU、内存、磁盘IO、网络带宽限制的核心概念与cgroup原理

2.1 为什么需要资源限制?

在 Docker 容器化部署中,多个容器共享宿主机的操作系统内核与硬件资源。如果没有资源限制,一个异常容器(如内存泄漏、CPU 死循环)可能耗尽宿主机资源,导致其他业务容器甚至宿主机本身不可用。资源限制是保障多租户隔离、服务稳定性与可预测性的第一道防线。

核心目标: 通过 cgroup(Control Group)机制,对每个容器的 CPU、内存、磁盘 I/O、网络带宽进行配额控制,实现“有限资源下的公平调度与故障隔离”。

2.2 cgroup 原理概述

cgroup 是 Linux 内核提供的一种资源管理机制,Docker 通过它实现资源限制。cgroup 将进程(容器内的所有进程)组织成层级化的控制组,并为每个组设置资源配额。Docker 在创建容器时,会在 /sys/fs/cgroup/ 下为容器创建对应的子目录,写入限制参数。

cgroup 层级结构与 Docker 资源限制原理 宿主机 cgroup 根 cpu 子系统 memory 子系统 blkio 子系统 net_prio 子系统 docker 容器组 docker 容器组 docker 容器组 docker 容器组 容器 A 容器 B 容器 C 容器 D 说明: 每个子系统独立管理一种资源。Docker 为每个容器在 cpu、memory、blkio 等子系统下创建子 cgroup。 容器退出后,对应的 cgroup 目录自动清理。通过 /sys/fs/cgroup/<subsystem>/docker/<container_id>/ 可查看实时限制。

2.3 CPU 资源限制

Docker 通过 --cpus、--cpu-shares、--cpuset-cpus 等参数控制容器 CPU 使用。底层对应 cgroup 的 cpu 子系统。

参数 cgroup 文件 说明 典型场景
--cpus cpu.cfs_quota_us / cpu.cfs_period_us 限制容器最多使用多少个 CPU 核心(支持小数,如 1.5) 精确控制 CPU 上限,防止单容器占满所有核心
--cpu-shares cpu.shares 设置 CPU 权重(相对值,默认 1024),仅在 CPU 竞争时生效 保证高优先级容器获得更多 CPU 时间片
--cpuset-cpus cpuset.cpus 将容器绑定到指定的物理 CPU 核心(如 0-3) NUMA 优化、低延迟应用、避免 CPU 缓存抖动
实践建议: 生产环境优先使用 --cpus 进行硬限制,配合 --cpu-shares 做软优先级。避免单独使用 --cpu-shares 作为唯一限制手段,因为它在 CPU 空闲时允许容器突破权重。

CPU 限制示例

# 限制容器最多使用 2.5 个 CPU 核心
docker run --cpus="2.5" nginx

# 设置 CPU 权重为 2048(默认 1024),竞争时获得更多时间片
docker run --cpu-shares=2048 nginx

# 绑定到 CPU 核心 0 和 1
docker run --cpuset-cpus="0,1" nginx

2.4 内存资源限制

内存限制通过 --memory(硬限制)和 --memory-swap(交换分区限制)实现,对应 cgroup 的 memory 子系统。当容器内存使用超过硬限制时,内核会触发 OOM Killer 终止容器进程。

参数 cgroup 文件 说明 注意事项
--memory / -m memory.limit_in_bytes 容器最大可用物理内存(如 512m、2g) 超过此值触发 OOM
--memory-swap memory.memsw.limit_in_bytes 物理内存 + 交换分区的总量上限 默认与 --memory 相同(禁用 swap)
--memory-reservation memory.soft_limit_in_bytes 内存软限制,当宿主机内存紧张时尽力保证 不保证严格限制,仅作为调度提示
--oom-kill-disable memory.oom_control 禁止 OOM Killer 杀死容器进程 需配合 --memory 使用,否则可能耗尽宿主机内存
OOM 风险: 设置 --memory 但不设置 --memory-swap 时,Docker 默认禁用 swap,容器内存达到硬限制后立即 OOM。对于 Java、Node.js 等内存密集型应用,建议预留 20%-30% 的缓冲空间。

内存限制示例

# 限制物理内存 512MB,禁用 swap
docker run -m 512m nginx

# 限制物理内存 1GB,swap 上限 512MB(总计 1.5GB)
docker run -m 1g --memory-swap 1.5g nginx

# 设置软限制 2GB,硬限制 4GB
docker run -m 4g --memory-reservation 2g nginx

2.5 磁盘 I/O 资源限制

磁盘 I/O 限制通过 --blkio-weight、--device-read-bps、--device-write-iops 等参数实现,对应 cgroup 的 blkio 子系统。支持按设备(如 /dev/sda)分别限制读写速率。

参数 cgroup 文件 说明 单位
--blkio-weight blkio.weight 块设备 I/O 权重(10-1000,默认 500) 相对值
--device-read-bps blkio.throttle.read_bps_device 限制设备读取速率(字节/秒) kb、mb、gb
--device-write-bps blkio.throttle.write_bps_device 限制设备写入速率(字节/秒) kb、mb、gb
--device-read-iops blkio.throttle.read_iops_device 限制设备读取 IOPS 次/秒
--device-write-iops blkio.throttle.write_iops_device 限制设备写入 IOPS 次/秒

磁盘 I/O 限制示例

# 设置 blkio 权重为 800(高优先级)
docker run --blkio-weight 800 nginx

# 限制 /dev/sda 读取速率 50MB/s,写入速率 30MB/s
docker run --device-read-bps /dev/sda:50mb --device-write-bps /dev/sda:30mb nginx

# 限制 /dev/sda 读取 IOPS 为 1000,写入 IOPS 为 500
docker run --device-read-iops /dev/sda:1000 --device-write-iops /dev/sda:500 nginx

2.6 网络带宽限制

Docker 原生未提供直接的网络带宽限制参数,但可通过以下方式实现:

  • tc(Traffic Control): 在容器 veth 接口上配置 HTB 或 TBF 队列规则,限制带宽。
  • --net QoS 插件: 使用第三方面网络插件(如 Calico、Weave)的 QoS 策略。
  • cgroup net_prio 子系统: 设置网络优先级,间接影响带宽分配。
方法 粒度 复杂度 适用场景
tc 直接限速 容器级别 中 单机部署,需要精确控制带宽
网络插件 QoS 容器/命名空间 低 Kubernetes 集群,声明式管理
cgroup net_prio 优先级 低 仅需区分优先级,不要求精确速率

tc 限速示例

# 获取容器网络命名空间 PID
CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' container_name)

# 在容器网络命名空间中配置 tc 限速(限制出口带宽 10Mbps)
nsenter -t $CONTAINER_PID -n tc qdisc add dev eth0 root tbf rate 10mbit burst 32kbit latency 400ms
生产建议: 在 Kubernetes 环境中,优先使用 NetworkPolicy 配合 CNI 插件的带宽注解(如 kubernetes.io/ingress-bandwidth)进行限制。在纯 Docker 环境中,建议将 tc 限速封装为启动脚本或使用 docker-compose 的 ulimits 配合自定义网络驱动。

2.7 资源限制综合配置清单

以下是一个企业级 Nginx 容器的资源限制示例,涵盖 CPU、内存、磁盘 I/O 和网络带宽:

docker run -d \
  --name web-nginx \
  --cpus="2" \
  --memory="1g" \
  --memory-swap="1.5g" \
  --memory-reservation="768m" \
  --blkio-weight=600 \
  --device-read-bps /dev/sda:100mb \
  --device-write-bps /dev/sda:50mb \
  --device-read-iops /dev/sda:5000 \
  --device-write-iops /dev/sda:2000 \
  --restart=always \
  nginx:1.25-alpine
验证命令: 使用 docker stats web-nginx 实时查看资源使用情况;使用 cat /sys/fs/cgroup/memory/docker/<container_id>/memory.limit_in_bytes 确认 cgroup 配置生效。

2.8 常见资源限制异常与排查方向

异常现象 可能原因 排查命令/方法
容器频繁 OOM 重启 内存硬限制过低,或应用内存泄漏 docker logs --tail 50 查看 OOM 日志;dmesg | grep -i oom
容器 CPU 使用率被截断 --cpus 设置过小,或 cpuset 绑定核心不足 docker stats 观察 CPU%;cat /sys/fs/cgroup/cpu/docker/<id>/cpu.cfs_quota_us
磁盘写入缓慢 blkio 写入速率限制过低,或磁盘本身瓶颈 iotop 查看进程 I/O;cat /sys/fs/cgroup/blkio/docker/<id>/blkio.throttle.write_bps_device
网络延迟高、吞吐低 tc 限速策略过于严格,或网络插件 QoS 冲突 tc -s qdisc show dev eth0 查看队列统计;iperf3 测试带宽