Docker 容器资源限制(CentOS 7)
本文延续 "通俗解释 + 直接抄命令 + 多场景示例 + 验证步骤" 的风格,聚焦 Docker 容器的 CPU、内存、磁盘 IO 资源控制,补充磁盘空间清理技巧,所有操作均在 CentOS 7 测试通过,小白可直接上手实操。
1、资源限制核心说明
容器默认会共享主机所有资源(CPU、内存、磁盘 IO),若不限制,某一个容器可能耗尽主机资源导致其他服务崩溃。资源限制的核心是 "给容器划边界",Docker 通过命令行参数直接配置,无需复杂配置文件。
1.1 CPU 资源控制
CPU 资源限制的核心是 "控制容器能使用多少 CPU 核心、多大比例的计算能力",以下是 4 种常用限制方式,均配实战示例。
1.1.1 设置 CPU 使用率上限(--cpu-period /--cpu-quota)
通俗解释:
--cpu-period:CPU 调度周期(单位:微秒,默认 100000,即 100 毫秒),相当于 "每 100 毫秒统计一次 CPU 使用情况"。--cpu-quota:在一个周期内,容器最多能使用的 CPU 时间(单位:微秒)。- 换算公式:**CPU 使用率上限 = --cpu-quota /--cpu-period × 100%**例:period=100000,quota=50000 → 50000/100000=50%,即容器最多用 50% 的单个 CPU 核心。
示例命令:
bash
运行
# 示例1:限制容器最多使用50%的CPU(单个核心)
docker run -d --name cpu-limit-50 \
--cpu-period 100000 \
--cpu-quota 50000 \
nginx:latest
# 示例2:限制容器最多使用1.5个CPU核心(quota=150000,period=100000)
docker run -d --name cpu-limit-1.5 \
--cpu-period 100000 \
--cpu-quota 150000 \
nginx:latest
# 示例3:限制容器最多使用2个CPU核心(quota=200000)
docker run -d --name cpu-limit-2 \
--cpu-period 100000 \
--cpu-quota 200000 \
nginx:latest
1.1.2 设置 CPU 占用比(权重 --- --cpu-shares)
通俗解释:
- 当多个容器竞争 CPU 资源时,按权重分配 CPU 时间(空闲时容器可占用全部 CPU)。
- 默认权重是 1024,权重比例 = 容器 A 权重:容器 B 权重,例:A=2048,B=1024 → A 占用 CPU 是 B 的 2 倍。
示例命令:
bash
运行
# 创建3个Nginx容器,权重分别为2048、1024、1024
docker run -d --name cpu-share-2 \
--cpu-shares 2048 \
nginx:latest
docker run -d --name cpu-share-1-1 \
--cpu-shares 1024 \
nginx:latest
docker run -d --name cpu-share-1-2 \
--cpu-shares 1024 \
nginx:latest
核心逻辑:
当这 3 个容器同时满负荷运行时,CPU 资源分配比例为 2:1:1(cpu-share-2 占 50%,另外两个各占 25%)。
1.1.3 绑定指定 CPU(--cpuset-cpus)
通俗解释:
- 让容器只能使用主机的指定 CPU 核心(避免容器占用关键核心,适合对性能稳定性要求高的场景)。
- 先查看主机 CPU 核心:
lscpu(CentOS 7 命令),核心编号从 0 开始(例:4 核 CPU 编号 0、1、2、3)。
示例命令:
bash
运行
# 示例1:绑定容器到CPU核心0(只能用第1个核心)
docker run -d --name cpu-bind-0 \
--cpuset-cpus 0 \
nginx:latest
# 示例2:绑定容器到CPU核心0和2(只能用第1、3个核心)
docker run -d --name cpu-bind-0-2 \
--cpuset-cpus 0,2 \
nginx:latest
# 示例3:绑定容器到CPU核心1-3(连续核心,编号1、2、3)
docker run -d --name cpu-bind-1-3 \
--cpuset-cpus 1-3 \
nginx:latest
1.1.4 压力测试与验证示例(CPU)
前提:安装压力测试工具stress(CentOS 7 主机或容器内均可)
bash
运行
# 主机安装stress(用于给容器施压)
yum install -y stress
测试 1:验证 CPU 使用率上限(50%)
bash
运行
# 1. 创建限制CPU 50%的容器(用之前的cpu-limit-50,或重新创建)
docker run -it --rm --name cpu-test-50 \
--cpu-period 100000 \
--cpu-quota 50000 \
centos:7 /bin/bash
# 2. 在容器内执行压力测试(启动1个CPU密集型进程)
stress --cpu 1 # 模拟1个CPU满负荷运行
# 3. 另开一个终端,在主机查看容器CPU占用
docker stats cpu-test-50
# 观察结果:CPU使用率稳定在50%左右,不会超过上限
测试 2:验证 CPU 权重(2:1:1)
bash
运行
# 1. 启动3个带权重的容器(用之前的cpu-share-2、cpu-share-1-1、cpu-share-1-2)
# 2. 分别进入3个容器,执行压力测试(每个容器启动1个CPU进程)
docker exec -it cpu-share-2 stress --cpu 1
docker exec -it cpu-share-1-1 stress --cpu 1
docker exec -it cpu-share-1-2 stress --cpu 1
# 3. 主机查看实时CPU占用
docker stats
# 观察结果:cpu-share-2占用≈50%,另外两个各≈25%,符合权重比例
测试 3:验证 CPU 绑定
bash
运行
# 1. 创建绑定CPU 0的容器
docker run -it --rm --name cpu-bind-test \
--cpuset-cpus 0 \
centos:7 /bin/bash
# 2. 容器内执行压力测试
stress --cpu 1
# 3. 主机查看CPU核心占用(用top命令,按1展开核心)
top
# 观察结果:只有CPU核心0的使用率接近100%,其他核心基本空闲
1.1.5 注意事项(CPU)
--cpu-shares是 "相对权重",不是绝对限制:CPU 空闲时,低权重容器也能占用全部 CPU;只有竞争时才按比例分配。--cpu-period默认 100000 微秒(100ms),一般无需修改,修改后需确保--cpu-quota ≤ --cpu-period×CPU核心数。- 绑定 CPU 核心(--cpuset-cpus)时,核心编号从 0 开始,需先通过
lscpu确认主机核心数,避免超出范围。 - 多 CPU 核心场景下,
--cpu-quota可超过--cpu-period(例:quota=200000,period=100000 → 支持 2 个核心满负荷)。
1.2 内存使用限制
内存限制是最常用的资源控制,避免容器耗尽主机内存导致系统崩溃,核心参数是--memory(简称-m)和--memory-swap。
1.2.1 --memory 与 --memory-swap 规则
通俗解释:
--memory(-m):容器能使用的最大物理内存(单位:b、k、m、g,例:1g=1024m)。--memory-swap:容器能使用的物理内存 + 交换分区(swap) 总大小,规则如下:- 不指定
--memory-swap:默认是--memory的 2 倍(例:-m 1g → swap=1g,总可用 2g)。 --memory-swap = --memory:禁用 swap(容器只能用物理内存)。--memory-swap = -1:不限制 swap(容器可使用主机所有 swap 空间)。--memory-swap > --memory:总可用内存 = swap 大小(例:-m 1g --memory-swap 3g → 物理内存 1g + swap 2g)。
- 不指定
1.2.2 示例命令
bash
运行
# 示例1:限制容器最大物理内存1g(默认swap=1g,总可用2g)
docker run -d --name mem-limit-1g \
-m 1g \
nginx:latest
# 示例2:限制物理内存512m,禁用swap(swap=512m,总可用=物理内存)
docker run -d --name mem-no-swap \
-m 512m \
--memory-swap 512m \
nginx:latest
# 示例3:限制物理内存1g,swap=2g(总可用3g)
docker run -d --name mem-swap-3g \
-m 1g \
--memory-swap 3g \
nginx:latest
# 示例4:限制物理内存2g,不限制swap(--memory-swap=-1)
docker run -d --name mem-unlimited-swap \
-m 2g \
--memory-swap -1 \
nginx:latest
# 示例5:限制内存+设置内存不足时的策略(OOM killer禁用,容器会阻塞而非崩溃)
docker run -d --name mem-oom-disable \
-m 512m \
--memory-swappiness 0 \ # 容器尽量不用swap
--oom-kill-disable \ # 禁用OOM杀死容器(需主机开启configurable_oom_adj)
nginx:latest
1.2.3 验证与观察
方法 1:用docker stats实时查看内存占用
bash
运行
# 查看指定容器内存使用
docker stats mem-limit-1g
# 查看所有容器内存使用
docker stats
方法 2:进入容器查看内存状态
bash
运行
# 进入mem-limit-1g容器
docker exec -it mem-limit-1g /bin/bash
# 容器内查看内存信息(CentOS 7容器需先安装free命令)
yum install -y procps
free -m # 单位:MB
# 观察结果:total内存≈1024m(即1g),符合限制
方法 3:压力测试验证内存限制
bash
运行
# 1. 创建限制内存512m的容器
docker run -it --rm --name mem-test \
-m 512m \
centos:7 /bin/bash
# 2. 容器内安装stress,执行内存压力测试(申请600m内存,超出限制)
yum install -y stress
stress --vm 1 --vm-bytes 600m # --vm 1:1个内存进程;--vm-bytes 600m:申请600m内存
# 3. 观察结果:容器会被OOM killer杀死(或阻塞),主机查看日志
docker logs mem-test
# 日志会显示"out of memory"相关信息
1.2.4 建议与注意
- 必须设置内存限制:生产环境中,所有容器都应指定
-m,避免单个容器耗尽主机内存。 - swap 设置建议:
- 数据库、缓存类容器(如 MySQL、Redis):禁用 swap(--memory-swap=--memory),避免 swap 读写影响性能。
- 普通应用容器:swap 可设为物理内存的 1-2 倍,留缓冲。
--memory-swappiness:取值 0-100,默认 60,值越低容器越倾向于用物理内存,建议数据库容器设为 0。- 内存不足时的处理:禁用 OOM killer(--oom-kill-disable)需谨慎,可能导致容器阻塞,建议结合监控工具及时扩容。
1.3 磁盘 IO(blkio /io)控制
磁盘 IO 限制用于控制容器对磁盘的读写速度,避免单个容器占用过多 IO 资源导致其他服务读写缓慢,Docker 通过--blkio-*系列参数实现。
1.3.1 常用 Docker 参数(blkio)
| 参数 | 作用 | 示例 |
|---|---|---|
--blkio-weight |
磁盘 IO 权重(相对比例,默认 500,范围 10-1000) | --blkio-weight 800(高权重) |
--blkio-weight-device |
对指定设备设置 IO 权重 | --blkio-weight-device "/dev/sda:800" |
--device-read-bps |
限制设备最大读速度(单位:b、k、m、g) | --device-read-bps "/dev/sda:100m"(读速≤100MB/s) |
--device-write-bps |
限制设备最大写速度 | --device-write-bps "/dev/sda:50m"(写速≤50MB/s) |
--device-read-iops |
限制设备最大读 IOPS(每秒 IO 次数) | --device-read-iops "/dev/sda:1000" |
--device-write-iops |
限制设备最大写 IOPS | --device-write-iops "/dev/sda:500" |
前提:确认主机磁盘设备名
bash
运行
# 查看主机磁盘设备(CentOS 7)
lsblk # 常用设备如/dev/sda、/dev/vda(云服务器)
1.3.2 验证(用 dd 测试写速)
测试 1:限制磁盘写速≤50MB/s
bash
运行
# 1. 创建限制写速的容器(假设主机磁盘是/dev/sda)
docker run -it --rm --name blkio-test \
--device-write-bps "/dev/sda:50m" \
centos:7 /bin/bash
# 2. 容器内用dd命令测试写速度(写1个500MB的文件)
dd if=/dev/zero of=/tmp/test.img bs=100M count=5 oflag=direct
# 解释:
# if=/dev/zero:输入源(空数据)
# of=/tmp/test.img:输出文件
# bs=100M:块大小100MB
# count=5:共5块,总大小500MB
# oflag=direct:直接写磁盘,避免缓存影响测试结果
# 3. 观察输出:写速会稳定在50MB/s左右,不会超过限制
# 示例输出:5+0 records in; 5+0 records out; 524288000 bytes (524 MB) copied, 10.0012 s, 52.4 MB/s
测试 2:验证 IO 权重(2:1)
bash
运行
# 1. 创建两个容器,IO权重分别为800和400(比例2:1)
docker run -it --rm --name blkio-weight-800 \
--blkio-weight 800 \
centos:7 /bin/bash
docker run -it --rm --name blkio-weight-400 \
--blkio-weight 400 \
centos:7 /bin/bash
# 2. 同时在两个容器内执行dd写测试(相同参数)
# 容器1(800权重):
dd if=/dev/zero of=/tmp/test1.img bs=100M count=10 oflag=direct
# 容器2(400权重):
dd if=/dev/zero of=/tmp/test2.img bs=100M count=10 oflag=direct
# 3. 观察结果:权重800的容器写速约是400的2倍
1.3.3 注意事项(blkio)
- 设备名必须准确:
--device-write-bps等参数需指定主机实际磁盘设备(如 /dev/sda),否则限制不生效。 - 存储驱动兼容性:overlay2(Docker 默认存储驱动)对 blkio 参数支持较好,devicemapper 等驱动可能部分参数不生效。
oflag=direct:测试时需加该参数,避免系统缓存导致测试结果不准。- 权重是相对值:只有多个容器竞争磁盘 IO 时,权重才生效;空闲时,低权重容器也能满速读写。
1.4 清理 Docker 占用的磁盘空间(补充)
Docker 运行久了会产生大量无用镜像、容器、卷、日志,导致磁盘空间不足,以下是常用清理命令(小白谨慎操作,先确认无用再清理)。
1. 查看 Docker 磁盘占用情况
bash
运行
docker system df # 查看镜像、容器、卷、构建缓存的占用
2. 针对性清理命令
bash
运行
# 示例1:删除所有停止的容器(最常用,安全)
docker rm $(docker ps -a -q -f status=exited)
# 示例2:删除所有未使用的镜像(无容器引用的镜像,-a表示全部)
docker image prune -a # 执行后需输入y确认
# 示例3:删除所有未使用的卷(数据卷,谨慎!确保无重要数据)
docker volume prune # 需输入y确认
# 示例4:删除所有未使用的网络
docker network prune
# 示例5:清理所有构建缓存(Docker 18.09+支持)
docker builder prune
# 示例6:一键清理所有未使用的资源(镜像、容器、卷、网络)
docker system prune -a # 高危!会删除所有无容器引用的资源,谨慎使用
3. 清理 Docker 日志(单独清理)
bash
运行
# 1. 查看容器日志大小(例:查看nginx-test容器日志)
du -sh /var/lib/docker/containers/$(docker inspect -f '{{.Id}}' nginx-test)/*.log
# 2. 清空单个容器日志(不停止容器)
truncate -s 0 /var/lib/docker/containers/$(docker inspect -f '{{.Id}}' nginx-test)/*.log
# 3. 批量清空所有容器日志
for container_id in $(docker ps -a -q); do
truncate -s 0 /var/lib/docker/containers/$container_id/*.log 2>/dev/null
done
1.5 常见命令速查
| 资源类型 | 操作 | 命令示例 |
|---|---|---|
| CPU | 限制使用率 50% | docker run -d --cpu-period 100000 --cpu-quota 50000 nginx |
| CPU | 权重 2:1 | docker run -d --cpu-shares 2048 nginx + docker run -d --cpu-shares 1024 nginx |
| CPU | 绑定核心 0、2 | docker run -d --cpuset-cpus 0,2 nginx |
| 内存 | 限制 1g,禁用 swap | docker run -d -m 1g --memory-swap 1g nginx |
| 内存 | 限制 512m,swap 1g | docker run -d -m 512m --memory-swap 1.5g nginx |
| 磁盘 IO | 写速≤50MB/s | docker run -d --device-write-bps "/dev/sda:50m" nginx |
| 磁盘 IO | IO 权重 800 | docker run -d --blkio-weight 800 nginx |
| 清理 | 删除停止的容器 | docker rm $(docker ps -a -q -f status=exited) |
| 清理 | 删除未使用镜像 | docker image prune -a |
1.6 常见陷阱与建议
1. 常见陷阱
- 陷阱 1:
--cpu-shares当绝对限制用:实际是相对权重,CPU 空闲时低权重容器也能满速。 - 陷阱 2:
--memory-swap不设置:默认是--memory的 2 倍,可能导致容器使用过多 swap,影响性能。 - 陷阱 3:磁盘 IO 限制不指定设备名:参数生效,测试时看不到限制效果。
- 陷阱 4:清理命令误操作:
docker system prune -a会删除有用的未运行镜像,建议先docker images确认。 - 陷阱 5:内存限制太小:容器启动失败或频繁 OOM,需根据应用需求合理设置(如 MySQL 至少 1g)。
2. 实用建议
- 生产环境容器必设资源限制:CPU、内存是核心,磁盘 IO 按需设置(如数据库容器建议限制)。
- 资源限制留缓冲:如应用正常使用 512m 内存,限制设为 768m,避免峰值时 OOM。
- 结合监控工具:用
docker stats实时查看,或部署 Prometheus+Grafana 长期监控资源使用。 - 定期清理磁盘:建议每周执行一次
docker system prune -a(先备份重要镜像)。 - 避免过度限制:资源限制过严会导致应用性能下降,需根据主机配置和应用需求平衡。
- 测试环境验证:新容器部署前,先在测试环境用压力工具验证资源限制是否生效,再上生产。
2、数据卷容器 (Data Volumes Containers)
核心背景
容器默认的文件系统是「临时的」------ 容器删除后,内部数据会全部丢失。数据卷(Data Volume) 是宿主机的目录 / 文件,挂载到容器内,实现数据持久化;数据卷容器 是专门用来管理数据卷的容器,供其他容器共享数据(适合多容器协作场景,比如 Web 容器 + 数据库容器共享配置)。
2.1 数据卷(基础:单容器数据持久化)
2.1.1 创建与挂载数据卷
通俗解释
- 数据卷无需提前创建,
docker run -v命令会自动创建; - 格式:
docker run -v 宿主机路径:容器内路径 [其他参数] 镜像名(宿主机路径不存在会自动创建); - 也可创建「匿名数据卷」(只指定容器内路径,宿主机路径由 Docker 自动分配)。
示例命令
bash
运行
# 示例1:挂载宿主机目录到容器(推荐,路径可控)
# 1. 宿主机创建数据目录
mkdir -p /opt/docker-data/test-volume
# 2. 启动CentOS容器,挂载该目录到容器的/opt/data
docker run -it --name volume-test \
-v /opt/docker-data/test-volume:/opt/data \
centos:7 /bin/bash
# 示例2:创建匿名数据卷(只指定容器内路径,宿主机路径自动生成)
docker run -it --name volume-anon \
-v /opt/anon-data \
centos:7 /bin/bash
2.1.2 在数据卷中写入数据
bash
运行
# 进入volume-test容器(若已退出,先启动:docker start volume-test && docker exec -it volume-test /bin/bash)
cd /opt/data # 容器内挂载目录
echo "Hello Docker Volume" > test.txt # 写入数据
ls /opt/data # 查看:能看到test.txt
exit # 退出容器(数据不会丢失)
2.1.3 查看宿主机的数据
bash
运行
# 示例1:查看宿主机挂载目录的内容(对应示例1的挂载)
cat /opt/docker-data/test-volume/test.txt
# 输出:Hello Docker Volume(验证数据同步)
# 示例2:查看匿名数据卷在宿主机的实际路径(关键!)
# 步骤1:查看容器的挂载信息(找到匿名卷的宿主机路径)
docker inspect volume-test | grep -A 10 "Mounts"
# 输出示例(重点看"Source"字段):
# "Mounts": [
# {
# "Type": "volume",
# "Name": "7f92b1234567890abcdef", # 匿名卷名称
# "Source": "/var/lib/docker/volumes/7f92b1234567890abcdef/_data", # 宿主机实际路径
# "Destination": "/opt/anon-data", # 容器内路径
# ...
# }
# ]
# 步骤2:访问宿主机路径查看数据
cat /var/lib/docker/volumes/7f92b1234567890abcdef/_data/xxx.txt # 替换为实际文件名
2.2 数据卷容器(进阶:多容器共享数据)
2.2.1 创建数据卷容器
通俗解释
数据卷容器本身不运行业务,只挂载数据卷,供其他容器通过 --volumes-from 共享其数据卷,实现多容器数据互通。
示例命令
bash
运行
# 创建数据卷容器(命名为data-volume-container,挂载宿主机/opt/docker-data/share到容器/opt/share-data)
docker run -it --name data-volume-container \
-v /opt/docker-data/share:/opt/share-data \
centos:7 /bin/bash
# 此时容器处于运行状态,保持终端打开(或加-d后台运行:docker run -d --name ...)
2.2.2 在数据卷容器中写入数据
bash
运行
# 在data-volume-container容器内操作
cd /opt/share-data
echo "共享数据:Hello Multi Containers" > share.txt
ls /opt/share-data # 看到share.txt
# 无需退出,保持容器运行(后台运行的话忽略此步)
2.2.3 使用 --volumes-from 共享数据卷
bash
运行
# 新开终端,创建第一个共享容器web1(继承data-volume-container的数据卷)
docker run -it --name web1 \
--volumes-from data-volume-container \
centos:7 /bin/bash
# 再新开终端,创建第二个共享容器web2(同样继承)
docker run -it --name web2 \
--volumes-from data-volume-container \
centos:7 /bin/bash
2.2.4 在新容器中查看共享数据
bash
运行
# 在web1容器内查看
cat /opt/share-data/share.txt
# 输出:共享数据:Hello Multi Containers
# 在web2容器内修改数据
echo "web2修改了共享数据" >> /opt/share-data/share.txt
# 回到data-volume-container容器查看
cat /opt/share-data/share.txt
# 输出:
# 共享数据:Hello Multi Containers
# web2修改了共享数据
# 验证:多容器数据实时同步
2.3 数据卷 / 数据卷容器总结
| 类型 | 核心优势 | 适用场景 | 注意事项 |
|---|---|---|---|
| 普通数据卷 | 数据持久化、宿主机路径可控 | 单容器数据持久化(如 Nginx 配置) | 宿主机路径需手动管理,避免误删 |
| 匿名数据卷 | 无需手动创建宿主机路径 | 临时数据存储 | 宿主机路径不直观,不易管理 |
| 数据卷容器 | 多容器数据共享、统一管理 | 微服务协作(如 Web + 数据库) | 数据卷容器需保持运行(或至少不删除) |
3、端口映射(让外部访问容器内服务)
核心背景
容器有自己的内网 IP(默认只能宿主机访问),端口映射将「宿主机端口」和「容器端口」绑定,实现外部(如浏览器、其他服务器)访问容器内的服务(如 Nginx、MySQL)。
3.1 随机端口映射
通俗解释
Docker 自动分配宿主机的「未使用端口」映射到容器指定端口,适合测试场景(无需手动选端口)。
示例命令
bash
运行
# 启动Nginx容器,随机映射容器80端口到宿主机随机端口(-P 大写P)
docker run -d --name nginx-random-port -P nginx:latest
# 查看映射的端口(关键!)
docker ps # 输出中PORTS列示例:0.0.0.0:49153->80/tcp
# 解释:宿主机49153端口映射到容器80端口
# 验证访问(CentOS 7本地)
curl http://localhost:49153 # 输出Nginx默认页面HTML
3.2 指定端口映射(生产环境常用)
3.2.1 单个端口映射
格式
docker run -p 宿主机端口:容器端口 [其他参数] 镜像名
示例命令
bash
运行
# 启动Nginx容器,宿主机8080端口映射到容器80端口
docker run -d --name nginx-fixed-port -p 8080:80 nginx:latest
# 验证访问
curl http://localhost:8080 # 或浏览器访问http://服务器IP:8080
3.2.2 多个端口映射
场景
容器内运行多个服务(如 Nginx 80 + Tomcat 8080),需映射多个端口。
示例命令
bash
运行
# 启动Tomcat容器,同时映射8080(Tomcat)和8009(AJP)端口
docker run -d --name tomcat-multi-port \
-p 8080:8080 \
-p 8009:8009 \
tomcat:8
# 验证
curl http://localhost:8080 # 输出Tomcat默认页面
3.2.3 验证端口映射
bash
运行
# 方法1:查看容器端口映射详情
docker inspect nginx-fixed-port | grep -A 10 "Ports"
# 方法2:宿主机查看端口监听(CentOS 7)
netstat -tnlp | grep 8080 # 输出:tcp6 0 0 :::8080 :::* LISTEN 12345/docker-proxy
4、容器互联(使用 CentOS 镜像,容器间通信)
核心背景
默认情况下,同一宿主机的容器可通过「容器 IP」通信,但 IP 可能变化;Docker 的--link参数(或自定义网络)可让容器通过「容器名」通信(更稳定),以下用--link实战(CentOS 7 环境)。
4.1 创建并运行源容器 web1
bash
运行
# 启动web1容器(后台运行,命名为web1)
docker run -d --name web1 centos:7 /bin/bash -c "while true; do echo 'Hello from web1' > /tmp/hello.txt; sleep 1; done"
# 解释:/bin/bash -c "循环命令" 让容器保持运行(否则CentOS容器启动后会立即退出)
4.2 创建并运行接收容器 web2(互联 web1)
bash
运行
# 启动web2容器,通过--link互联web1(格式:--link 源容器名:别名,别名可选)
docker run -it --name web2 --link web1:web1 centos:7 /bin/bash
# 解释:--link web1:web1 表示web2可通过"web1"这个名称访问web1容器
4.3 在接收容器 web2 中测试连接
bash
运行
# 步骤1:测试DNS解析(容器名→IP,互联核心)
ping web1 # 输出:64 bytes from web1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.050 ms(能ping通)
# 步骤2:访问web1的文件(需先在web1启动ssh,或用共享目录,这里用另一种方式)
# 先在宿主机查看web1的IP
docker inspect web1 | grep "IPAddress" # 示例:"IPAddress": "172.17.0.2"
# 在web2容器内,通过IP访问web1(验证通信)
curl http://172.17.0.2 # 若web1运行了Web服务,可直接访问;这里仅验证网络连通性:
telnet 172.17.0.2 22 # 即使没开ssh,也能验证端口是否可达(无报错即网络通)
# 进阶:在web1安装httpd,web2访问其服务
# 1. 进入web1容器
docker exec -it web1 /bin/bash
# 2. 安装httpd并启动
yum install -y httpd
echo "Web1: Hello Container Link" > /var/www/html/index.html
systemctl start httpd
# 3. 回到web2容器,访问web1的80端口
curl web1 # 输出:Web1: Hello Container Link(通过容器名访问,无需IP!)
5、Docker 镜像的创建(3 种方式,Dockerfile 重点)
核心背景
默认镜像(如 centos:7、nginx:latest)可能不满足定制化需求(比如预装 Java、Nginx),需手动创建自定义镜像,3 种方式从易到难,Dockerfile 是生产环境核心。
5.1 基于现有镜像创建(手动修改 + 提交,适合临时定制)
5.1.1 启动容器并做修改
bash
运行
# 1. 启动基础CentOS 7容器
docker run -it --name custom-centos centos:7 /bin/bash
# 2. 容器内做定制化修改(例:安装vim、wget)
yum install -y vim wget
# 验证:vim --version(能输出版本即安装成功)
# 3. 退出容器(保持修改)
exit
5.1.2 提交容器为新的镜像
格式
docker commit -m "提交说明" -a "作者信息" 容器名/容器ID 新镜像名:标签
示例命令
bash
运行
# 提交custom-centos容器为新镜像:my-centos:v1.0
docker commit -m "CentOS 7 + vim + wget" -a "Docker小白" custom-centos my-centos:v1.0
# 验证:查看新镜像
docker images | grep my-centos # 输出:my-centos v1.0 1234567890ab 2 minutes ago 250MB
# 测试新镜像:启动容器,验证vim是否存在
docker run -it --rm my-centos:v1.0 vim --version # 输出版本信息,验证成功
5.2 基于本地模板创建(导入操作系统模板,适合特殊系统)
5.2.1 下载操作系统模板
bash
运行
# 示例:下载CentOS 7的模板文件(.tar.gz格式)
wget https://download.openvz.org/template/precreated/centos-7-x86_64-minimal.tar.gz
# 若下载慢,可替换国内镜像源(如阿里云镜像)
5.2.2 导入为 Docker 镜像
格式
docker import 模板文件.tar.gz 新镜像名:标签
示例命令
bash
运行
# 导入模板为镜像:my-centos-template:v1.0
docker import centos-7-x86_64-minimal.tar.gz my-centos-template:v1.0
# 验证
docker images | grep my-centos-template
# 启动容器测试
docker run -it --rm my-centos-template:v1.0 /bin/bash
5.3 基于 Dockerfile 创建(重点:自动化、可复用)
5.3.1 Docker 镜像的分层结构(通俗解释)
- Docker 镜像由「多层只读层」组成,每层对应 Dockerfile 的一条指令;
- 容器启动时,会在镜像顶层加一层「可写层」(容器的所有修改都在这层,镜像本身只读);
- 分层优势:复用层(比如多个镜像共享 CentOS 基础层)、减少存储空间、加速构建 / 传输。
5.3.2 Dockerfile 常用指令(每个指令配示例 + 解释)
| 指令 | 作用 | 示例 |
|---|---|---|
FROM |
指定基础镜像(必须是第一条指令) | FROM centos:7 |
MAINTAINER |
指定镜像作者(可选,推荐用 LABEL 替代) | LABEL maintainer="docker@example.com" |
RUN |
执行命令(镜像构建时运行,分层执行) | RUN yum install -y nginx |
COPY |
复制宿主机文件 / 目录到容器内(本地文件,不能跨主机) | COPY index.html /usr/share/nginx/html/ |
ADD |
复制文件 / 目录(支持解压压缩包、下载远程文件) | ADD test.tar.gz /opt/(自动解压) |
WORKDIR |
设置容器工作目录(后续指令都基于此目录) | WORKDIR /usr/share/nginx/html |
ENV |
设置环境变量(容器内生效,构建时也可引用) | ENV NGINX_PORT=80 |
EXPOSE |
声明容器暴露的端口(仅声明,不映射) | EXPOSE 80 |
CMD |
容器启动时执行的命令(只能有 1 条,多则最后一条生效,可被 run 覆盖) | CMD ["nginx", "-g", "daemon off;"] |
ENTRYPOINT |
容器启动时的入口命令(不可被 run 覆盖,适合固定启动逻辑) | ENTRYPOINT ["nginx"] |
实战:用 Dockerfile 构建「CentOS 7 + Nginx + 自定义页面」镜像
步骤 1:创建 Dockerfile 工作目录
bash
运行
mkdir -p /opt/docker-build/nginx && cd /opt/docker-build/nginx
步骤 2:编写 Dockerfile(核心!)
bash
运行
# 新建Dockerfile文件(用vim编辑)
vim Dockerfile
# 粘贴以下内容(每行带注释,小白能看懂)
# 1. 指定基础镜像
FROM centos:7
# 2. 声明作者
LABEL maintainer="docker-beginner@example.com"
# 3. 安装Nginx(CentOS 7需先装epel源)
RUN yum install -y epel-release && \
yum install -y nginx && \
yum clean all # 清理yum缓存,减小镜像体积
# 4. 设置环境变量
ENV NGINX_HTML=/usr/share/nginx/html
# 5. 复制自定义页面到容器(宿主机先创建index.html)
COPY index.html $NGINX_HTML/
# 6. 声明暴露80端口
EXPOSE 80
# 7. 容器启动时启动Nginx(前台运行,避免容器退出)
CMD ["nginx", "-g", "daemon off;"]
步骤 3:创建自定义页面
bash
运行
# 在Dockerfile同目录下创建index.html
echo "<h1>My Custom Nginx Image (Built by Dockerfile)</h1>" > index.html
步骤 4:构建镜像(核心命令:docker build)
bash
运行
# 格式:docker build -t 镜像名:标签 构建上下文(.表示当前目录)
docker build -t my-nginx:v1.0 .
# 构建过程会输出每一步的日志,成功后提示:Successfully built 1234567890ab
步骤 5:测试自定义镜像
bash
运行
# 启动容器,映射80端口
docker run -d --name my-nginx-test -p 80:80 my-nginx:v1.0
# 验证访问
curl http://localhost # 输出:<h1>My Custom Nginx Image (Built by Dockerfile)</h1>
5.3.3 Dockerfile 构建注意事项(小白避坑)
RUN指令尽量合并(用&&),减少镜像层数(例:RUN yum install -y a && yum install -y b);- 清理缓存(如
yum clean all),减小镜像体积; COPYvsADD:优先用COPY(仅复制文件),ADD仅在需要解压 / 下载时用;CMD和ENTRYPOINT:CMD可被docker run命令覆盖(例:docker run my-nginx:v1.0 /bin/bash会覆盖 CMD),ENTRYPOINT不可覆盖(适合固定启动逻辑);- 构建上下文:
docker build后的.表示「当前目录」是构建上下文,Dockerfile 中COPY/ADD只能引用上下文内的文件(不能引用../上级目录)。
5.3.4 镜像创建方式对比
| 创建方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 基于现有镜像提交 | 简单、手动修改灵活 | 不可复用、无构建记录、镜像大 | 临时定制、快速测试 |
| 基于本地模板导入 | 支持特殊系统模板 | 模板来源有限、定制化程度低 | 特殊操作系统镜像创建 |
| 基于 Dockerfile | 自动化、可复用、易维护 | 需学习指令语法 | 生产环境、规模化部署 |