Docker——5.Docker资源管理
·
一、Docker资源管理概述
1.1 为什么需要资源管理
当多个容器同时运行时,如果不进行资源限制,某个容器可能会占用全部硬件资源,导致其他容器无法正常工作。Docker通过Cgroups(Control Groups)技术来控制容器使用的资源配额,包括:
- CPU控制:限制CPU使用率和权重
- 内存控制:限制内存使用上限
- I/O控制:限制磁盘读写速度
1.2 容器启动管理(重启策略)
为了保证容器运行的健壮性(自愈能力),Docker提供了--restart参数,让容器在退出时自动尝试重启。
四种重启策略
| 策略值 | 说明 | 适用场景 |
|---|---|---|
no | 默认策略,守护进程启动时不自动重启容器 | 测试环境、临时容器 |
on-failure[:max-retries] | 仅当容器以非零状态退出时才重启,可限制重试次数 | 需要容错但不希望无限重启的场景 |
always | 无论容器当前状态如何,总是在守护进程启动时启动 | 生产环境核心服务 |
unless-stopped | 容器退出时总是重启,但守护进程启动前已停止的容器除外 | 手动停止后不希望自动重启的场景 |
二、实验一:容器重启策略测试
实验目标
验证四种重启策略在不同场景下的行为差异。
实验步骤
步骤1:测试 --restart=no(默认策略)
# 创建两个容器,一个不指定策略(默认no),一个显式指定no
docker run -it --name c1 centos:7.7.1908 /bin/bash
docker run -it --name c2 --restart=no centos:7.7.1908 /bin/bash
# 查看容器重启策略配置(在inspect输出的第42行左右)
docker inspect c2
# 重启Docker服务
systemctl restart docker
# 查看容器状态:两个容器都不会自动重启
docker ps -a
# 停止所有容器
docker stop $(docker ps -aq)
# 清理容器
docker rm $(docker ps -aq)
# 清理已经停止的容器
docker container prune
预期结果:重启Docker服务后,c1和c2都处于停止状态,不会自动启动。
步骤2:测试 --restart=on-failure
# 创建两个使用on-failure策略的容器
docker run -it --name c1 --restart=on-failure centos:7.7.1908 /bin/bash
docker run -it --name c2 --restart=on-failure centos:7.7.1908 /bin/bash
# 正常退出容器(exit命令,退出码为0)
# 在容器内执行 exit
# 重启Docker服务
systemctl restart docker
# 查看容器状态
docker ps -a
# 强行关闭或杀死容器(模拟非零退出)
docker kill c1
docker stop c2
预期结果:
- 正常退出(exit)的容器不会重启(因为退出码为0)
- 被kill或异常退出的容器会尝试重启
- 可以指定最大重试次数:
--restart=on-failure:3
步骤3:测试 --restart=always
# 创建使用always策略的容器
docker run -it --name c1 --restart=always centos:7.7.1908 /bin/bash
# 停止容器
docker stop c1
# 重启Docker服务
systemctl restart docker
# 查看容器状态:容器会自动启动
docker ps -a
预期结果:无论容器是正常停止还是异常退出,重启Docker服务后都会自动启动。
步骤4:测试 --restart=unless-stopped
# 创建使用unless-stopped策略的容器
docker run -it --name c1 --restart=unless-stopped centos:7.7.1908 /bin/bash
# 场景1:正常退出容器
# 在容器内执行 exit
# 重启Docker服务
systemctl restart docker
docker ps -a # 容器会自动重启
# 场景2:手动停止容器
docker stop c1
# 重启Docker服务
systemctl restart docker
docker ps -a # 容器不会自动重启(因为是被手动停止的)
预期结果:
- 容器异常退出或正常退出后会重启
- 但如果是在Docker守护进程启动前就被手动停止的容器,不会自动重启
步骤5:更新正在运行的容器重启策略
# 动态修改容器的重启策略
docker update --restart=always c1
# 验证修改
docker inspect c1 | grep -A 5 RestartPolicy
三、实验二:CPU资源控制
实验目标
理解CPU权重(cpu-shares)的工作原理,验证多容器竞争CPU时的资源分配比例。
理论基础
- CPU权重(cpu-shares):默认值为1024,只有在多个容器同时竞争CPU时才生效
- 权重比例:容器A权重1000,容器B权重500,则A获得约66.6%的CPU时间,B获得约33.3%
- 单容器场景:如果只有一个容器运行,权重设置无意义,它可以占用全部可用CPU
实验准备:安装stress压力测试工具
# 在宿主机上stress工具
yum -y install stress
# 查看stress帮助信息
stress --help
# 测试CPU负载(产生2个进程,持续60000秒)
stress -c 2 -v --timeout 60000s
# 另一个终端观察CPU使用情况
top
实验步骤
步骤1:创建两个容器并设置不同CPU权重
# 先清理之前的容器
docker stop c1
docker kill c2
docker ps -a
# 正常退出容器(如果需要)
docker attach c1
exit
# 重启Docker服务确保环境干净
systemctl restart docker
docker ps -a
# 创建docker10容器:权重512,绑定到CPU0和CPU1
docker run -itd --name docker10 --cpuset-cpus 0,1 --cpu-shares 512 centos:7.7.1908 /bin/bash
# 创建docker20容器:权重1024,绑定到CPU0和CPU1
docker run -itd --name docker20 --cpuset-cpus 0,1 --cpu-shares 1024 centos:7.7.1908 /bin/bash
参数说明:
--cpuset-cpus 0,1:限制容器只能使用CPU0和CPU1核心--cpu-shares 512:设置CPU权重为512(docker10)--cpu-shares 1024:设置CPU权重为1024(docker20)-itd:交互式、伪终端、后台运行
步骤2:验证容器CPU配置
# 进入docker10容器
docker attach docker10
# 查看容器能使用的CPU核心
cat /sys/fs/cgroup/cpuset/cpuset.cpus
# 输出:0-1
# 查看CPU权重设置
cat /sys/fs/cgroup/cpu/cpu.shares
# 输出:512
# 退出容器(Ctrl+P+Q 分离,不要直接exit)
# 进入docker20容器
docker attach docker20
# 同样验证配置
cat /sys/fs/cgroup/cpuset/cpuset.cpus
cat /sys/fs/cgroup/cpu/cpu.shares
# 输出:1024
步骤3:安装stress并进行CPU压测
注意:以下操作需要在两个容器中分别执行
# ===== 在docker10容器中执行 =====
docker attach docker10
# 换源(加速下载)
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
# 安装stress
yum -y install stress
# 开始CPU压测:产生2个CPU密集型进程,持续12000秒
stress -c 2 -v --timeout 12000s
# ===== 在docker20容器中执行 =====
docker attach docker20
# 换源
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
# 安装stress
yum -y install stress
# 开始CPU压测
stress -c 2 -v --timeout 12000s
stress参数说明:
-c 2:产生2个进程,每个进程反复调用sqrt()计算随机数的平方根,消耗CPU-v:显示详细运行信息--timeout 12000s:持续运行12000秒(约3.3小时)
步骤4:观察CPU使用率分布
# 在宿主机上打开新终端,使用top观察
top
# 或使用htop(更直观)
htop
预期结果:
- docker10(权重512)约占33.3%的CPU时间
- docker20(权重1024)约占66.6%的CPU时间
- 两者比例为 1:2,与权重比例一致
步骤5:动态修改CPU权重
# 将docker20的权重从1024改为2048
docker update docker20 --cpu-shares 2048
# 重新观察top中的CPU占比变化
# 此时docker10:docker20 = 512:2048 = 1:4
# docker10约占20%,docker20约占80%
四、实验三:内存资源控制
实验目标
验证Docker对容器内存使用的限制机制。
实验步骤
步骤1:启动限制内存的容器
# 启动容器,限制最大使用内存为256MB
docker run -it -m 256m --name docker30 centos:7.7.1908 /bin/bash
参数说明:
-m 256m:限制容器最大使用256MB内存
步骤2:查看内存限制配置
# 在容器内查看内存限制(单位:字节)
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
# 输出:268435456(即256 * 1024 * 1024 = 268435456字节)
步骤3:进行内存压力测试
# 在容器内安装stress
yum -y install stress
# 产生2个内存分配进程,持续60000秒
# -m 2:产生2个进程,每个进程不断调用malloc()和free()分配释放内存
stress -m 2 -v --timeout 60000s
预期结果:
- stress会尝试分配大量内存
- 当超过256MB限制时,容器会被OOM Killer终止或stress报错
- 可以通过
dmesg查看OOM日志
步骤4:观察内存使用情况
# 在宿主机上使用top观察
top
步骤5:综合限制(CPU + 内存)
# 同时限制CPU核心、CPU权重和内存
docker run -itd --name docker40 \
--cpuset-cpus 0,1 \
--cpu-shares 512 \
-m 1024m \
centos:7.7.1908 /bin/bash
说明:此容器被限制为:
- 只能使用CPU0和CPU1
- CPU权重为512
- 最大内存使用1024MB
五、实验四:I/O资源控制
实验目标
验证Docker对容器磁盘I/O读写速度的限制。
理论基础
硬盘读写速度是有限的,如果某些容器长时间大量读写数据,会影响其他容器的I/O性能。通过--device-read-bps和--device-write-bps可以限制容器的读写速度。
实验步骤
步骤1:测试默认I/O读写速度
# 启动一个无限制的容器
docker run -it centos:7.7.1908 /bin/bash
# 测试写入速度:写入10MB数据
time dd if=/dev/zero of=file1 bs=1M count=10
# 示例输出:
# 10+0 records in
# 10+0 records out
# 10485760 bytes (10 MB) copied, 0.00921237 s, 1.1 GB/s
说明:
if=/dev/zero:输入源为零设备(产生全0数据)of=file1:输出到file1文件bs=1M:每次读写1MBcount=10:共读写10次,总计10MBtime:测量执行时间- 未限制时速度可达1.1 GB/s(取决于磁盘性能)
步骤2:限制I/O写入速度
# 启动容器,限制写入速度为1MB/s
docker run -it --device-write-bps /dev/sda:1m centos:7.7.1908 /bin/bash
# 测试写入速度(使用direct IO,绕过缓存)
time dd if=/dev/zero of=file1 bs=1M count=10 oflag=direct
# 示例输出:
# 10+0 records in
# 10+0 records out
# 10485760 bytes (10 MB) copied, 9.95536 s, 1.1 MB/s
参数说明:
--device-write-bps /dev/sda:1m:限制对/dev/sda设备的写入速度为1MB/soflag=direct:使用直接IO方式,不走系统缓存,直接从内存写入硬盘,能真实反映磁盘限速效果
对比结果:
- 未限制:1.1 GB/s(约10ms完成)
- 限制1MB/s:1.1 MB/s(约10秒完成)
- 速度降低了约1000倍,符合预期
步骤3:使用iotop监控I/O
# 在另一台机器或宿主机上安装iotop
yum -y install iotop
# 运行iotop观察各进程的I/O使用情况
iotop
# 按'o'键只显示有I/O活动的进程
步骤4:使用iostat监控磁盘负载
# 安装sysstat工具包
yum -y install sysstat
# 监控磁盘I/O统计信息
iostat -dmx 2
# 关注 %util 列:表示磁盘负载的使用率
# 接近100%表示磁盘已满负荷运行
iostat输出关键字段:
%util:磁盘利用率,接近100%表示磁盘饱和await:平均等待时间(毫秒)svctm:平均服务时间(毫秒)
步骤5:限制读取速度
# 同时限制读取和写入速度
docker run -it \
--device-read-bps /dev/sda:5m \
--device-write-bps /dev/sda:1m \
centos:7.7.1908 /bin/bash
说明:
--device-read-bps /dev/sda:5m:限制读取速度为5MB/s--device-write-bps /dev/sda:1m:限制写入速度为1MB/s
步骤6:设置容器自动释放资源
# 启动容器,30秒后自动删除
docker run -itd --rm --name c111 centos:7.7.1908 sleep 30
# 30秒后容器会自动停止并被删除
docker ps -a # 30秒后查看,c111已不存在
说明:
--rm:容器停止后自动删除sleep 30:容器运行30秒后退出- 适用于临时测试任务,避免残留容器占用资源
六、实验总结
6.1 四种资源管理策略对比
| 资源类型 | 关键参数 | 作用 | 典型应用场景 |
|---|---|---|---|
| 重启策略 | --restart | 控制容器异常退出后的行为 | 生产环境服务自愈 |
| CPU控制 | --cpu-shares --cpuset-cpus | 限制CPU使用权重和核心绑定 | 多容器公平共享CPU |
| 内存控制 | -m / --memory | 限制最大内存使用量 | 防止内存泄漏耗尽宿主机 |
| I/O控制 | --device-read-bps --device-write-bps | 限制磁盘读写速度 | 防止某个容器独占磁盘I/O |
6.2 关键注意事项
- CPU权重只在竞争时生效:单个容器运行时,权重设置无意义
- 内存限制要严格测试:设置过小可能导致容器频繁被OOM Kill
- I/O限制需使用direct IO验证:绕过缓存才能看到真实限速效果
- 重启策略选择要谨慎:生产环境推荐
always或unless-stopped - 资源限制可以组合使用:如同时限制CPU、内存和I/O
6.3 常用监控命令
# 实时监控CPU和内存
top
htop
# 实时监控I/O
iotop
# 磁盘I/O统计
iostat -dmx
# 查看容器资源使用情况
docker stats
# 查看容器详细配置
docker inspect <container_name>
更多推荐

所有评论(0)