Docker资源限制详解
1. cgroups 控制组机制
1.1 什么是cgroups
cgroups(control groups)是Linux内核提供的一种机制,用于:
- 限制进程组使用的物理资源(CPU、内存、IO等)
- 记录进程组的资源使用情况
- 隔离不同进程组的资源访问
重要性:默认情况下Docker容器不对资源使用进行限制,存在内存泄漏等风险
1.2 cgroups目录结构
bash
[root@hrz3 ~]# docker run --name mycentos1 -itd -m 200M centos:7
# 查看cgroups的目录结构
[root@hrz3 ~]# ls /sys/fs/cgroup/
blkio cpuacct cpuset freezer memory net_cls,net_prio perf_event systemd
cpu cpu,cpuacct devices hugetlb net_cls net_prio pids
# 查看具体容器的内存限制
[root@hrz3 ~]# cat /sys/fs/cgroup/memory/docker/2e4ed7eeef4bdc6cafcdb234049479b6bd6aa6ed6253f38b25f06fd3ea844cb6/memory.limit_in_bytes
说明:每个资源类型都有对应的cgroup目录,容器创建时会在这些目录下生成对应的资源限制文件
2. 构建stress测试镜像
2.1 完整的stress镜像构建过程
bash
# 1. 拉取Ubuntu基础镜像
[root@hrz3 ~]# docker pull ubuntu:jammy
# 2. 创建Dockerfile
[root@hrz3 ~]# vim Dockerfile
Dockerfile内容:
dockerfile
# 使用Ubuntu基础镜像
FROM ubuntu:jammy
# 更新软件源并安装stress工具
RUN apt-get update && apt-get install -y stress
# 设置容器的默认启动命令
ENTRYPOINT ["/usr/bin/stress", "--verbose"]
bash
# 3. 构建stress镜像
[root@hrz3 ~]# docker build -t stress .
# 4. 验证镜像构建成功
[root@hrz3 ~]# docker images | grep stress
[root@hrz3 ~]# docker run --rm stress --help
3. 内存资源限制
3.1 核心内存限制参数
参数 | 功能 | 示例 | 说明 |
---|---|---|---|
-m, --memory |
容器最大内存使用量 | -m 512m |
硬限制,超过会被OOM Killer终止 |
--memory-swap |
内存+交换分区总限制 | -m 512m --memory-swap=1g |
控制交换空间使用 |
--memory-reservation |
内存软限制 | --memory-reservation 50M |
系统紧张时的目标限制 |
--kernel-memory |
内核内存限制 | --kernel-memory=128m |
限制内核数据结构使用 |
--oom-kill-disable |
禁用OOM Killer | --oom-kill-disable |
保护关键容器不被杀死 |
--memory-swappiness |
交换分区倾向 | --memory-swappiness=0 |
0-100,越低越避免使用swap |
--oom-score-adj |
OOM优先级调整 | --oom-score-adj=-500 |
-1000到1000,调整被杀优先级 |
3.2 内存限制实践示例
示例1:限制容器物理内存为50MB
用途:测试内存限制的基本功能
bash
[root@hrz3 ~]# docker run -it --name a1 --rm -m 50M stress --vm 1 --vm-bytes 30M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 31457280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 31457280 bytes
......
示例2:限制物理内存50MB,总内存(物理+交换)100MB
用途:允许容器使用交换空间扩展内存
bash
[root@hrz3 ~]# docker run -it --name a1 --rm -m 50M --memory-swap=100M stress --vm 1 --vm-bytes 70M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 73400320 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 73400320 bytes
......
示例3:设置内存软限制
用途:为容器设置内存使用目标,系统紧张时尽量保持在此范围内
bash
[root@hrz3 ~]# docker run -it -m 100M --memory-reservation 50M centos:7
示例4:禁用OOM Killer
用途:保护关键容器进程不被自动杀死
bash
[root@hrz3 ~]# docker run -it -m 100M --oom-kill-disable centos:7
4. CPU资源限制
4.1 核心CPU限制参数
参数 | 功能 | 示例 | 说明 |
---|---|---|---|
--cpu-shares , -c |
CPU相对权重 | -c 512 |
默认1024,按比例分配CPU时间 |
--cpus |
CPU核心数量限制 | --cpus=1.5 |
限制使用的CPU核心数 |
--cpuset-cpus |
CPU核心绑定 | --cpuset-cpus="0,2" |
指定使用的物理CPU核心 |
--cpu-period |
CPU调度周期 | --cpu-period=100000 |
CFS调度周期,默认100ms |
--cpu-quota |
CPU时间配额 | --cpu-quota=50000 |
周期内可用的CPU时间 |
--cpuset-mems |
NUMA节点绑定 | --cpuset-mems="0" |
在多NUMA节点系统中优化内存访问 |
4.2 CPU限制实践示例
示例1:CPU权重对比测试
用途:演示CPU时间按权重分配的原理
终端1:启动权重为512的容器
bash
[root@hrz3 ~]# docker run -it --name a1 --rm -c 512 stress --cpu 4
终端2:启动权重为1024的容器(默认值)
bash
[root@hrz3 ~]# docker run -it --name a2 --rm -c 1024 stress --cpu 4
终端3:监控CPU使用情况
bash
[root@hrz3 ~]# top
top命令输出分析:
bash
top - 20:07:09 up 3:28, 3 users, load average: 7.24, 3.52, 1.62
Tasks: 200 total, 9 running, 191 sleeping, 0 stopped, 0 zombie
%Cpu(s): 99.9 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st
可以看到系统CPU几乎被完全占用,多个stress进程在竞争CPU资源
示例2:CPU核心绑定
用途:将容器进程绑定到特定CPU核心,提高缓存命中率
bash
[root@hrz3 ~]# docker run -it --name a1 --rm --cpuset-cpus="1,3" stress --vm 2 --vm-bytes 100M
CPU绑定效果验证 :
在另一个终端查看CPU使用情况,按数字1显示各CPU核心使用率
bash
[root@hrz3 ~]# top
top - 20:14:13 up 3:36, 3 users, load average: 4.76, 3.13, 2.02
Tasks: 193 total, 4 running, 189 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.3 us, 6.2 sy, 0.0 ni, 93.1 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
%Cpu1 : 12.5 us, 87.5 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st # CPU1被占用
%Cpu2 : 0.3 us, 4.7 sy, 0.0 ni, 94.6 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
%Cpu3 : 16.0 us, 84.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st # CPU3被占用
说明:可以看到只有CPU1和CPU3被占用,证明CPU绑定生效
5. Block IO限制
5.1 核心Block IO参数
参数 | 功能 | 示例 | 说明 |
---|---|---|---|
--blkio-weight |
IO相对权重 | --blkio-weight 100 |
10-1000,默认500 |
--blkio-weight-device |
设备特定权重 | --blkio-weight-device="/dev/sda:200" |
针对特定设备的权重 |
--device-read-bps |
读取带宽限制 | --device-read-bps="/dev/sda:1mb" |
限制读取速度 |
--device-write-bps |
写入带宽限制 | --device-write-bps="/dev/sda:1mb" |
限制写入速度 |
--device-read-iops |
读取IOPS限制 | --device-read-iops="/dev/sda:100" |
限制读取操作次数 |
--device-write-iops |
写入IOPS限制 | --device-write-iops="/dev/sda:100" |
限制写入操作次数 |
5.2 Block IO限制实践示例
示例1:IO权重对比测试
用途:演示不同IO权重容器的磁盘访问优先级
终端1:启动权重为100的容器
bash
[root@hrz3 ~]# docker run --name a1 -it --rm --blkio-weight 100 centos:7
终端2:启动权重为1000的容器
bash
[root@hrz3 ~]# docker run --name a2 -it --rm --blkio-weight 1000 centos:7
在两个容器中分别执行磁盘测试:
在a1容器中执行
bash
[root@4365499baaba /]# time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.891708 s, 1.2 GB/s
real 0m0.908s
user 0m0.000s
sys 0m0.765s
在a2容器中执行
bash
[root@c30c3c7f1cc2 /]# time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.877454 s, 1.2 GB/s
real 0m0.878s
user 0m0.000s
sys 0m0.781s
说明 :oflag=direct
参数绕过缓存直接写入磁盘,测试真实磁盘IO性能
示例2:写入带宽限制
用途:限制容器对磁盘的写入速度,防止IO密集型应用影响其他服务
bash
[root@hrz3 ~]# docker run --name a3 -it --rm --device-write-bps /dev/sda:1mb centos:7
在容器内测试写入速度
bash
[root@867b0d653cfb /]# time dd if=/dev/zero of=test.out bs=1M count=20 oflag=direct
20+0 records in
20+0 records out
20971520 bytes (21 MB) copied, 0.0141288 s, 1.5 GB/s
real 0m0.015s
user 0m0.000s
sys 0m0.014s
注意:实际测试结果显示速度很快,这可能是因为:
- 系统缓存的影响
- 测试数据量较小
- 需要更长时间的测试才能看到限制效果
6. 关键概念总结
6.1 Linux Namespace类型
Linux内核实现了6种Namespace用于资源隔离:
- UTS: 主机名和域名隔离
- IPC: 进程间通信隔离
- PID: 进程ID隔离
- Mount: 文件系统挂载点隔离
- User: 用户和用户组隔离
- Network: 网络设备、端口等隔离
6.2 资源限制重要说明
重要理解:
- Docker容器资源限制只是对容器实际使用资源进行限制
- 从容器内部视角看,它认为自己的资源与宿主机相同
- 资源限制通过cgroups机制在宿主机层面实现
- 合理设置资源限制可以防止"吵闹的邻居"问题,保证系统稳定性
6.3 最佳实践建议
生产环境资源限制建议:
- 所有容器都应该设置适当的内存限制
- 关键业务容器应设置CPU权重保障性能
- IO密集型应用应设置磁盘IO限制
- 使用资源监控工具定期检查资源使用情况
- 根据实际业务需求动态调整资源限制
通过合理配置这些资源限制参数,可以确保Docker容器在共享的宿主机环境中稳定运行,避免单个容器过度消耗资源影响其他服务。