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
数据保留供后续使用
结束

相关推荐
程序媛Dev13 分钟前
训练模型用GCP,推理服务放阿里云?聊聊AIGC时代的多云自由
阿里云·云计算·aigc
—Qeyser11 小时前
Flutter GestureDetector 完全指南:让任何组件都能响应手势
flutter·云原生·容器·kubernetes
江湖有缘11 小时前
从零开始:基于 Docker Compose部署高可用 Miniflux RSS阅读器
运维·docker·容器
忍冬行者13 小时前
prometheus通过VMware_explorter监控VMware虚拟化集群
云原生·云计算·grafana·prometheus
林鸿风采14 小时前
在Alpine Linux上部署docker和Portainer管理工具
linux·运维·docker·portainer
林_学14 小时前
我扔掉了本地环境,从编码到上线只花了3分钟
docker
怜淇15 小时前
docker拉取openjdk8:jre失败
java·docker·容器
❀͜͡傀儡师18 小时前
docker部署BentoPDF应用
运维·docker·容器
AKAMAI18 小时前
Akamai Cloud客户案例 | 全球教育科技公司TalentSprint依托Akamai云计算服务实现八倍增长并有效控制成本
人工智能·云计算
为爱停留19 小时前
Spring Boot 应用配置参数化实践:通过 Docker Run 参数传递配置
spring boot·后端·docker