Docker04-数据卷与网络
Docker 数据卷与网络:持久化与容器互联
目录
- 回顾:为什么容器数据会丢
- 数据卷的三种方式:命名卷、绑定挂载、tmpfs
- 命名卷与绑定挂载的深入对比与选型
- 数据卷的管理命令
- 数据卷实战:用卷跑一个数据库
- 容器网络基础:为什么要学网络
- Docker 网络模式:bridge / host / none
- 自定义 bridge 网络与容器互联
- 端口映射原理与 DNS 解析
- 常见问题排查
- 总结
- 参考资料
0. 回顾:为什么容器数据会丢
第 1 篇讲过:容器可写层的生命周期和容器绑定,容器删除,可写层里的数据随之消失。数据库、上传文件、配置变更这类重要数据,绝不能放在容器可写层里。
这一篇详细讲数据卷(Volume),并顺带把容器网络讲透,因为「持久化 + 互联」是容器落地生产的两个基础能力。
一、数据卷的三种方式:命名卷、绑定挂载、tmpfs
Docker 提供三种数据存储方式,用途截然不同。
1.1 命名卷(named volume)
命名卷是由 Docker 管理的一块存储空间,存放在宿主机 /var/lib/docker/volumes/<卷名>/ 下。挂载方式:
# 把命名卷 mydata 挂载到容器的 /data 目录
docker run -d --name app -v mydata:/data someimage
- 卷名
mydata是 Docker 管理的抽象名字,你不用关心它具体落在宿主机哪里; - 适合正式数据(数据库、应用数据),因为它是 Docker 管理、便于备份和迁移。
1.2 绑定挂载(bind mount)
绑定挂载直接把宿主机的某个路径映射进容器,两边是同一个文件:
# 把宿主机 /home/user/project 挂载到容器的 /app
docker run -d --name app -v /home/user/project:/app someimage
# 挂载单个配置文件
docker run -d --name app -v /etc/nginx/nginx.conf:/etc/nginx/nginx.conf:ro nginx
- 路径必须以
/开头(绝对路径); - 适合开发场景(把源码挂进去实时同步)和配置文件注入;
- 结尾加
:ro表示只读挂载。
1.3 tmpfs 挂载
tmpfs 把数据放在内存里,不写磁盘:
docker run -d --name app --tmpfs /tmp someimage
- 速度最快,但容器停止/重启数据即消失;
- 适合临时数据、敏感缓存(不希望落盘)。
1.4 三者对比
| 方式 | 语法 | 数据存哪 | 是否随容器删除 | 适用场景 |
|---|---|---|---|---|
| 命名卷 | 卷名:/路径 |
Docker 管理(/var/lib/docker/volumes) | 否,卷独立保留 | 正式数据、数据库 |
| 绑定挂载 | /宿主机路径:/路径 |
宿主机指定路径 | 否,文件仍在宿主机 | 开发源码、配置注入 |
| tmpfs | --tmpfs /路径 |
内存 | 是,随容器 | 临时数据、敏感缓存 |
二、命名卷与绑定挂载的深入对比与选型
2.1 命名卷的优势
- Docker 统一管理:备份、迁移、权限都由 Docker 处理;
- 跨平台一致:不用关心宿主机具体路径;
- 适合多容器共享:多个容器挂同一个命名卷,数据互通。
2.2 绑定挂载的优势
- 路径直观:你清楚数据在宿主机哪里;
- 实时同步:开发时改宿主机代码,容器立即可见;
- 注入配置:把宿主机配置文件挂进容器,无需重新构建镜像。
2.3 怎么选
- 生产正式数据(数据库等):优先命名卷,Docker 管理更规范、易备份;
- 开发调试:用绑定挂载把源码挂进去;
- 配置文件:用绑定挂载 + :ro 注入,不改镜像;
- 临时/敏感:用 tmpfs。
经验之谈:能用命名卷就不用绑定挂载(尤其数据库),因为绑定挂载的宿主机路径权限和 SELinux 问题(RHEL 上)更容易踩坑,见第 9 章。
三、数据卷的管理命令
3.1 创建与查看卷
docker volume create mydata # 显式创建命名卷
docker volume ls # 列出所有卷
docker volume inspect mydata # 查看卷详情(挂在宿主机哪里)
3.2 挂载卷的几种写法
# 短语法(-v)
docker run -d --name app -v mydata:/data someimage
# 长语法(--mount,更明确、推荐)
docker run -d --name app --mount source=mydata,target=/data someimage
# 绑定挂载的长语法
docker run -d --name app --mount type=bind,source=/home/user/data,target=/data someimage
3.3 删除卷
docker volume rm mydata # 删除指定卷(先确保没有容器在用)
docker volume prune # 删除所有未被使用的卷
删除卷会永久删除其中的数据,务必确认。rm 一个正在被容器使用的卷会失败。
3.4 备份卷数据(用一个临时容器)
卷里的数据可以借助一个临时容器打包成 tar 备份:
# 把 mydata 卷的数据备份到当前目录的 backup.tar
docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar czf /backup/backup.tar -C /data .
原理:起一个临时容器,把要备份的卷挂到 /data,把当前目录挂到 /backup,然后用 tar 打包。
四、数据卷实战:用卷跑一个数据库
以 MySQL 为例,看看数据卷如何保证数据不丢。
4.1 用命名卷跑 MySQL
# 创建命名卷
docker volume create mysql-data
# 运行 MySQL,把数据目录挂到命名卷
docker run -d --name mysql-db \
-e MYSQL_ROOT_PASSWORD=mysecret \
-v mysql-data:/var/lib/mysql \
mysql:8.0
/var/lib/mysql 是 MySQL 存数据的目录,挂到命名卷后,即使容器被删,数据也还在卷里。
4.2 验证数据持久化
- 向数据库写入数据;
- 删除容器:
docker rm -f mysql-db; - 用同一个卷重新运行一个 MySQL:
docker run -d --name mysql-db2 -v mysql-data:/var/lib/mysql mysql:8.0; - 之前写入的数据依然存在。
这就是「容器可删、数据不丢」的核心实践。
4.3 要点
- 数据库镜像(MySQL、PostgreSQL、Redis)官方都明确指定了数据目录,照着挂到命名卷即可;
- 记得给数据库设置密码环境变量(如 MYSQL_ROOT_PASSWORD),不要用默认空密码。
五、容器网络基础:为什么要学网络
单个容器可以自己玩,但真实应用是多个容器协作:Web 要连数据库、前端要调后端。它们之间怎么找到对方、怎么通信,就是容器网络要解决的问题。
Docker 的网络设计核心:
- 网络命名空间:每个容器有自己独立的网络栈(自己的 IP、端口);
- 网络模式:决定容器用什么方式接入网络;
- DNS:Docker 内置 DNS,让容器能通过容器名互相访问。
六、Docker 网络模式:bridge / host / none
docker network ls 能看到 Docker 默认创建的几个网络。
6.1 bridge(默认,桥接网络)
bridge 是默认模式。Docker 会创建一个虚拟网桥(默认叫 docker0),所有 bridge 模式的容器都连在这个网桥上,彼此通过私有 IP 互通。
- 容器有自己独立的 IP(如 172.17.0.x);
- 默认模式,适合单机多容器互联;
- 容器能上网(通过 NAT),外部默认访问不到(需端口映射)。
6.2 host(主机网络)
host 模式下容器共享宿主机的网络栈,直接使用宿主机 IP 和端口,没有独立的网络隔离。
docker run -d --name app --network host someimage
- 性能好(没有 NAT 转发),适合对网络性能要求高的场景;
- 但端口直接占宿主机,多个 host 容器端口会冲突;
- 适用于需要绑定固定端口的服务(如部分中间件)。
6.3 none(无网络)
none 模式下容器没有网络,只有一个回环接口。
docker run -d --name app --network none someimage
- 完全隔离,适合只做计算、不需要网络的容器(安全性最高)。
6.4 三种模式对比
| 模式 | 网络隔离 | 是否有独立 IP | 外部访问 | 适用 |
|---|---|---|---|---|
| bridge | 有(网桥) | 有 | 需端口映射 | 默认,单机多容器 |
| host | 无(共享宿主) | 无(用宿主 IP) | 直接用宿主端口 | 性能敏感、固定端口 |
| none | 完全隔离 | 无 | 无法 | 纯计算、高安全 |
七、自定义 bridge 网络与容器互联
默认的 bridge 网络适合单容器,但多个容器要互相用名字访问时,最好创建自定义 bridge 网络。
7.1 为什么不用默认 bridge
默认 bridge 里的容器不能直接用容器名互相访问(需要用 IP),IP 会变,不稳定。自定义 bridge 网络自带 DNS 解析,容器之间可以用容器名直接通信,这才适合多服务协作。
7.2 创建自定义网络并接入容器
# 创建自定义 bridge 网络
docker network create mynet
# 用 --network 指定网络运行容器
docker run -d --name web --network mynet nginx
docker run -d --name db --network mynet mysql:8.0
# 在 web 容器里 ping db 的名字,能通(用容器名解析)
docker exec web ping db
在同一个自定义网络里,web 和 db 可以通过容器名互相访问,不需要知道对方的 IP。
7.3 把已有容器接入网络
docker network connect mynet web # 把运行中的 web 接入 mynet
docker network disconnect mynet web
7.4 查看网络详情
docker network inspect mynet # 查看该网络下有哪些容器、各自的 IP
八、端口映射原理与 DNS 解析
8.1 端口映射:外部访问容器
默认 bridge 网络下,外部访问不到容器的私有 IP,需要端口映射(第 1 篇讲过 -p 宿主机端口:容器端口)。
docker run -d --name web -p 8080:80 nginx
原理:Docker 在宿主机 iptables 加 NAT 规则,把宿主机 8080 的流量 DNAT 到容器 80。
8.2 容器访问宿主机与外部
- 容器上网:通过 Docker 的 NAT(masquerade)规则,容器以宿主机 IP 出网;
- 容器访问宿主机:Linux 上可用宿主机的网关地址(通常是 docker0 的 IP,如 172.17.0.1),或直接用
host.docker.internal(新版支持)。
8.3 容器间用名字通信
在自定义网络里,容器名会被 Docker 内置 DNS 解析为对应容器的 IP。这让多服务协作非常简单:写配置时直接用容器名当主机名,如 Web 连接数据库 db:3306。
这也是为什么 Docker Compose 里服务之间用「服务名」互相访问——本质上就是利用了自定义网络的 DNS 解析。
九、常见问题排查
9.1 容器间用 IP 能通,但用容器名不通
多半是用了默认 bridge 而不是自定义网络。把容器都放到同一个自定义 bridge 网络,即可用名字互通。
9.2 端口映射后外部还是访问不到
- 确认宿主机防火墙放行了对应端口(firewalld / iptables);
- 确认是宿主机 IP 而非容器 IP 访问;
docker port <容器>确认映射关系存在。
9.3 挂载卷后容器内权限不对(RHEL/SELinux)
RHEL 默认 SELinux enforcing,绑定挂载宿主目录到容器时,可能因文件类型标签(如 default_t)导致容器读不到。
检查并修正:
ls -Z /home/user/data # 查看 SELinux 标签
sudo chcon -Rt container_file_t /home/user/data # 改为容器可读的类型
或者临时加上 :z / :Z 挂载选项(-v /home/user/data:/data:Z)让 Docker 自动处理标签。不建议直接关闭 SELinux。
9.4 卷删除不了,提示被占用
先删掉使用该卷的容器,再 docker volume rm。docker volume prune 只删未被使用的卷。
9.5 容器能联网但 DNS 解析慢/失败
多容器协作时优先用自定义网络和容器名,减少对宿主机 DNS 的依赖;检查 /etc/resolv.conf 在容器内是否正常。
十、总结
- 三种持久化方式:命名卷(正式数据)、绑定挂载(开发/配置)、tmpfs(临时/敏感);
- 选型原则:数据库等正式数据用命名卷,源码/配置用绑定挂载,临时数据用 tmpfs;
- 卷管理:create / ls / inspect / rm / prune,可借临时容器 tar 备份;
- 网络模式:bridge(默认,可互联)、host(共享宿主,性能好)、none(完全隔离);
- 容器互联:用自定义 bridge 网络,容器间可用容器名通过内置 DNS 互通;
- RHEL 特有:SELinux 可能阻止绑定挂载,需修正标签或加 :Z。
参考资料
- Docker 官方:数据卷(Volumes):https://docs.docker.com/storage/volumes/
- Docker 官方:绑定挂载(Bind mounts):https://docs.docker.com/storage/bind-mounts/
- Docker 官方:tmpfs 挂载:https://docs.docker.com/storage/tmpfs/
- Docker 官方:网络概览(Networking overview):https://docs.docker.com/network/
- Docker 官方:自定义 bridge 网络:https://docs.docker.com/network/network-tutorial-standalone/
