文章目录
- 前言
- 一、Docker网络管理
-
- [1.1 Docker网络实现原理](#1.1 Docker网络实现原理)
- [1.2 Docker端口映射](#1.2 Docker端口映射)
-
- [1.2.1 随机端口映射](#1.2.1 随机端口映射)
- [1.2.2 指定端口映射](#1.2.2 指定端口映射)
- [1.2.3 Docker端口映射总结](#1.2.3 Docker端口映射总结)
- [1.3 Docker的网络模式](#1.3 Docker的网络模式)
-
- [1.3.1 host模式(与宿主机共享网络栈)](#1.3.1 host模式(与宿主机共享网络栈))
- [1.3.2 Container模式(与其他容器共享网络栈)](#1.3.2 Container模式(与其他容器共享网络栈))
- [1.3.3 无网络模式(none)](#1.3.3 无网络模式(none))
- [1.3.4 桥接模式(bridge)](#1.3.4 桥接模式(bridge))
- [1.3.5 自定义模式](#1.3.5 自定义模式)
- [1.3.6 Docker网络模式总结](#1.3.6 Docker网络模式总结)
- 二、Docker资源控制(Docker优化)
-
- [2.1 CPU资源控制](#2.1 CPU资源控制)
-
- [2.1.1 设置CPU使用率上限(--cpu-period / --cpu-quota)](#2.1.1 设置CPU使用率上限(--cpu-period / --cpu-quota))
- [2.1.2 设置CPU占用比(权重 --- --cpu-shares)](#2.1.2 设置CPU占用比(权重 — --cpu-shares))
- [2.1.3 绑定指定CPU(--cpuset-cpus)](#2.1.3 绑定指定CPU(--cpuset-cpus))
- [2.1.4 CPU压力测试与验证示例](#2.1.4 CPU压力测试与验证示例)
- [2.1.5 CPU资源控制注意事项](#2.1.5 CPU资源控制注意事项)
- [2.2 内存使用限制](#2.2 内存使用限制)
-
- [2.2.1 --memory与--memory-swap规则](#2.2.1 --memory与--memory-swap规则)
- [2.2.2 内存限制示例命令](#2.2.2 内存限制示例命令)
- [2.2.3 内存限制验证与OOM行为](#2.2.3 内存限制验证与OOM行为)
- [2.2.4 内存限制建议与注意](#2.2.4 内存限制建议与注意)
- [2.3 磁盘IO(blkio/io)控制](#2.3 磁盘IO(blkio/io)控制)
-
- [2.3.1 常用Docker磁盘IO限制参数](#2.3.1 常用Docker磁盘IO限制参数)
- [2.3.2 磁盘IO限制验证(dd测试)](#2.3.2 磁盘IO限制验证(dd测试))
- [2.3.3 磁盘IO控制注意事项](#2.3.3 磁盘IO控制注意事项)
- [2.4 清理Docker占用的磁盘空间](#2.4 清理Docker占用的磁盘空间)
- [2.5 Docker资源控制常见命令速查](#2.5 Docker资源控制常见命令速查)
- [2.6 Docker资源控制常见陷阱与建议](#2.6 Docker资源控制常见陷阱与建议)
- [三、Docker数据卷容器(Data Volumes Containers)](#三、Docker数据卷容器(Data Volumes Containers))
-
- [3.1 数据卷](#3.1 数据卷)
-
- [3.1.1 创建与挂载数据卷](#3.1.1 创建与挂载数据卷)
- [3.1.2 在数据卷中写入数据](#3.1.2 在数据卷中写入数据)
- [3.1.3 查看宿主机同步的数据](#3.1.3 查看宿主机同步的数据)
- [3.2 数据卷容器](#3.2 数据卷容器)
-
- [3.2.1 创建数据卷容器](#3.2.1 创建数据卷容器)
- [3.2.2 在数据卷容器中写入数据](#3.2.2 在数据卷容器中写入数据)
- [3.2.3 使用--volumes-from共享数据卷](#3.2.3 使用--volumes-from共享数据卷)
- [3.2.4 在新容器中验证共享数据](#3.2.4 在新容器中验证共享数据)
- [3.3 数据卷与数据卷容器总结](#3.3 数据卷与数据卷容器总结)
- 四、Docker容器互联(使用CentOS镜像)
-
- [4.1 创建并运行源容器web1](#4.1 创建并运行源容器web1)
- [4.2 创建并运行接收容器web2(--link互联)](#4.2 创建并运行接收容器web2(--link互联))
- [4.3 在接收容器web2中测试连接](#4.3 在接收容器web2中测试连接)
- [4.4 Docker容器互联总结](#4.4 Docker容器互联总结)
- 五、Docker镜像的创建
-
- [5.1 基于现有镜像创建](#5.1 基于现有镜像创建)
-
- [5.1.1 启动容器并进行修改](#5.1.1 启动容器并进行修改)
- [5.1.2 提交容器为新镜像](#5.1.2 提交容器为新镜像)
- [5.2 基于本地模板创建](#5.2 基于本地模板创建)
-
- [5.2.1 下载操作系统模板](#5.2.1 下载操作系统模板)
- [5.2.2 导入模板为Docker镜像](#5.2.2 导入模板为Docker镜像)
- [5.3 基于Dockerfile创建(重点)](#5.3 基于Dockerfile创建(重点))
-
- [5.3.1 Docker镜像的分层结构与UnionFS](#5.3.1 Docker镜像的分层结构与UnionFS)
- [5.3.2 Dockerfile操作常用指令详解(重点)](#5.3.2 Dockerfile操作常用指令详解(重点))
- [5.3.3 Dockerfile实战示例(构建Apache镜像)](#5.3.3 Dockerfile实战示例(构建Apache镜像))
- [5.3.4 基于Dockerfile构建镜像](#5.3.4 基于Dockerfile构建镜像)
- [5.3.5 Docker镜像分层与缓存机制解析](#5.3.5 Docker镜像分层与缓存机制解析)
- [5.4 Docker镜像创建方式总结](#5.4 Docker镜像创建方式总结)
- [Docker 命令无法补全解决方案](#Docker 命令无法补全解决方案)
- 总结
前言
在容器化技术飞速发展的今天,Docker作为最主流的容器引擎,已经成为开发、测试和运维岗位的必备技能。但很多同学在使用Docker时,往往只停留在"拉取镜像、启动容器"的基础操作,对Docker的网络通信、资源限制、数据持久化以及镜像定制等核心功能理解不深,导致在实际项目中遇到各种"卡壳"问题。
本文将从实战角度出发,系统梳理Docker的六大核心模块:网络管理 、资源控制 、数据卷容器 、端口映射 、容器互联 和镜像创建,每个模块都包含原理讲解、命令示例和注意事项,帮你打通Docker使用的"任督二脉"。无论你是刚接触Docker的新手,还是需要巩固基础的开发者/运维工程师,这篇文章都能为你提供实用的指导。
一、Docker网络管理
Docker容器的网络通信是容器化应用部署的核心环节------容器之间如何通信?容器如何被外部网络访问?不同场景下该选择哪种网络模式?这些问题都需要通过Docker的网络管理机制来解决。
1.1 Docker网络实现原理
Docker的网络通信依赖于Linux桥接技术 ,其核心是宿主机上虚拟的docker0
网桥。具体实现逻辑如下:
- 虚拟网桥(docker0) :Docker启动时会在宿主机创建一个名为
docker0
的虚拟网桥,它相当于一个"虚拟交换机",负责连接宿主机上的所有Docker容器。 - Container-IP分配 :启动容器时,Docker会从
docker0
的网段(默认通常是172.17.0.0/16
)中分配一个唯一的IP地址(即Container-IP
)给容器,并将docker0
设置为容器的默认网关。 - 容器间通信 :同一宿主机内的所有容器都接入
docker0
网桥,因此容器之间可以通过各自的Container-IP
直接通信(无需经过宿主机的物理网卡)。 - 外部网络访问限制 :
docker0
是宿主机虚拟的网络设备,并非真实的物理网卡,外部网络无法直接通过Container-IP
访问容器。若需外部访问,需通过端口映射将容器端口映射到宿主机端口,再通过"宿主机IP:宿主机端口"访问容器。
1.2 Docker端口映射
容器内部的端口默认无法被外部网络访问(因docker0
是虚拟网桥),需通过端口映射 将容器端口映射到宿主机端口,实现外部访问。Docker支持两种端口映射方式:随机映射(-P)和指定映射(-p)。
1.2.1 随机端口映射
使用-P
(大写)参数,Docker会自动从32768
开始分配一个未使用的宿主机端口,映射到容器暴露的端口(如Nginx的80端口)。适用于无需固定端口的场景(如测试环境)。
实战示例:
bash
# 启动Nginx容器,随机映射端口
docker run -d --name test1 -P nginx
# 查看端口映射结果(重点看PORTS列)
docker ps -a
# 输出示例:
# CONTAINER ID IMAGE COMMAND CREATED PORTS NAMES
#6fd7a69e7883 nginx "/docker-entrypoint...." 15 seconds ago Up 14 seconds 0.0.0.0:49158->80/tcp, :::49158->80/tcp test1
# 外部访问(替换为宿主机IP)
http://192.168.80.10:49158
# 查看容器日志(排查访问问题)
docker logs test1 # 或使用容器ID

1.2.2 指定端口映射
使用-p
(小写)参数,手动指定"宿主机端口:容器端口",适用于需要固定访问端口的场景(如生产环境的Web服务)。
实战示例:
bash
# 启动Nginx容器,指定宿主机43000端口→容器80端口
docker run -d --name test2 -p 43000:80 nginx
# 查看端口映射结果
docker ps -a
# 输出示例:
# CONTAINER ID IMAGE COMMAND CREATED PORTS NAMES
# b3369e74b2a8 nginx "/docker-entrypoint...." 25 seconds ago Up 23 seconds 0.0.0.0:43000->80/tcp, :::43000->80/tcp test2
# 外部访问(固定端口43000)
http://192.168.80.10:43000
# 查看容器日志(排查访问问题)
docker logs test2 # 或使用容器ID

1.2.3 Docker端口映射总结
映射方式 | 参数 | 特点 | 适用场景 |
---|---|---|---|
随机映射 | -P | 自动分配宿主机端口(32768+) | 测试环境、无需固定端口 |
指定映射 | -p 宿主机端口:容器端口 | 手动指定端口,固定访问地址 | 生产环境、需要固定端口的服务 |
注意:宿主机端口需未被占用,若端口冲突,容器启动会失败,需更换宿主机端口。
1.3 Docker的网络模式
使用docker run
创建容器时,可通过--net
或--network
参数指定容器的网络模式,不同模式对应不同的网络隔离与通信能力。Docker支持5种核心网络模式,以下逐一解析。
1.3.1 host模式(与宿主机共享网络栈)
-
原理 :类似VMware的"桥接模式",容器不创建独立的
Network Namespace
(网络命名空间),而是与宿主机共享同一个网络栈。因此,容器不会虚拟自己的网卡、配置独立IP,而是直接使用宿主机的IP和端口。 -
特点:网络性能最优(无额外网络转发开销),但容器会占用宿主机的端口,存在端口冲突风险。
-
适用场景:需要高性能网络的应用(如数据库)
-
实战命令 :
bash# 启动Nginx容器,使用host模式 docker run -d --name nginx-host --network host nginx # 访问容器:直接通过宿主机IP(无需端口映射,容器用宿主机80端口) # http://宿主机IP:80
1.3.2 Container模式(与其他容器共享网络栈)
-
原理 :新创建的容器不与宿主机共享网络,而是与已存在的某个容器 共享同一个
Network Namespace
。两个容器共享IP、端口范围,但文件系统、进程列表等其他资源仍保持隔离;可通过lo
回环网卡直接通信。 -
适用场景:需要两个容器紧密协作(如"应用容器+日志收集容器"),且希望避免端口映射的场景。
-
实战案例:
bash# 1. 先创建基础容器test1-container(CentOS 7) docker run -itd --name test1-container centos:7 /bin/bash # 2. 查看test1-container的进程号(用于后续验证网络命名空间) docker inspect -f '{{.State.Pid}}' test1-container # 输出示例:1753 # 3. 查看test1-container的网络命名空间(记录net对应的编号,如4026532575) ls -l /proc/1753/ns # 输出示例: # lrwxrwxrwx 1 root root 0 1月 7 11:27 net -> net:[4026532504]
bash# 4. 创建test2-container,指定与test1-container共享网络 docker run -itd --name test2-container --net=container:test1-container centos:7 /bin/bash # 5. 验证网络命名空间共享(test2-container的net编号与test1-container一致) docker inspect -f '{{.State.Pid}}' test2-container # 输出示例:1844 ls -l /proc/1844/ns # 输出示例: # lrwxrwxrwx 1 root root 0 1月 7 12:27 net -> net:[4026532504]
1.3.3 无网络模式(none)
-
原理 :容器拥有独立的
Network Namespace
,但Docker不为其配置任何网络(无网卡、无IP、无路由),仅保留lo
回环网卡(用于容器内部进程通信)。 -
特点:完全封闭的网络环境,无法联网,安全性极高。
-
适用场景:不需要网络通信的离线任务(如本地数据处理、加密计算)。
-
实战命令 :
bashdocker run -itd --name test-none --network none centos:7 /bin/bash # 进入容器查看网络(仅lo网卡) docker exec -it test-none ip addr
1.3.4 桥接模式(bridge)
- 原理 :Docker的默认网络模式(不指定
--net
时默认使用),类似VMware的"NAT模式"。容器拥有独立的Network Namespace
,并通过docker0
网桥与宿主机通信,具体流程,如下:- Docker启动时创建
docker0
虚拟网桥; - 为每个容器分配
Container-IP
,并设置docker0的IP地址为容器的默认网关。 - 在主机上创建一对
veth pair
(虚拟网卡对)(连接两个不同的网络命名空间
):一端作为容器内的eth0
网卡,另一端放在主机中, 以 * 这样类似的名字命名,并将这个网络设备加入到docker0
网桥; - 通过
iptables
的nat
表配置端口转发,实现容器与外部网络的通信。
- Docker启动时创建
- 补充说明 :
virbr0
与docker0
的区别------virbr0
是Linux虚拟化技术(如KVM、VirtualBox)创建的虚拟网桥,用于虚拟机通信;docker0
仅用于Docker容器。 - 总结:bridge网络模式中,容器运行在同一宿主机内的虚拟网桥上,可以通过容器互相通信,与宿主机网络隔离。
1.3.5 自定义模式
Docker允许用户创建自定义网络,支持三种驱动:
bridge
:类似默认bridge
模式,但增加了DNS解析(容器可通过名称通信)、网络隔离等功能。单机网络模式,适合在一台宿主机、内容器互联;overlay
:用于跨主机容器通信(Docker Swarm集群场景);macvlan
:容器像一台物理机一样直接获取宿主机的所在的网络的IP(容器像物理机一样直接连接局域网)
实战:创建自定义bridge网络并指定IP
默认bridge
模式不支持手动指定Container-IP
,需通过自定义网络实现:
bash
# 1. 创建自定义bridge网络(子网172.18.0.0/16,网卡名docker1)
docker network create --subnet=172.18.0.0/16 --opt "com.docker.network.bridge.name"="docker1" mynetwork
# 参数说明:
# --subnet:指定网络子网;
# --opt "com.docker.network.bridge.name":指定宿主机上的网卡名(默认是br-xxx格式,不易记);
# mynetwork:自定义网络名称。
# 2. 启动容器时指定自定义网络和IP
docker run -itd --name test4 --net mynetwork --ip 172.18.0.10 centos:7 /bin/bash
# 3. 验证IP(进入容器查看)
docker exec -it test4 ip addr # 应显示172.18.0.10
docker inspect test4
bash
# 管理 Linux 桥接网络
brctl show
# 管理 Docker 容器网络
docker network ls

1.3.6 Docker网络模式总结
网络模式 | 核心特点 | 适用场景 |
---|---|---|
host | 共享宿主机网络栈,无端口映射 | 对网络性能要求高,无端口冲突风险的场景 |
Container | 共享其他容器网络,隔离其他资源 | 容器间紧密协作(如应用+日志收集) |
none | 无网络配置,仅lo网卡 | 离线任务、高安全性需求 |
bridge | 默认模式,独立网络栈+docker0网桥 | 单主机容器通信,常规场景 |
自定义 | 支持DNS、跨主机、MAC模拟 | 集群部署、复杂网络隔离 |
额外附加:
- Overlay:这是Docker Swarm模式的网络,主要用于在多个主机上创建一个分布式网络。容器间即便在不同的主机也能完成通信,相当于在跨主机的容器之间创建了一个覆盖网络。
- Macvlan:Macvlan模式可以让容器直接连接到主机的物理网络,每个Macvlan接口都有一个唯一的MAC地址,此模式使得容器看起来就像是网络上的物理设备。
二、Docker资源控制(Docker优化)
为避免单个容器占用过多宿主机资源(如CPU、内存),Docker基于Linux的cgroups
(Control Groups)机制实现资源限制。
cgroups
是Linux内核提供的资源管理工具,支持限制、统计、优先级分配等功能。
cgroups 的 4 大功能(简要)
- 资源限制:限制任务使用的总资源量。
- 优先级分配:如通过 cpu 时间片和 IO 带宽分配优先级。
- 资源统计:统计 cpu 时长、内存用量等。
- 任务控制:对 cgroup 中的进程执行挂起/恢复等操作。
2.1 CPU资源控制
2.1.1 设置CPU使用率上限(--cpu-period / --cpu-quota)
-
原理:Linux使用CFS(完全公平调度器)调度CPU,通过两个参数控制容器CPU使用率:
--cpu-period
:调度周期(单位:微秒,默认100000,即100ms);--cpu-quota
:容器在一个周期内可使用的CPU时间(单位:微秒,默认-1,即无限制);- 计算公式:
可用CPU核心数 = cpu-quota / cpu-period
(如50000/100000=0.5,即50%的单核CPU)。
-
实战示例:
bash# 方式1:使用--cpu-quota(限制为50%单核CPU) docker run -itd --name test6 --cpu-quota 50000 centos:7 /bin/bash # 方式2:使用--cpus(更直观,Docker 1.13+支持) docker run -itd --name cputest --cpus="0.5" centos:7 /bin/bash # 说明:--cpus="0.5" 等价于 --cpu-period=100000 --cpu-quota=50000 # 进行压测并在宿主机查看cpu使用率 docker stats
-
注意:若宿主机有4个逻辑核,0.5个CPU相当于整机CPU能力的12.5%(0.5/4=0.125)。
-
最小值/范围 :
--cpu-period
有效范围通常 1000 ~ 1000000(单位 us)。--cpu-quota
必须 >= 1000(1 ms)或者 -1(不限制)。
2.1.2 设置CPU占用比(权重 --- --cpu-shares)
-
原理 :
--cpu-shares
指定CPU使用的相对权重 (默认1024),仅在CPU资源紧张(容器争用CPU)时生效,并非硬限制。例如:- 容器A(--cpu-shares 512)与容器B(--cpu-shares 1024)争用CPU时,分配比约为1:2。
-
实战示例 :
bash# 创建两个不同权重的容器 docker run -itd --name c1 --cpu-shares 512 centos:7 docker run -itd --name c2 --cpu-shares 1024 centos:7
bash# 验证:在容器内运行压力测试工具stress # 1. 进入容器安装stress(先在容器内设置阿里源) docker cp CentOS-Base.repo c1:/etc/yum.repos.d/ docker exec -it c1 bash yum install -y epel-release && yum install -y stress # 2. 每个容器启动4个CPU压力进程 stress -c 4 # 在c1和c2中分别执行 # 3. 宿主机查看CPU分配(倾向于1:2) docker stats
2.1.3 绑定指定CPU(--cpuset-cpus)
-
原理:将容器进程绑定到宿主机的指定CPU核心(硬亲和性),避免进程在不同核心间切换,提升性能稳定性。
-
实战示例 :
bash# 将容器绑定到宿主机第1、3个核心(核心编号从0开始) docker run -itd --name test7 --cpuset-cpus "1,3" centos:7 /bin/bash # 验证:宿主机查看核心利用率 top # 按键盘1键,查看CPU1和CPU3的使用率 # 或进入容器运行 taskset -p <pid>
2.1.4 CPU压力测试与验证示例
通过自定义脚本模拟CPU高负载,验证资源限制效果:
-
在容器内创建一个繁忙循环脚本:
bash# /cpu.sh #!/bin/bash i=0 while true; do let i++; done
-
在容器内运行
./cpu.sh
,在宿主机观察top
与docker stats
:bashdocker exec -it <container> bash ./cpu.sh
-
分别进入容器,进行压力测试
bashyum install -y epel-release yum install -y stress stress -c 4 #产生四个进程,每个进程都反复不停的计算随机数的平方根
-
修改
cgroups
手工测试(示例):bash# 找到容器对应的 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 # 设置配额(临时生效)
2.1.5 CPU资源控制注意事项
--cpu-shares
是权重,非硬限制(CPU空闲时,容器可使用超过权重的资源);--cpu-quota/--cpus
是硬限制,容器无法突破设定的CPU上限(quota = -1 表示无限制);--cpuset-cpus
适合对性能稳定性要求高的场景(避免与其他进程抢核)(如数据库容器)。- 在多核宿主机上理解
quota/period
的含义(单位是 "相对于 1 个 CPU 的份额")。
2.2 内存使用限制
内存限制通过-m/--memory
和--memory-swap
参数实现,避免容器耗尽宿主机内存。
2.2.1 --memory与--memory-swap规则
--memory
:限制容器可使用的物理内存 (如-m 512m
表示512MB);--memory-swap
:限制容器可使用的物理内存+交换分区(swap) 总量,需与--memory
配合使用;- 核心规则:
- 示例
-m 300m --memory-swap=1g
:物理内存300MB,swap可用700MB(1G-300M); - 不设置
--memory-swap
:默认swap为--memory
的2倍(如-m 512m
,swap默认1024MB); --memory-swap=-1
:swap无限制(使用宿主机所有可用swap);--memory-swap=--memory
:容器不可使用swap(物理内存用尽触发OOM)。
- 示例
2.2.2 内存限制示例命令
bash
# 1. 限制物理内存512MB(swap默认1024MB)
docker run -itd --name memtest -m 512m centos:7 /bin/bash
# 2. 限制物理内存300MB,swap总量1GB(swap可用700MB)
docker run -itd --name memtest2 -m 300m --memory-swap=1g centos:7 /bin/bash
2.2.3 内存限制验证与OOM行为
-
验证内存限制:
bash# 1. 宿主机查看容器内存限制(替换为容器ID) cd /sys/fs/cgroup/memory/docker/<容器ID>/ cat memory.limit_in_bytes # 输出内存限制(单位:字节,512MB=536870912字节) cat memory.usage_in_bytes # 输出当前内存使用量 # 2. 容器内模拟内存高负载(使用stress) docker exec -it memtest bash stress --vm 1 --vm-bytes 600m # 尝试使用600MB内存(超过512MB限制)
-
OOM行为 :若容器内存超过限制且无swap可用,内核会触发OOM Killer杀死容器,可通过
docker logs
查看日志或者dmesg
来确认 OOM 事件。
2.2.4 内存限制建议与注意
- 生产环境必须为容器设置内存限制,避免单个容器把宿主机内存耗尽;
- 内存敏感型应用(如Redis、MySQL)建议禁用swap(
--memory-swap=--memory
),避免swap导致性能下降; - 配合容器健康检查和重启策略(如
--restart=on-failure
),应对OOM后的容器恢复。 - 在 cgroup v2 环境下内存控制文件名/行为可能与 v1 略有不同(检查
/sys/fs/cgroup
结构)。
2.3 磁盘IO(blkio/io)控制
Docker基于cgroups
的blkio
控制器(cgroup v1)或io
控制器(cgroup v2)限制容器的磁盘读写速率和IOPS(每秒输入输出次数)。
2.3.1 常用Docker磁盘IO限制参数
参数 | 作用 | 示例 |
---|---|---|
--device-read-bps | 限制设备读速率(单位:B/s、KB/s、MB/s) | --device-read-bps /dev/sda:1M |
--device-write-bps | 限制设备写速率 | --device-write-bps /dev/sda:1M |
--device-read-iops | 限制设备读IOPS(次数) | --device-read-iops /dev/sda:100 |
--device-write-iops | 限制设备写IOPS(次数) | --device-write-iops /dev/sda:100 |
实战示例 :限制容器对/dev/sda
(宿主机磁盘)的写速率为1MB/s
bash
docker run -it --name iotest --device-write-bps /dev/sda:1MB centos:7 /bin/bash
2.3.2 磁盘IO限制验证(dd测试)
通过dd
命令(跳过文件系统缓存)测试写速率:
bash
# 容器内执行dd命令(写入10个1MB的块)跳过文件系统缓存
dd if=/dev/zero of=test.out bs=1M count=10 oflag=direct
# 输出示例(写速约1MB/s,符合限制):
# 10485760 bytes (10 MB) copied, 10.0028 s, 1.0 MB/s

2.3.3 磁盘IO控制注意事项
- 限制需指定具体块设备路径 (如
/dev/sda
),路径错误会导致限制失效; - 云环境或虚拟化环境中,底层存储(如AWS EBS、阿里云云盘)可能有自身IO限制,容器层限制需结合底层限制配置;
- cgroup v2环境中,IO限制参数不同(如使用
--device-io-max
),需参考对应Docker版本文档。
2.4 清理Docker占用的磁盘空间
Docker运行一段时间后,会积累停止的容器、未使用的镜像、网络和构建缓存,可通过以下命令清理:
bash
# 清理所有未使用的资源(停止的容器、未使用的镜像、网络、缓存)
docker system prune -a
# 注意:此命令会删除所有未活跃的资源,执行前确认无需保留!

2.5 Docker资源控制常见命令速查
bash
# CPU相关
docker run -itd --name c1 --cpu-shares 512 centos:7 # 权重512
docker run -itd --name c2 --cpu-quota 50000 centos:7 # 50%单核
docker run -itd --name c3 --cpuset-cpus "1,3" centos:7 # 绑定核心1、3
docker run -itd --name c4 --cpus="0.5" centos:7 # 直观指定0.5核
# 内存相关
docker run -itd --name memtest -m 512m centos:7 # 512MB物理内存
docker run -itd --name memtest2 -m 300m --memory-swap=1g centos:7 # 300M+700M swap
# 磁盘IO相关
docker run -it --name iotest --device-write-bps /dev/sda:1MB centos:7 # 写速1MB/s
# 监控与验证
docker stats # 实时监控容器资源使用
docker exec -it <容器ID> bash # 进入容器操作
cat /sys/fs/cgroup/cpu/docker/<容器ID>/cpu.cfs_quota_us # 查看CPU配额
cat /sys/fs/cgroup/memory/docker/<容器ID>/memory.limit_in_bytes # 查看内存限制
# 清理资源
docker system prune -a # 清理未使用资源
2.6 Docker资源控制常见陷阱与建议
- 权重vs限额 :
--cpu-shares
是相对权重(争用时生效),--cpu-quota/--cpus
是硬限额(强制限制); - cgroup版本差异:CentOS 7默认用cgroup v1,CentOS 8+或新内核可能用cgroup v2,控制器名称和参数不同(如blkio→io);
- IO 限制依赖底层设备:在云/虚拟机上测试时,注意底层虚拟磁盘的行为。
- 生产环境监控:建议搭配Prometheus+Grafana+cAdvisor监控容器资源,及时发现资源瓶颈;
- 权限控制 :修改
/sys/fs/cgroup
目录下的配置需root权限,优先使用docker run
参数配置,避免直接修改系统文件。
三、Docker数据卷容器(Data Volumes Containers)
容器的文件系统是临时的------容器删除后,内部数据会丢失。Docker的数据卷(Data Volumes)机制解决了这一问题,实现数据持久化;而数据卷容器则进一步简化了多容器间的数据共享。
3.1 数据卷
数据卷是容器内的特殊目录,可与宿主机目录或其他容器共享,具备以下特性:
- 数据持久化:容器删除后,数据卷中的数据不会丢失;
- 双向同步:宿主机与容器对数据卷的修改实时同步;
- 跨容器共享:多个容器可挂载同一个数据卷。
3.1.1 创建与挂载数据卷
通过docker run
的-v
或--mount
参数挂载数据卷,格式:-v 宿主机目录:容器内目录
。
bash
# 挂载宿主机/var/www目录到容器内/data1目录
docker run -v /opt/www:/data1 --name web1 -it centos:7 /bin/bash
# 参数说明:
# /var/www:宿主机目录(不存在会自动创建);
# /data1:容器内目录(不存在会自动创建);
# web1:容器名称。
-v /var/www:/data1
: 将宿主机上的/var/www
目录挂载到容器中的/data1
目录。这样容器内/data1
的修改会同步到宿主机上的/var/www
。--name web1
: 给容器指定一个名称web1
。-it centos:7 /bin/bash
: 使用centos:7
镜像启动容器并进入交互式 shell。

3.1.2 在数据卷中写入数据
进入容器后,在数据卷目录(/data1
)中创建文件,数据会同步到宿主机:
bash
# 容器内执行(写入数据到/data1/abc.txt)
echo "this is web1" > /data1/abc.txt
exit
此时,容器中的 /data1/abc.txt
文件与宿主机中的 /var/www/abc.txt
文件是同步的。即使容器退出,宿主机上的数据依然存在。
3.1.3 查看宿主机同步的数据
退出容器后,查看宿主机/var/www
目录,数据已同步:
bash
# 宿主机执行
cat /opt/www/abc.txt # 输出:this is web1

3.2 数据卷容器
数据卷容器是专门用于提供数据卷的容器 ,不运行应用程序,仅作为"数据载体",供其他容器通过--volumes-from
挂载其数据卷。适用于多容器共享数据的场景(如微服务中的配置共享、日志存储)。
3.2.1 创建数据卷容器
bash
# 创建数据卷容器web2,挂载两个数据卷/data1和/data2
docker run --name web2 -v /data1 -v /data2 -it centos:7 /bin/bash
# 说明:-v /data1 未指定宿主机目录,Docker会在宿主机/var/lib/docker/volumes/下创建匿名卷
--name web2
: 给容器命名为web2
。-v /data1 -v /data2
: 在容器内部挂载了两个数据卷/data1
和/data2
。这些数据卷不依赖于宿主机,而是仅仅存在于容器内。

3.2.2 在数据卷容器中写入数据
进入web2
容器,在数据卷中写入测试数据:
bash
# 进入web2容器
docker exec -it web2 bash
# 在/data1和/data2中写入数据
echo "this is web2" > /data1/abc.txt
echo "THIS IS WEB2" > /data2/ABC.txt
3.2.3 使用--volumes-from共享数据卷
创建新容器web3
,通过--volumes-from
挂载web2
的数据卷:
bash
# 创建web3,共享web2的所有数据卷
docker run -it --volumes-from web2 --name web3 centos:7 /bin/bash
# 说明:--volumes-from web2 表示继承web2的所有数据卷配置
--volumes-from web2
: 这表示将容器web2
中的所有数据卷挂载到新容器web3
中。
3.2.4 在新容器中验证共享数据
进入web3
容器,查看/data1
和/data2
目录,可看到web2
中写入的数据:
bash
# 进入web3容器
docker exec -it web3 bash
# 查看数据
cat /data1/abc.txt # 输出:this is web2
cat /data2/ABC.txt # 输出:THIS IS WEB2

3.3 数据卷与数据卷容器总结
- 数据卷 (Data Volumes) :解决"容器数据持久化"问题,通过
-v
挂载宿主机目录; - 数据卷容器(Data Volumes Containers) :解决"多容器数据共享"问题,通过
--volumes-from
继承数据卷,无需每个容器都挂载宿主机目录; - 注意 :数据卷容器删除后,其数据卷(匿名卷)不会被删除,需手动清理(
docker volume rm <卷ID>
)。
四、Docker容器互联(使用CentOS镜像)
容器互联是指通过网络让两个或多个容器直接通信,Docker早期通过--link
选项实现,适用于简单的单主机容器通信场景(复杂场景建议使用自定义网络)。
4.1 创建并运行源容器web1
首先创建"源容器"web1
,作为通信的发起方:
bash
# 启动web1容器(后台运行,随机端口映射)
docker run -itd -P --name web1 centos:7 /bin/bash
# 参数说明:
# -itd:交互式+后台运行;
# -P:随机映射端口;
# --name web1:指定容器名称(互联需依赖名称)。
4.2 创建并运行接收容器web2(--link互联)
创建"接收容器"web2
,通过--link
选项连接web1
,格式:--link 源容器名称:源容器别名
。
bash
# 启动web2,通过--link连接web1(别名为web1)
docker run -itd -P --name web2 --link web1:web1 centos:7 /bin/bash
# 说明:--link web1:web1 表示将web1容器暴露给web2,web2中可通过"web1"这个别名访问web1。
4.3 在接收容器web2中测试连接
进入web2
容器,通过ping
命令测试与web1
的通信(无需知道web1
的Container-IP
):
bash
# 1. 进入web2容器
docker exec -it web2 bash
# 2. 测试与web1的连通性(使用别名web1)
ping web1
# 输出示例(ping通表示互联成功):
# PING web1 (172.17.0.2) 56(84) bytes of data.
# 64 bytes from web1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.068 ms

4.4 Docker容器互联总结
- 核心原理 :
--link
会在接收容器的/etc/hosts
文件中添加源容器的别名与Container-IP
的映射,因此接收容器可通过别名通信; - 局限性 :
--link
仅支持单主机容器互联,且不支持动态更新(源容器IP变化后,接收容器的/etc/hosts
不会自动更新); - 替代方案 :复杂场景(如跨主机、动态容器)建议使用Docker自定义网络(如
overlay
),支持DNS自动解析和动态IP更新。
五、Docker镜像的创建
Docker镜像是容器的"模板",包含容器运行所需的程序、库、配置等。创建Docker镜像主要有三种方式:基于现有容器创建
、基于本地模板创建
、基于Dockerfile创建
(最常用、最灵活)。
5.1 基于现有镜像创建
该方式是"先修改容器,再将修改后的容器提交为新镜像",适用于快速定制简单镜像。
5.1.1 启动容器并进行修改
bash
# 1. 启动一个CentOS 7容器(交互式)
docker create -it --name mycentos centos:7 /bin/bash # 创建容器
docker start <容器ID> # 启动容器
docker exec -it <容器ID> bash # 进入容器
# 2. 修改容器内部的环境(例如安装软件包、修改配置文件等),然后退出容器
# 安装OpenJDK 8
yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel
# 验证java版本
java-version
yum clean all
5.1.2 提交容器为新镜像
使用docker commit
命令将修改后的容器提交为新镜像,格式:docker commit -m "提交说明" -a "作者" 容器ID 新镜像名:标签
。
bash
# 提交容器(容器ID替换为实际ID)
docker commit -m "openjdk8" -a "simon" 1450d38ffda5 openjdk:8
# 查看新镜像
docker images
# 输出示例:
# REPOSITORY TAG IMAGE ID CREATED SIZE
# openjdk 8 4ee649b7cf2b 5 seconds ago 469MB

5.2 基于本地模板创建
通过导入现成的操作系统模板(如OpenVZ模板)创建镜像,适用于快速获取特定系统环境的场景。
5.2.1 下载操作系统模板
从OpenVZ官网下载模板(以Debian 7为例):
bash
# 使用wget下载模板
wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz
# 或使用curl下载
curl -L http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz -o debian-7.tar.gz
5.2.2 导入模板为Docker镜像
使用docker import
命令导入模板:
bash
# 将模板文件导入为镜像(镜像名debian:test)
cat debian-7.0-x86-minimal.tar.gz | docker import - debian:test
# 查看镜像
docker images
# 输出示例:
# REPOSITORY TAG IMAGE ID CREATED SIZE
# debian test 5120c6b1c973 4 seconds ago 215MB

5.3 基于Dockerfile创建(重点)
Dockerfile是一个包含一系列指令 的文本文件,每条指令对应镜像的一层,通过docker build
命令自动构建镜像。这种方式支持自动化、可重复构建,是生产环境中创建镜像的首选方式。
5.3.1 Docker镜像的分层结构与UnionFS
Docker镜像基于UnionFS(联合文件系统) 构建,具有以下特点:
- 分层存储:每一条Dockerfile指令生成一层镜像,层与层之间相互独立;
- 只读特性:所有镜像层都是只读的,容器启动时会在镜像层之上添加一层"可读写层"(容器层);
- 缓存机制:Docker会缓存已构建的镜像层,若指令或文件未变化,直接复用缓存,加速构建。
为什么Docker中的CentOS镜像只有200MB左右?
传统CentOS系统镜像约4GB,而Docker镜像仅保留rootfs
(根文件系统,包含/bin
、/etc
等核心目录),共享宿主机的bootfs
(引导文件系统,包含内核),因此体积大幅缩小。
5.3.2 Dockerfile操作常用指令详解(重点)
Dockerfile指令按功能可分为基础镜像指令 、镜像操作指令 、容器启动指令等,以下是常用指令:
-
FROM
指定新镜像基于的基础镜像,Dockerfile 的第一条指令必须为
FROM
。dockerfileFROM centos:7
-
MAINTAINER
指定镜像的维护者信息:
dockerfileMAINTAINER "Simon Cai <simoncwh@example.com>"
-
RUN
执行命令并将结果提交到镜像中。常用来安装软件包、修改配置等。
dockerfileRUN yum install -y httpd
-
ENTRYPOINT
设置容器启动时默认执行的命令(不可被覆盖,优先级高于CMD):
dockerfileENTRYPOINT ["httpd", "-D", "FOREGROUND"]
-
CMD
容器启动时执行的默认命令。
CMD
指令会被docker run
命令后指定的命令覆盖。dockerfileCMD ["httpd", "-D", "FOREGROUND"]
-
EXPOSE
声明容器内的端口(仅文档说明,不实际映射):
dockerfileEXPOSE 80
-
ENV
设置环境变量(容器内可使用):
dockerfileENV MY_VAR=my_value
-
ADD
将文件或目录从宿主机复制到镜像中,支持从 URL 下载文件,并能自动解压归档文件:
dockerfileADD myfile.tar.gz /app
-
COPY
将本地文件或目录复制到镜像中(仅本地文件,无解压):
dockerfileCOPY . /app
-
VOLUME
声明容器内的挂载点(创建匿名卷):
dockerfileVOLUME ["/data"]
-
USER
设置容器内运行命令时的用户:
dockerfileUSER root
-
WORKDIR
设置后续指令的工作目录(类似cd):
dockerfileWORKDIR /app
-
ONBUILD
设置当该镜像作为基础镜像时,后续 Dockerfile 执行的命令:
dockerfileONBUILD RUN echo "Building from base image"
-
HEALTHCHECK
设置容器的健康检查:
dockerfileHEALTHCHECK CMD curl --fail http://localhost:8080 || exit 1
关键指令区别:
RUN
vsCMD
vsENTRYPOINT
:RUN
:构建镜像时执行(如安装软件);CMD
:容器启动时执行,可被docker run
后的命令覆盖(如docker run xxx bash
会覆盖CMD);ENTRYPOINT
:容器启动时执行,不可被覆盖,若需传参需用docker run --entrypoint
。
ADD
vsCOPY
:ADD
支持URL下载和自动解压(如.tar.gz),功能更丰富;COPY
仅复制本地文件,功能简单,推荐优先使用(避免意外解压)。
5.3.3 Dockerfile实战示例(构建Apache镜像)
以构建一个基于CentOS 7的Apache(httpd)镜像为例,完整流程如下:
- 创建工作目录:
bash
mkdir -p /opt/apache && cd /opt/apache
- 编写Dockerfile:
bash
vim Dockerfile
#基于的基础镜像
FROM centos:7
#维护镜像的用户信息
MAINTAINER this is apache image <cwh>
#镜像操作指令安装apache软件,需提前准备国内源文件
ADD CentOS-Base.repo /etc/yum.repos.d/
RUN yum clean all
#RUN yum -y update
RUN yum -y install httpd
#开启 80 端口
EXPOSE 80
#复制网站首页文件
ADD index.html /var/www/html/index.html
//方法一:
#将执行脚本复制到镜像中
ADD run.sh /opt/run.sh
#启动容器时执行脚本
CMD sh /opt/run.sh
//方法二:
ENTRYPOINT [ "/usr/sbin/apachectl" ]
CMD ["-D", "FOREGROUND"]
//方法三
# 启动 httpd 服务
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
bash
准备执行脚本(方式一)
vim run.sh
#!/bin/bash
rm -rf /run/httpd/* #清理httpd的缓存
/usr/sbin/apachectl -D FOREGROUND #指定为前台运行
#因为Docker容器仅在它的1号进程(PID为1)运行时,会保持运行。如果1号进程退出了,Docker容器也就退出了。
# 准备网站页面
echo "this is test web" > index.html

5.3.4 基于Dockerfile构建镜像
使用docker build
命令构建镜像,格式:docker build -t 镜像名:标签 构建上下文路径
(.
表示当前目录为构建上下文)。
bash
# 构建镜像(镜像名httpd:centos,标签centos)注意末尾的.
docker build -t httpd:centos ./
# 查看构建的镜像
docker images
# 输出示例:
# REPOSITORY TAG IMAGE ID CREATED SIZE
# httpd centos 9e154b3b93e6 8 seconds ago 493MB
bash
# 新镜像运行容器
docker run -d -p 1216:80 httpd:centos
# 测试
http://192.168.10.14:1216/
5.3.5 Docker镜像分层与缓存机制解析
- 分层机制 :Dockerfile中的每条指令对应一层镜像,例如:
FROM centos:7
→ 基础层;RUN yum install -y httpd
→ 安装层;COPY index.html /var/www/html/
→ 复制层。
- 缓存机制 :
- 若Dockerfile指令未变化,且依赖的文件(如
index.html
)未修改,Docker会复用缓存层; - 若某一层指令或文件变化,该层及之后的所有层都会重新构建(缓存失效)。
- 若Dockerfile指令未变化,且依赖的文件(如
- 镜像层是不可变的
- 删除容器时只会删除其上面的读写层,底层的镜像层不会丢失。
- 优化建议 :
- 频繁变化的指令(如
COPY
)放在Dockerfile末尾,减少重新构建的层数; - 合并
RUN
指令(用&&
连接),减少镜像层数(如合并yum install
和yum clean
); - 使用
.dockerignore
文件排除不需要的文件(如node_modules
、日志文件),减小构建上下文体积。
- 频繁变化的指令(如
5.4 Docker镜像创建方式总结
- 基于现有镜像创建:通过修改容器并提交为新的镜像。
- 基于本地模板创建:从模板文件导入创建镜像。
- 基于 Dockerfile 创建:通过编写 Dockerfile 来定制镜像,支持自动化构建。
Docker 命令无法补全解决方案
- 首先安装 bash-completion 包:
bash
yum install -y bash-completion
- 重新加载 bash 配置使补全生效:
bash
source /etc/profile.d/bash_completion.sh
- 之后测试 Docker 命令补全是否正常工作:
bash
docker run --cpu- # 按Tab键应该会显示补全选项
总结
本文系统梳理了Docker的六大核心功能:网络管理、资源控制、数据卷容器、端口映射、容器互联和镜像创建,每个模块都从"原理+实战"角度出发,提供了可直接复用的命令和配置示例。
Docker的核心价值在于"隔离"与"标准化"------通过网络隔离实现容器间通信控制,通过资源限制避免宿主机资源耗尽,通过数据卷实现数据持久化,通过Dockerfile实现镜像的标准化构建。这些功能看似独立,实则相辅相成,共同构成了Docker容器化应用的基础。
建议大家在学习过程中"边学边练":每掌握一个知识点,就动手执行命令验证效果(如创建自定义网络、设置CPU限制、编写Dockerfile),只有通过实战才能真正理解Docker的底层逻辑。后续我还会分享Docker Compose、Docker Swarm等容器编排工具的使用,欢迎持续关注!