cgroups、Data Volumes Containers和 端口映射、 容器互联
前言
在 Docker 中,为了实现**资源可控、数据持久、服务互通**三大核心目标,有几项关键技术被广泛应用:cgroups(Control Groups):Linux 内核机制,Docker 借此对容器的 CPU、内存、I/O 等资源进行限制、统计与隔离,确保容器不会“失控”占用宿主机全部资源。
Data Volumes / Data Volume Containers:用于解决容器**数据易失性问题。通过挂载卷(Volume)或将数据托管在专用容器中,实现数据持久化和多容器共享。
端口映射(Port Mapping):将容器内部服务端口(如 80)映射到宿主机端口(如 8080),使外部网络能够访问容器内应用。
容器互联(Container Linking / 自定义网络):让多个容器之间能安全、便捷地通信,早期使用 `--link`,现代推荐使用 Docker 自定义网络实现服务发现与隔离。
这四项技术共同构成了 Docker 容器稳定运行、高效协作与生产就绪的基础。
cgroups
概述
- cgroups(Control Groups)是 Linux 内核提供的资源控制机制。对容器非常重要,可控制:资源限制、优先级分配、资源统计、任务控制(挂起/恢复/终止)。
- Docker 通过 cgroups 来实现 CPU、内存、IO 等限制与度量。
cgroups 的 4 大功能
- 资源限制:限制任务使用的总资源量。
- 优先级分配:如通过 cpu 时间片和 IO 带宽分配优先级。
- 资源统计:统计 cpu 时长、内存用量等。
- 任务控制:对 cgroup 中的进程执行挂起/恢复等操作。
设置 CPU 使用率上限
- 原理:Linux 使用 CFS(Completely Fair Scheduler)。通过两个参数控制:cpu.cfs_period_us(周期,微秒)和 cpu.cfs_quota_us(配额,微秒)。
- quota / period = 可用 CPU 核心数的 小数 表示(相对于 1 个 CPU)。
- 默认 period = 100000(100 ms)。quota = -1 表示不限制。
- 示例:限制容器为 50% 的一个 CPU:
docker run -itd --name test6 --cpu-quota 50000 centos:7 /bin/bash 0.5
解释:50000 / 100000 = 0.5 → 相当于 0.5 个 CPU(即 50% 的单核)。
- 注意:如果宿主机有 4 个逻辑核,那么 0.5 个 CPU ≈ 0.5 / 4 = 0.125(即 12.5% 的整机 CPU能力)。
- (计算示例:50000/100000 = 0.5;0.5/4 = 0.125 → 12.5%)
- 最小值/范围:--cpu-period 有效范围通常 1000 ~ 1000000(单位 us)。--cpu-quota 必须 >=1000(1 ms)或者 -1(不限制)。
- 另一种更直观的写法:
docker run -itd --name cputest --cpus="0.5" centos:7 /bin/bash
--cpus=0.5 是 --cpu-quota/ --cpu-period 的友好封装(要求较新版本 Docker)。
设置 CPU 占用比
- 原理:--cpu-shares 指定相对权重(默认 1024),仅在 CPU 争用时生效(不是硬限制)。
- 举例:两个容器 c1、c2,--cpu-shares 512 与 --cpu-shares 1024,在争用情况下 CPU分配比约为 1:2。
- 示例:
docker run -itd --name c1 --cpu-shares 512 centos:7
docker run -itd --name c2 --cpu-shares 1024 centos:7
- 验证:运行压力程序(stress -c N)后用 docker stats 观察 CPU % 倾向于 1:2(随系统负载和核心数而变化)。
绑定指定 CPU
- 用途:把容器进程绑定到宿主机的指定 CPU 核上(硬亲和性)。
- 示例:将容器绑定到第 1 和第 3 个核:
docker run -itd --name test7 --cpuset-cpus "1,3" centos:7 /bin/bash
- 验证:在宿主机运行 top 或 htop(按 1)查看各核利用率,或进入容器运行 taskset -p <pid>。
压力测试与验证示例(CPU)
- 在容器内创建一个繁忙循环脚本:
# /cpu.sh
#!/bin/bash
i=0
while true; do let i++; done
- 在容器内运行 ./cpu.sh,在宿主机观察 top 与 docker stats:
docker exec -it <container> bash
./cpu.sh
- 分别进入容器,进行压力测试
yum install -y epel-release
yum install -y stress
stress -c 4 #产生四个进程,每个进程都反复不停的计算随机数的平方根
- 修改 cgroups 手工测试(示例):
# 找到容器对应的 cgroup 路径(容器ID替换)
cd /sys/fs/cgroup/cpu/docker/<container-id>/
cat cpu.cfs_period_us
cat cpu.cfs_quota_us
echo 50000 > cpu.cfs_quota_us # 设置配额(临时生效)
注意事项
- --cpu-shares 是权重,不是限额。
- --cpu-quota/ --cpu-period 是硬限制(quota = -1 表示无限制)。
- 使用 --cpuset-cpus 能提高性能稳定性(避免与其他进程抢核)。
- 在多核宿主机上理解 quota/period 的含义(单位是 “相对于 1 个 CPU 的份额”)。
内存使用限制
- -m, --memory:限制容器可用的物理内存(例如 -m 512m)。
- --memory-swap:限制容器可用的物理内存 + swap 总量(必须与 -m 一起使用以明确 swap 上限)。
--memory 与 --memory-swap 规则
- 示例:-m 300m --memory-swap=1g
- 含义:容器可用物理内存 = 300 MB;物理 + swap 总共 = 1 GB → swap 可用 = 700 MB(1G
- - 300M)。
- 默认行为:若不设置 --memory-swap,通常容器可使用的 swap 为 -m 值的两倍(行为可能随
- Docker 版本/配置变化)。
- 若 --memory-swap = -1:swap 不受限制(宿主机可用多少 swap 就用多少)。
- 若 --memory-swap = -m:容器不能使用 swap(物理内存用尽会触发 OOM)。
示例命令
docker run -itd --name test8 -m 512m centos:7 /bin/bash
# 或者设置 swap 总额
docker run -itd --name test8b -m 300m --memory-swap=1g centos:7
验证与观察
- 使用 docker stats 观察 MEM USAGE / LIMIT。
- 在宿主机查看 cgroup:
cd /sys/fs/cgroup/memory/docker/<container-id>/
cat memory.limit_in_bytes
cat memory.usage_in_bytes
- OOM 行为:如果容器超过允许内存且没有 swap 或无更多内存可用,会被内核 OOM killer 杀掉。可查看容器日志与 dmesg 来确认 OOM 事件。
建议与注意
- 为生产服务设置合理内存限制,避免单容器把宿主机内存耗尽。
- 对于内存敏感的应用,建议同时设置 -m 与 --memory-swap,并配合健康检查/重启策略。
- 在 cgroup v2 环境下内存控制文件名/行为可能与 v1 略有不同(检查 /sys/fs/cgroup 结构)。
磁盘 IO(blkio / io)控制
- Docker 提供对块设备读写带宽与 IOPS 的限制选项(基于 cgroups 的 blkio 控制器)。
- 注意:在 cgroup v2 中,blkio 功能被 io 控制器取代,语义与文件名有所不同(如果你运行的是
- 较新内核/系统,请参考对应 cgroup 版本文档)。
常用 Docker 参数(blkio)
- --device-read-bps /dev/sda:1M:限制设备上读速率为 1 MB/s。
- --device-write-bps /dev/sda:1M:限制写速率为 1 MB/s。
- --device-read-iops /dev/sda:100:限制读 IOPS(次数)。
- --device-write-iops /dev/sda:100:限制写 IOPS(次数)。
示例:
docker run -it --name test10 --device-write-bps /dev/sda:1MB centos:7 /bin/bash
验证
- 在容器内执行写入测试,使用 oflag=direct 跳过文件系统缓存:
dd if=/dev/zero of=test.out bs=1M count=10 oflag=direct
- 输出示例说明:10485760 bytes (10 MB) copied, 10.0025 s, 1.0 MB/s → 写速被限为约 1MB/s。
注意事项
- 限制需要指定具体块设备路径(如 /dev/sda)。错误的设备路径不会生效。
- 在虚拟化环境或云盘(如 EBS、云盘快照)上,底层 IO 性能由云提供商或 hypervisor 决定,容器
- 层设置可能受限。
- 在 cgroup v2 上,对 IO 的控制接口为 io.max 等,需要使用不同的工具/路径来配置验证。
清理 Docker 占用的磁盘空间
- 清理未使用的数据(可释放磁盘空间):
docker system prune -a
- 该命令会删除停止的容器、未使用的镜像、未使用的网络和构建缓存(要谨慎使用,会删除很多资源)。
常见命令速查
总结命令 资源限制
# CPU
docker run -itd --name c1 --cpu-shares 512 centos:7
docker run -itd --name c2 --cpu-quota 50000 centos:7
docker run -itd --name c3 --cpuset-cpus "1,3" centos:7
docker run -itd --name c4 --cpus="0.5" centos:7
# 内存
docker run -itd --name memtest -m 512m centos:7
docker run -itd --name memtest2 -m 300m --memory-swap=1g centos:7
# blkio
docker run -it --name iotest --device-write-bps /dev/sda:1MB centos:7
# 监控/验证
docker stats
docker exec -it <container> bash
cat /sys/fs/cgroup/cpu/docker/<container-id>/cpu.cfs_quota_us
cat /sys/fs/cgroup/memory/docker/<container-id>/memory.limit_in_bytes
# 清理
docker system prune -a
常见陷阱与建议
- 理解权重 vs 限额:--cpu-shares = 权重(争用时生效);--cpu-quota/ --cpus = 硬限制。
- cgroup v1 vs v2:不同内核/发行版可能使用不同 cgroup 版本,相关文件/控制器名会不同(例如
- blkio ↔ io)。CentOS7 默认通常是 cgroup v1。
- IO 限制依赖底层设备:在云/虚拟机上测试时,注意底层虚拟磁盘的行为。
- 生产环境:建议配合监控(Prometheus + cAdvisor / node-exporter)来持续观察容器资源使用
- 情况并调优。
- 权限:修改 /sys/fs/cgroup/* 需要 root 权限;Docker run 的限制设置通常更简单、安全。
Data Volumes Containers
数据卷
数据卷是 Docker 中一种专门为容器提供持久化存储的机制。它是容器内部的特殊目录,可以与宿主机或其他容器共享数据。通过使用数据卷,容器可以在其生命周期内访问和修改数据,而不会影响镜像本身。这样一来,数据卷能够保持数据持久性,即使容器被删除或重建,数据依然能够保留。
创建与挂载数据卷
使用 docker run 命令启动一个容器时,可以通过 -v 或 --mount 选项将宿主机的目录挂载到容器中的数据卷。下面是一个简单的例子:
docker run -v /var/www:/data1 --name web1 -it centos:7 /bin/bash
- -v /var/www:/data1: 将宿主机上的 /var/www 目录挂载到容器中的 /data1 目录。这样容器内
- /data1 的修改会同步到宿主机上的 /var/www。
- --name web1: 给容器指定一个名称 web1。
- -it centos:7 /bin/bash: 使用 centos:7 镜像启动容器并进入交互式 shell。
在数据卷中写入数据
进入容器后,可以在 /data1 目录下创建文件:
echo "this is web1" > /data1/abc.txt
此时,容器中的 /data1/abc.txt 文件与宿主机中的 /var/www/abc.txt 文件是同步的。即使容器退
出,宿主机上的数据依然存在。
查看宿主机的数据
退出容器后,返回宿主机查看数据是否已成功同步:
cat /var/www/abc.txt
你应该能看到容器中写入的数据内容:this is web1。
数据卷容器
数据卷容器是一种专门用于共享数据的容器,它不是用于运行应用程序的容器,而是仅仅提供一个数据卷,供其他容器挂载并使用。这种方式常用于多个容器共享数据,避免数据丢失或重复管理。
创建数据卷容器
首先,创建一个数据卷容器 web2,并挂载多个数据卷:
docker run --name web2 -v /data1 -v /data2 -it centos:7 /bin/bash
- --name web2: 给容器命名为 web2。
- -v /data1 -v /data2: 在容器内部挂载了两个数据卷 /data1 和 /data2。这些数据卷不依赖于宿主机,而是仅仅存在于容器内。
在数据卷容器中写入数据
进入 web2 容器后,可以在 /data1 和 /data2 目录下写入数据:
echo "this is web2" > /data1/abc.txt
echo "THIS IS WEB2" > /data2/ABC.txt
使用 --volumes-from 共享数据卷
接下来,创建一个新的容器 web3,并通过 --volumes-from 选项将 web2 容器中的数据卷挂载到
web3 容器中:
docker run -it --volumes-from web2 --name web3 centos:7 /bin/bash
- --volumes-from web2: 这表示将容器 web2 中的所有数据卷挂载到新容器 web3 中。
在新容器中查看数据
进入 web3 容器后,查看 web2 容器中的数据:
cat /data1/abc.txt
cat /data2/ABC.txt
看到如下:
this is web2
THIS IS WEB2
小结
- 数据卷 (Data Volumes) 是容器中的特殊目录,用于持久化存储数据。它可以通过宿主机的目录进行挂载,实现容器与宿主机之间的数据共享。
- 数据卷容器 (Data Volumes Containers) 允许容器之间共享数据卷,避免每个容器都需要挂载宿主机目录。使用 --volumes-from 可以让多个容器共享同一数据卷。
端口映射
在 Docker 中,容器内部运行的服务默认是不能被外部网络访问的。如果需要让外部网络能够访问容器中的服务,就需要使用端口映射机制。端口映射将宿主机的端口映射到容器内的端口,从而使得外部网络能够通过访问宿主机的端口,进而访问容器内的服务。
随机端口映射
如果不指定端口,Docker 会自动为容器的服务分配一个随机端口(通常从 32768 开始)。这种方式适用于无需指定端口号的场景。
命令示例:
docker run -d --name test1 -P nginx
- -P: 自动将容器内部暴露的端口映射到宿主机上的随机端口。
- nginx: 使用 nginx 镜像启动容器。
运行后,可以通过 docker ps -a 查看容器的状态,特别是端口映射信息:
docker ps -a
输出示例:
CONTAINER ID IMAGE COMMAND CREATED STATUS
PORTS NAMES
9d3c04f57a68 nginx "/docker-entrypoint...." 4 seconds ago Up 3 seconds
0.0.0.0:49170->80/tcp test1
此时,test1 容器内部的端口 80 被映射到宿主机的端口 49170。你可以通过浏览器访问:
http://192.168.80.10:49170
指定端口映射
如果你希望容器内的服务映射到宿主机上的指定端口,可以使用 -p 选项手动指定端口映射。
命令示例:
docker run -d --name test2 -p 43000:80 nginx
- -p 43000:80: 将宿主机的端口 43000 映射到容器内的端口 80。这意味着你可以通过访问宿主机的 43000 端口来访问容器中的 Nginx 服务。
运行后,通过 docker ps -a 查看容器的状态,特别是端口映射信息:
docker ps -a
输出示例:
CONTAINER ID IMAGE COMMAND CREATED STATUS
PORTS NAMES
b04895f870e5 nginx "/docker-entrypoint...." 17 seconds ago Up 15 seconds
0.0.0.0:43000->80/tcp test2
此时,test2 容器内部的端口 80 被映射到宿主机的端口 43000。你可以通过浏览器访问:
http://192.168.80.10:43000
总结
- 随机端口映射:使用 -P 选项,Docker 会自动为容器暴露的端口分配一个随机的宿主机端口,适用于无需手动指定端口的情况。
- 指定端口映射:使用 -p <宿主机端口>:<容器端口> 的格式,手动指定宿主机和容器之间的端口映射关系,适用于需要明确指定端口的场景。
通过端口映射,容器内的服务可以轻松暴露给外部网络,供外界访问。
容器互联
容器互联是一种让容器之间能够通过网络相互通信的机制。通过在容器间建立网络通信隧道,源容器和接收容器可以互相看到对方的指定信息。Docker 提供了 --link 选项来实现容器互联,在一个容器中可以通过另一个容器的名称来访问它。
创建并运行源容器 web1
首先,创建并运行源容器 web1,它将作为通信的源容器。使用 CentOS 镜像启动容器,并让容器在后台运行:
docker run -itd -P --name web1 centos:7 /bin/bash
- -itd: 启动容器并使其在后台运行。
- -P: 随机映射容器的端口到宿主机。
- --name web1: 给容器指定一个名称 web1。
- centos:7: 使用 CentOS 7 镜像启动容器。
- /bin/bash: 启动后进入容器的 bash shell。
创建并运行接收容器 web2
接下来,创建并运行接收容器 web2,并使用 --link 选项来连接容器 web1,从而实现容器间的通信。
docker run -itd -P --name web2 --link web1:web1 centos:7 /bin/bash
- --link web1:web1: 通过 --link 选项连接 web1 容器,将 web1 容器暴露给 web2 容器,并在web2 中将 web1 显示为别名 web1。这样 web2 容器就可以通过 web1 访问源容器的信息。
在接收容器 web2 中测试连接
进入容器 web2,然后尝试 ping web1 容器,验证是否可以与 web1 容器通信:
docker exec -it web2 bash
ping web1
- docker exec -it web2 bash: 进入 web2 容器的 bash 环境。
- ping web1: 测试 web2 是否能与 web1 通信。
如果连接成功,说明容器互联配置正确。
小结
- 源容器:通过 docker run 启动,并通过 --name 指定一个唯一名称,例如 web1。
- 接收容器:通过 docker run 启动,并通过 --link 选项将其与源容器 web1 连接。--link 会将
- 源容器暴露为别名,接收容器可以通过该别名与源容器进行通信。
- 容器间通信:接收容器可以通过源容器的名称进行通信,如在 web2 中通过 ping web1 测试与
- web1 的连通性。
这种容器互联的方式适用于简单的容器间网络通信,但在较复杂的场景中,建议使用 Docker 网络(如桥接网络或自定义网络)来管理容器间的通信。
总结
Docker 四大核心机制简明总结:
- cgroups(资源控制):利用 Linux 内核的 cgroups 限制容器的 **CPU、内存、I/O** 等资源使用,防止资源争抢,保障系统稳定性。
- Data Volumes / Data Volume Containers(数据持久化):通过 挂载卷(Volume)或专用 数据卷容器,实现容器数据持久存储与多容器共享,避免容器删除导致数据丢失。
- 端口映射(Port Mapping):使用 `-p 宿主机端口:容器端口`(如 `-p 8080:80`),将容器内服务暴露给外部网络,实现从宿主机或外网访问容器应用。
- 容器互联(Container Networking):早期用 `--link`,现已推荐使用自定义 Docker 网络(`docker network create`),容器可通过名称直接通信,更安全、灵活、可扩展。
✅ 这四项是 Docker 实现 **隔离、持久、互通、可控 的基石,为容器化应用的开发与部署提供核心支撑。
更多推荐



所有评论(0)