03 · 数据卷与网络(Volume and Network)

📅 预计 60 分钟 | ⭐ = 重要知识点 | 📌 中英术语见文末
🛠 本讲命令基于 Docker 引擎,均可直接运行


3.0 先给直觉:临时工的两个短板

容器像"临时工":随叫随到(秒级启动),干完即走(删除就没了)。但临时工有两个短板——干过的活不留存(容器删了,里面改的文件全没了)和没有自己的联系地址(默认出不去、别人也进不来)。

这一讲解决这两件事:

  • 数据卷(volume):给容器配一个"专属储物柜",柜子在宿主机上,容器删了柜子还在。
  • 网络(network):给容器发"门牌号"(IP、端口映射),让它能和外面以及别的容器通信。

💡 记忆口诀:容器是无状态的一次性用品;数据卷负责"留数据",网络负责"通消息"。


3.1 数据卷:给容器配"专属储物柜"

为什么要数据卷

容器的文件系统是临时的:docker rm 一删,容器里的所有改动(数据库、上传的文件、日志)全部消失。所以凡是要长期保留的数据,都不能只写在容器里,要放到容器之外的存储上。

数据卷就是宿主机上由 Docker 管理的一块存储,挂载进容器后,容器里读写它,就像读写自己的目录,但数据实际落在宿主机上。

三种挂载方式 ⭐:

方式 类型 数据在哪 适用场景
命名卷 volume Docker 管理(/var/lib/docker/volumes/ 数据库数据、重要文件
绑定挂载 bind mount 宿主机指定目录(你指定的路径) 开发改代码即时生效
临时挂载 tmpfs 宿主机内存 只要临时数据、不要落盘

创建和使用命名卷

docker volume create mydata    # 创建卷
docker volume ls               # 查看所有卷
docker volume inspect mydata   # 查看卷详情(挂载点等)

运行容器时挂载:

docker run -d -v mydata:/var/lib/mysql --name db mysql:8.0

-v mydata:/var/lib/mysql 的语法是 卷名:容器内路径:把名为 mydata 的卷挂到容器里的 /var/lib/mysql 目录。MySQL 把数据写进该目录,容器删了,mydata 卷还在,下次换个容器挂同一个卷,数据原样回来。

绑定挂载:开发时改代码即时生效

docker run -d -v /home/user/app:/app -w /app node:18

-v /home/user/app:/app:宿主机目录 ,容器目录 。宿主机上改代码,容器里立刻能看到——开发时不用每次重新构建镜像,非常方便。-w /app 是设置工作目录。

另一种写法:--mount

--mount 更啰嗦但更明确,脚本和文档里常见:

docker run -d \
  --mount type=volume,source=mydata,target=/var/lib/mysql \
  --name db mysql:8.0

typevolume / bind / tmpfs 三种之一,source 是来源,target 是容器内路径。

数据卷的备份与共享

卷的数据在宿主机上,备份用临时容器挂载打包即可:

# 把 mydata 卷打包成 mydata-backup.tar
docker run --rm -v mydata:/data -v $(pwd):/backup alpine \
  tar czf /backup/mydata-backup.tar -C /data .

思路:用一个临时容器同时挂载目标卷和当前目录,把卷内容打成 tar 包放到宿主机,--rm 用完即删。

多个容器共享同一份数据,除了各挂同一个卷,还可以用 --volumes-from 继承另一个容器的挂载:

docker run -d --name db mysql:8.0        # 先起一个挂卷的容器
docker run -d --volumes-from db backup-service  # 新容器复用 db 的挂载

⚠️ 常见错误

  1. -v 路径写反宿主机:容器,写反了会挂错目录甚至报错。
  2. bind mount 用绝对路径-v ./app:/app 在 Compose 里是相对项目目录;直接用 docker run 时要写绝对路径,否则 Docker 可能把 ./app 当成卷名处理。
  3. 忘了挂卷就删容器:数据库容器没挂卷,docker rm 之后数据永久丢失——重要数据务必先挂卷再跑。

3.2 容器间网络:门牌号与通讯录

Docker 的网络模型

Docker 安装时会创建一块虚拟网桥 docker0,容器默认接入它,走 bridge(桥接) 模式。每启动一个容器,Docker 会给它分配一个内网 IP,像给每间房发门牌号。容器之间、容器与宿主机之间靠这个虚拟网络互通。

三种默认网络模式 ⭐:

模式 网络隔离 特点 适用
bridge(默认) 有独立网络栈 通过 NAT 出网,需 -p 映射对外 日常单容器、隔离需求
host 无隔离 直接用宿主机网络栈,性能最好,无端口映射 高性能服务、想直接共享宿主网络
none 完全隔离 无网络,适合离线任务 安全敏感的临时任务

host 模式特别注意:容器直接用宿主机的 IP 和端口,-p 参数会被忽略(不需要也做不到"映射",因为端口已经共享了)。

自定义网络:容器间的"通讯录"

默认 bridge 下,容器之间可以用 IP 通信,但 IP 会变、不好记。更专业的做法是创建自定义网络,容器之间直接用容器名互相访问(Docker 内置 DNS 解析):

docker network create mynet          # 创建自定义桥接网络
docker run -d --network mynet --name web nginx
docker run -it --network mynet --name client ubuntu bash
# 在 client 容器里:ping web  /  curl http://web

mynet 里,web 这个名字就代表那个 nginx 容器,别的容器用它访问即可——这是第 5 讲 Compose 里服务互相调用能"只写服务名"的底层原理。

网络管理的命令

docker network ls              # 列出所有网络
docker network inspect mynet   # 看网络详情(接入的容器、网段等)
docker network connect mynet web   # 把一个已运行的容器接入网络
docker network disconnect mynet web # 把容器从网络断开

一个容器可以同时接多个网络:比如既在 mynet 里和别的容器通信,又保持默认网络对外映射。多网络在"数据库隔离网络 + 网关网络"这类分层架构里很常见。

排查容器连不通时,先 docker network inspect 确认两边在同一个网络里,再用 docker exec 进容器 ping 对方服务名试连通性。

⚠️ 常见错误

  1. 默认网络里别指望容器名解析:只有自定义网络才有内置 DNS 的容器名解析,默认 bridge 里要用 IP 或老旧的 --link
  2. host 模式还写 -p:写了也没用,直接拿宿主机端口用,端口冲突时会启动失败。
  3. 以为 none 是"坏"模式:它是故意切断网络,跑离线任务或安全场景时恰恰是特性。

3.3 端口映射:让外面的世界找到你

三种映射写法 ⭐

docker run -d -p 8080:80 --name web nginx      # 宿主8080 → 容器80
docker run -d -P --name web2 nginx             # -P 大写:随机宿主端口映射所有EXPOSE端口
docker run -d -p 80 --name web3 nginx          # 只写容器端口:宿主随机端口映射到容器80

-p 8080:80 的语法是 宿主机端口:容器端口,方向千万别记反。

  • 访问方式:浏览器访问 http://宿主机IP:8080,请求进入宿主机 8080 端口,Docker 转发给容器 80。
  • -P(大写)会读取镜像里 EXPOSE 声明的端口,为它们各随机分配一个宿主端口,可通过 docker port web2 查看实际端口。
docker port web    # 查看容器的端口映射明细

为什么容器默认外面访问不到

容器在私有网段里(如 172.17.x.x),外部网络无法直接路由到它。-p 做的事是在宿主机上"开一个口"(监听宿主端口),把流量转进容器——类似小区门卫:外来找 8080 房号,门卫帮你转给里面那间房。

⚠️ 常见错误

  1. 映射方向写反-p 80:8080 是把宿主 80 转到容器 8080,如果容器实际监听 80,就连不上。
  2. 只写 -p 容器端口:会用随机宿主端口,你能访问但端口不稳定,记得 docker port 查一下。
  3. 忘写 -p 就以为能访问:容器内部服务默认对外不可见,不映射就访问不到。

📌 双语术语表(本讲)

中文 English 记忆点
数据卷 volume 专属储物柜
绑定挂载 bind mount 宿主机目录直连容器
临时挂载 tmpfs 内存中的临时盘
桥接模式 bridge 默认,NAT 出网
主机模式 host 共享宿主网络栈
无网络 none 完全隔离
端口映射 port mapping 宿主端口:容器端口
随机映射 -P 大写 P 随机端口
自定义网络 custom network 容器名互相访问
暴露端口 expose 声明端口(EXPOSE
备份卷 volume backup 临时容器打包
继承挂载 volumes-from 复用别的容器的卷
接入网络 network connect 运行中也能改网络
多网络 multiple networks 一个容器接多个网

⭐ 本讲考点清单

  1. 三种挂载方式:命名卷 / bind mount / tmpfs,各自的数据存放位置
  2. -v 卷名:容器内路径 语法,宿主机目录在冒号前
  3. 容器删了,卷还在;重要数据必须挂卷
  4. 三种网络模式:bridge(默认)/ host(共享网络栈,无端口映射)/ none(无网络)
  5. host 模式下 -p 无效
  6. -p 宿主端口:容器端口 方向;-P 随机映射;docker port 查看
  7. 自定义网络 + 容器名互访(内置 DNS)
  8. 默认 bridge 网络不提供容器名解析
  9. 容器默认对外不可见,必须 -p 才能从外部访问
  10. --mount type=volume,source=...,target=... 的写法
  11. 卷备份用临时容器挂载打包;--volumes-from 复用别的容器的挂载
  12. network connect / disconnect 可动态改容器网络;一个容器可接多网络
  13. 排查连通性:network inspect 确认同网 → exec 进容器 ping 服务名