文章目录
- 前言
- 理论部分
-
- 4_资源限制
-
- 4.1_cgroups四大功能
- 4.2_CPU资源控制
- 4.3_内存使用限制
- [4.4_磁盘 IO 控制](#4.4_磁盘 IO 控制)
- 5_数据卷容器
- 6_端口映射
- 7_容器互联
-
- [7.1_--link 方式(已弃用)](#7.1_--link 方式(已弃用))
- 7.2_自定义网络(推荐)
- 实验部分
- 结语
- 扩展
前言
本文档聚焦 资源限制、数据卷容器、端口映射、容器互联 四大核心章节,系统讲解如何通过 cgroups 控制容器资源使用、利用数据卷实现持久化存储、通过端口映射暴露服务,以及容器间通信机制。内容严格保留所有命令、配置参数、路径及实验步骤,便于教学与实操参考。
- 什么是CgroupS
- cgroup 对CPU限制
- cgroup 对内存的限制
- 资源限制的主要类型
- 资源限制几种方式
- 资源限制的状态查询
- 数据卷 容器
- 端口映射
- 容器中间互联
理论部分
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_容器互联
容器互联指容器间通过网络相互通信。
7.1_--link 方式(已弃用)
语法 :--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:实时显示容器资源使用情况;top按1键显示每个 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_容器互联实验
4.1_--link 方式(传统方法)
① 创建源容器
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
数据保留供后续使用
结束