46 Docker资源管理

文章目录

前言

本文档聚焦 资源限制、数据卷容器、端口映射、容器互联 四大核心章节,系统讲解如何通过 cgroups 控制容器资源使用、利用数据卷实现持久化存储、通过端口映射暴露服务,以及容器间通信机制。内容严格保留所有命令、配置参数、路径及实验步骤,便于教学与实操参考。

  1. 什么是CgroupS
  2. cgroup 对CPU限制
  3. cgroup 对内存的限制
  4. 资源限制的主要类型
  5. 资源限制几种方式
  6. 资源限制的状态查询
  7. 数据卷 容器
  8. 端口映射
  9. 容器中间互联

理论部分

4_资源限制

Docker利用Linux内核提供的 cgroups(Control Groups) 机制,实现资源隔离与限制。

4.1_cgroups四大功能

  • 资源限制:设定任务使用资源上限。
  • 优先级分配:通过权重分配CPU时间片、IO带宽。
  • 资源统计:记录CPU时长、内存用量等。
  • 任务控制:挂起、恢复或终止进程组。

4.2_CPU资源控制

① CPU使用率上限(硬限制)
参数

  • --cpus=0.5:核数,新版本友好封装
  • --cpu-period=100000:周期,值(微秒)在1千~1百万之间,和配额一起用。
  • --cpu-quota=50000:配额,周期的占比,值不超过周期。(quota = -1 表示不限制)

原理 :CFS 调度器基于配额/周期计算可用 CPU 份额。
注意 :在 N 核机器上,--cpus=0.5 ≈ 占用整机 0.5/N 的 CPU 能力。

② CPU权重(软限制)

  • 参数--cpu-shares=512(默认 1024)
  • 行为:仅在 CPU 争用时生效,按权重比例分配时间片。

③ CPU亲和性

  • 参数--cpuset-cpus="0,2"(从0开始,第1颗和第3颗)
  • 作用:将容器进程绑定到指定 CPU 核,提升性能稳定性。

4.3_内存使用限制

① 基础选项

  • -m, --memory=512m:限制物理内存。
  • --memory-swap=1g:限制物理内存 + swap 总量(故而不能低于物理内存限制)

② 关键规则

配置 行为
-m 300m --memory-swap=1g 物理内存 300MB,swap 可用 700MB
--memory-swap = -m 禁用 swap,内存耗尽触发 OOM
--memory-swap = -1 不限制,宿主机swap有多少就用多少。

OOM(Out-Of-Memory):内核杀掉超限容器。

4.4_磁盘 IO 控制

① 限制参数

  • --device-read-bps /dev/sda:1M :限制设备上读速率为 1 MB/s
  • --device-write-bps /dev/sda:1MB:写带宽上限
  • --device-read-iops /dev/sda:100 :限制读 IOPS(次数)
  • --device-write-iops /dev/sda:100:写 IOPS 上限

② 注意事项

  • 必须指定真实块设备路径
  • 云环境可能受底层虚拟化限制。

5_数据卷容器

5.1_数据卷

Data Volumes

  • 定义:容器内的特殊目录,可与宿主机或其他容器共享。
  • 特性
    • 数据持久化(容器删除不影响数据)。
    • 支持绑定挂载(-v /host:/container)。
    • 绕过 UnionFS,直接写入宿主机文件系统。

5.2_数据卷容器

Data Volume Container

  • 定义:专门用于提供数据卷的容器,不运行应用。
  • 用途:多个容器共享同一数据源,避免重复挂载宿主机目录。
  • 实现 :通过 --volumes-from <容器名> 挂载其所有数据卷。

优势:解耦数据与应用,便于备份与迁移。

5.3_数据卷原理

共享状态
直接挂载路径(对比)
应用容器使用

--volumes-from
数据卷容器路径
第一步:创建数据卷
创建命名数据卷

docker volume create app_data
数据卷 app_data 准备就绪
运行数据卷容器

docker run -v app_data:/data

--name volume_container busybox
数据卷容器 volume_container 运行中

(通常执行 sleep infinity)
启动应用容器 A

docker run --volumes-from volume_container

--name app1 my_app
启动应用容器 B

docker run --volumes-from volume_container

--name app2 my_app
启动应用容器 C

docker run -v app_data:/data

--name app3 my_app
容器 A, B, C 均挂载

同一个数据卷 app_data
容器 A 写入 /data/file.txt
容器 B 和 C 可立即读取

/data/file.txt
实现多应用实例间

数据持久化与实时共享


6_端口映射

容器内部服务默认无法被外部访问,需通过端口映射暴露。

6.1_随机端口映射(-P)

  • 自动将容器 EXPOSE 的端口映射到宿主机 32768~65535 随机端口。
  • 适用于无需固定端口的场景。

6.2_指定端口映射(-p)

  • 手动指定映射关系:-p <宿主端口>:<容器端口>
  • 支持协议指定:-p 8080:80/tcp
  • 注意:宿主端口不能低于 60(Compose 限制)。

原理:Docker 在 iptables 中添加 DNAT 规则实现端口转发。


7_容器互联

容器互联指容器间通过网络相互通信。

语法--link <源容器>:<别名>
机制

  • /etc/hosts 添加源容器 IP 记录。
  • 设置环境变量(如 WEB1_PORT=tcp://172.17.0.2:80)。
  • 局限:单向连接,不支持 DNS 动态解析。

宿主机 Docker Engine
--link 机制
成功解析为 172.17.0.2
--link 内部机制
etc/hosts 更新

172.17.0.2 web1
环境变量注入

WEB1_PORT等变量/
源容器: web1

IP: 172.17.0.2
接收容器: web2

IP: 172.17.0.3
步骤1: docker run --name web1
步骤2: docker run --name web2 --link web1:web1
步骤3: docker exec -it web2 ping web1
域名解析
连通成功 Ping OK

7.2_自定义网络(推荐)

  • 创建自定义 bridge 网络:docker network create mynet
  • 容器加入同一网络后,自动支持 DNS 解析(通过容器名通信)。
  • 优势 :双向通信、动态发现、无需修改 /etc/hosts

生产建议 :始终使用自定义网络替代 --link


实验部分

1_资源限制实验

1.1_CPU 限制

① 限制 CPU 使用率
方法一:直接更改 cgroup 配置

  • 查看容器ID
shell 复制代码
docker inspect -f '{{.Id}}' 容器名
  • 修改CFS调度器文件
shell 复制代码
cd /sys/fs/cgroup/cpu/docker/<容器ID>/
cat cpu.cfs_period_us	# 默认会输出100000(周期值,微秒)
cat cpu.cfs_quota_us	# 默认会输出-1(配额值,-1表示不限制)

# 修改配额值
echo 50000 > cpu.cfs_quota_us

方法二:使用docker命令指定周期值和配额值

shell 复制代码
docker run -itd --name c1 --cpu-quota 100000 centos:7 /bin/bash

# 查看容器的CPU配额
docker inspect -f '{{.HostConfig.CpuQuota}}' 容器名或ID
# 查看容器的CPU配额
docker inspect -f '{{.HostConfig.CpuPeriod}}' 容器名或ID

方法三:使用docker命令指定CPU(s)核数

shell 复制代码
docker run -itd --name c2 --cpus="0.5" centos:7 /bin/bash

--cpus="0.5":限制容器最多使用 0.5 个 CPU 核心

② 设置 CPU 权重

shell 复制代码
docker run -itd --name c1 --cpu-shares 512 centos:7
docker run -itd --name c2 --cpu-shares 1024 centos:7

# 如果容器已存在,可修改CPU权重,需重启容器
docker update --cpu-shares=512 c1
docker update --cpu-shares=1024 c2

# 查看容器的CPU权重
docker inspect -f '{{.HostConfig.CpuShares}}' 容器名或ID

--cpu-shares:设置 CPU 时间片权重(默认 1024),争用时 c2 获得约 2 倍于 c1 的 CPU 时间

③ 绑定 CPU 核

  • 查看宿主机CPU核
shell 复制代码
# 检查可用的 CPU
cat /sys/fs/cgroup/cpuset/cpuset.cpus

# 查看核心数
nproc
lscpu | grep "Socket"
  • 容器绑定CPU核
shell 复制代码
docker run -itd --name c1 --cpuset-cpus "1,3" centos:7 /bin/bash
docker update --cpuset-cpus="1,3" c1

--cpuset-cpus "1,3":将容器进程绑定到宿主机的第 1 和第 3 个 CPU 核(从 0 开始计数)

  • 查看容器绑定的CPU核
shell 复制代码
docker inspect -f '{{.HostConfig.CpusetCpus}}' c1

④ 压力测试
方法一:使用死循环脚本

  • 准备一个死循环脚本cpu.sh
bash 复制代码
#!/bin/bash
i=0
while true; do let i++; done
  • 拷贝到容器并后台运行该脚本
shell 复制代码
docker cp cpu.sh c1:/opt/
docker exec -itd c1 /bin/bash /opt/cpu.sh

方法二:使用stress压测工具

shell 复制代码
# 进入容器
docker exec -it c1 bash
# 安装 stress
yum install -y epel-release
yum install -y stress
# 生成 CPU 负载
stress -c 4

stress -c 4:启动 4 个 worker 进程进行平方根计算,模拟 CPU 密集型负载

⑤ 验证

shell 复制代码
# 实时监测
docker stats

# 静态输出
docker stats --no-stream c1 c2
ini 复制代码
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O         BLOCK I/O        PIDS
e2d845b42569   c2        51.36%    534.7MiB / 3.7GiB   14.11%    105MB / 704kB   442kB / 50.5MB   7
3e1540bd88a7   c1        102.25%   1MiB / 3.7GiB       0.03%     698B / 0B       0B / 0B          7
  • 宿主机观察各核利用率
shell 复制代码
top -d 1

docker stats:实时显示容器资源使用情况;top1 键显示每个 CPU 核的使用率

  • 查看 cgroup 配置
shell 复制代码
cat /sys/fs/cgroup/cpu/docker/<容器ID>/cpu.cfs_quota_us
cat /sys/fs/cgroup/cpu/docker/<容器ID>/.....

1.2_内存限制

  • 查看容器当前内存限制
shell 复制代码
docker inspect -f '内存: {{.HostConfig.Memory}} 内存交换: {{.HostConfig.MemorySwap}}' <容器名/ID>

run创建容器加-m时,--memory-swap=缺省默认值是容器物理内存的2倍。如果不加-m,则--memory-swap=为0。

① 限制物理内存

shell 复制代码
docker run -itd --name memtest -m 512m centos:7 /bin/bash

-m 512m:限制容器最大使用 512MB 物理内存

② 限制内存+swap

shell 复制代码
docker update -m 300m --memory-swap=1g memtest

--memory-swap=1g:物理内存 + swap 总量不超过 1GB,因此 swap 可用 = 700MB

③ 验证

  • 实时监控
shell 复制代码
docker stats
  • 查看 cgroup 限制
shell 复制代码
cat /sys/fs/cgroup/memory/docker/<容器ID>/memory.limit_in_bytes
  • 模拟 OOM
shell 复制代码
stress --vm 1 --vm-bytes 600M   # 超过 512m 限制
docker exec c1 stress --vm 2 --vm-bytes 800M --timeout 30s

stress --vm 1 --vm-bytes 600M:分配 600MB 虚拟内存触发 OOM;dmesg | tail 查看内核日志确认 kill 事件

  • 查看 OOM 日志

    dmesg -T | tail
    watch -n 1 'dmesg -T | tail -5'

dmesg -T:内核日志,-T:人类可读的时间戳

1.3_磁盘 IO 限制

① 限制写速

shell 复制代码
docker run -it --name iotest --device-write-bps /dev/sda:1MB centos:7 /bin/bash

--device-write-bps /dev/sda:1MB:限制对 /dev/sda 设备的写入带宽为 1MB/s

② 验证写速

shell 复制代码
# 在容器内执行
dd if=/dev/zero of=test.out bs=1M count=10 oflag=direct

dd:数据复制工具;oflag=direct:绕过文件系统缓存直写磁盘;输出应显示 ~1.0 MB/s


2_数据卷容器实验

2.1_创建与挂载数据卷

① 挂载宿主机目录

  • 建一个nginx容器,并拷贝容器里nginx存放数据的目录。
shell 复制代码
docker cp nginx:/etc/nginx/ /etc/
docker cp nginx:/var/log/nginx/ /var/log/
docker cp nginx:/usr/share/nginx/html/ /var/www/
# 或者直接在宿主机yum安装一个nginx,前提是版本一致。
  • 再重新建一个nginx容器,挂载数据卷。
shell 复制代码
docker run -v /etc/nginx:/etc/nginx \
		   -v /var/log/nginx:/var/log/nginx \
		   -v /var/www/html:/usr/share/nginx/html \
		   -p 80:80 -d --name web1 nginx:latest 

-v /var/www/html:/usr/share/nginx/html:将宿主机 /var/www/html 挂载到容器 /usr/share/nginx/html

② 在容器中写入数据

shell 复制代码
echo "this is web1" > /var/www/html/index.html

③ 验证宿主机数据

shell 复制代码
curl http://localhost

输出:this is web1,证明数据同步

2.2_创建数据卷容器

① 创建专用数据卷容器

shell 复制代码
docker run --name web2 -v /data1 -v /data2 -it centos:7 /bin/bash

-v /data1 -v /data2:在容器内创建两个匿名数据卷(不绑定宿主机路径)

② 在数据卷容器中写入数据

shell 复制代码
echo "this is web2" > /data1/abc.txt
echo "THIS IS WEB2" > /data2/ABC.txt

2.3_共享数据卷

① 创建新容器并挂载数据卷

shell 复制代码
docker run -it --volumes-from web2 --name web3 centos:7 /bin/bash

--volumes-from web2:挂载 web2 容器的所有数据卷

② 验证数据共享

shell 复制代码
cat /data1/abc.txt
cat /data2/ABC.txt

输出:

ini 复制代码
this is web2
THIS IS WEB2

3_端口映射实验

3.1_随机端口映射

① 启动容器

shell 复制代码
docker run -d --name test1 -P nginx

-P:自动映射容器暴露的端口(如 80)到宿主机随机高端口

② 查看映射

shell 复制代码
docker ps -a

输出示例:0.0.0.0:49170->80/tcp

③ 访问服务

浏览器访问:http://<宿主IP>:49170

3.2_指定端口映射

① 启动容器

shell 复制代码
docker run -d --name test2 -p 43000:80 nginx

-p 43000:80:将宿主机 43000 端口映射到容器 80 端口

② 查看映射

shell 复制代码
docker ps -a

输出示例:0.0.0.0:43000->80/tcp

③ 访问服务

浏览器访问:http://<宿主IP>:43000


4_容器互联实验

① 创建源容器

shell 复制代码
docker run -itd -P --name web1 centos:7 /bin/bash

② 创建接收容器并链接

shell 复制代码
docker run -itd -P --name web2 --link web1:web1 centos:7 /bin/bash

--link web1:web1:将 web1 容器暴露给 web2,并设置别名为 web1

③ 测试连通性

shell 复制代码
docker exec -it web2 bash
cat /etc/hosts
ping web1

成功 ping 通,证明 --link 生效

4.2_自定义网络方式(推荐)

① 创建自定义网络

shell 复制代码
docker network create mynet

② 启动容器并加入网络

shell 复制代码
docker run -itd --name app1 --network mynet centos:7 /bin/bash
docker run -itd --name app2 --network mynet centos:7 /bin/bash

③ 测试 DNS 解析

shell 复制代码
docker exec -it app1 ping app2

成功 ping 通,证明自定义网络自动解析容器名


结语

资源限制要点 :CPU 用 --cpus(硬限)或 --cpu-shares(权重),内存必须设 -m 并谨慎配置 swap,IO 限制需指定真实设备。
数据持久化方案 :简单场景用 -v 绑定挂载,多容器共享用数据卷容器(--volumes-from)。
服务暴露方式 :开发用 -P 随机映射,生产用 -p 指定端口。
容器通信演进--link 已过时,自定义网络是唯一推荐方案,支持 DNS 自动解析。

!question\] `--cpu-shares` 和 `--cpus` 的本质区别是什么? `--cpu-shares` 是相对权重(争用时按比例分配),非硬限制;`--cpus` 是绝对上限(硬限制),即使 CPU 空闲也不可超用。 \[!question\] 如何避免容器因内存超限被 OOM kill? 1. 合理设置 `-m`;2. 限制 `--memory-swap`;3. 应用层实现内存监控与优雅降级;4. 配置容器重启策略(`--restart=on-failure`)。 \[!question\] 在云服务器上设置 `--device-write-bps` 为何无效? 云盘(如 AWS EBS、阿里云云盘)的 IO 性能由底层虚拟化层控制,容器内的 cgroups 限制可能被覆盖或忽略,建议在物理机验证。 \[!question\] 为什么设置 `--memory-swap = -m` 会禁用 swap? 此配置表示"物理内存 + swap 总量 = 物理内存限制",即 swap 可用量为 0,从而禁用 swap,内存超限直接 OOM。 \[!question\] 数据卷容器与普通容器挂载数据卷有何区别? 数据卷容器专用于提供数据卷,生命周期独立于应用容器;普通容器挂载的数据卷随容器删除而丢失(除非使用命名卷)。 \[!question\] `-P` 和 `-p` 的本质区别是什么? `-P` 仅映射 Dockerfile 中 `EXPOSE` 声明的端口,且端口随机;`-p` 可映射任意端口,且可手动指定宿主端口。 \[!question\] 为何推荐使用自定义网络而非 `--link`? `--link` 需静态配置、单向连接、不支持动态发现;自定义网络提供双向 DNS 解析、动态 IP 分配、更安全的隔离。

扩展

容器存储的生命周期
绑定挂载
命名卷
数据卷容器
读操作
写操作
备份
恢复


开始
选择数据管理方式
绑定挂载 Bind Mount
命名卷 Named Volume
数据卷容器 Volume Container
宿主机路径: /host/path
直接映射宿主机目录
文件双向实时同步
应用容器使用
Docker 管理存储位置
自动创建和数据迁移
容器间共享数据
创建专用数据卷容器
定义数据卷路径
其他容器 --volumes-from
多容器共享数据
数据操作类型
从数据卷读取
写入数据卷
备份数据卷
恢复数据卷
数据持久化存储
数据备份流程
数据恢复流程
生命周期结束
是否删除数据卷
手动删除卷 docker volume rm
数据保留供后续使用
结束

相关推荐
hans汉斯2 小时前
嵌入式操作系统技术发展趋势
大数据·数据库·物联网·rust·云计算·嵌入式实时数据库·汉斯出版社
cab52 小时前
如何解决由于 Docker 的大日志文件导致磁盘空间不足的问题
docker
天河归来3 小时前
本地windows环境升级dify到1.11.1版本
java·spring boot·docker
厚德云3 小时前
全球首款填空式AI绘画提示词工具PromptFill正式发布
人工智能·ai作画·云计算·aigc·ai绘画
么么...4 小时前
在 Ubuntu 上安装 Docker 并部署 MySQL 容器
linux·运维·经验分享·笔记·mysql·ubuntu·docker
翼龙云_cloud5 小时前
亚马逊云渠道商:Lightsail 如何制定备份与快照策略以平衡安全及成本?
运维·安全·云计算·aws
学Linux的语莫5 小时前
kompose、docker转k8s
docker·容器·kubernetes
同聘云5 小时前
阿里云云服务器云备份满了可以删除吗?不小心把备份删除了怎么办
服务器·阿里云·云计算
打码人的日常分享5 小时前
企业数据资产管控和数据治理解决方案
大数据·运维·网络·人工智能·云计算