4. Docker网络与存储:打通容器间通信与数据持久化

好,咱们进入第四章。这一章我打算聊聊Docker里两个特别基础但又特别容易踩坑的东西——网络和存储。

说实话,我刚用Docker那会儿,觉得网络不就是端口映射嘛,存储不就是挂个目录嘛。结果呢?线上容器之间互相访问不了,数据一重启就丢了,那叫一个狼狈。嗯,今天咱们就把这两个东西彻底讲透。

4.1 网络模式:容器怎么互相找到对方?

Docker的网络模式,说白了就是决定容器用什么方式跟外界通信。官方提供了三种默认模式:bridge、host、none。我一个个说。

4.1.1 bridge模式(默认)

你什么都不配,直接docker run,用的就是bridge模式。Docker会在宿主机上创建一个虚拟网桥docker0,每个容器都会分配一个私有IP,比如172.17.0.2。

容器之间可以通过IP互相访问,但有个问题——IP是动态分配的。你重启一次容器,IP就变了。所以生产环境里,我从来不用IP来通信,太不靠谱了。

核心特点:

  • 容器有独立网络栈
  • 通过端口映射暴露服务(-p 8080:80)
  • 容器间默认不能通过容器名通信

4.1.2 host模式

这个模式就简单粗暴了——容器直接使用宿主机的网络栈。没有独立IP,没有端口映射,容器里监听80端口,就等于宿主机监听80端口。

我在项目中遇到过一种场景:某个性能测试工具需要直接操作宿主机网卡,用bridge模式延迟太高。换成host模式,性能确实上去了。但代价是隔离性变差,你想想看,容器里要是搞个端口冲突,整个宿主机都受影响。

注意:host模式在Windows和Mac的Docker Desktop上表现不一样,因为底层是虚拟机。我曾经在这上面吃过亏,本地跑得好好的,上了Linux服务器就报端口冲突。

4.1.3 none模式

这个模式最极端——容器没有网络。没有网卡,没有IP,完全隔离。什么时候用?比如你跑一个离线计算任务,或者一个只处理本地文件的工具,不需要联网。安全要求高的场景,我偶尔会用。

4.2 自定义网络:这才是生产级的玩法

默认的bridge网络有个硬伤——容器之间不能通过容器名通信。你想想看,微服务架构里,订单服务要调用用户服务,总不能写死IP吧?

所以,我个人习惯是:永远创建自定义网络

# 创建一个自定义bridge网络
docker network create my-net

# 启动两个容器,都连到这个网络
docker run -d --name web --network my-net nginx
docker run -d --name app --network my-net my-app

# 现在app容器里可以直接 ping web
docker exec app ping web

看到了吗?自定义网络自带DNS解析。容器名就是主机名,互相访问直接用名字。这才是微服务通信的正确姿势。

我的建议:一个项目创建一个独立网络。比如前端服务一个网络,后端服务一个网络,数据库单独一个网络。这样既隔离又灵活。

4.3 数据卷(Volume)与绑定挂载(Bind Mount)

好,网络聊完了,咱们说说存储。Docker容器默认是无状态的——容器删了,里面的数据就没了。那数据库、日志文件怎么办?

Docker提供了两种持久化方案:Volume和Bind Mount。我分别讲讲。

4.3.1 Volume(数据卷)

Volume是Docker自己管理的存储区域。你不需要关心它在宿主机上的具体路径,Docker会帮你搞定。

# 创建一个数据卷
docker volume create my-data

# 挂载到容器
docker run -d --name db -v my-data:/var/lib/mysql mysql

我个人特别喜欢Volume,原因有三:

  • 跨平台:Linux、Windows、Mac上行为一致
  • 备份方便docker volume backup一条命令搞定
  • 性能好:底层是Docker自己优化的存储驱动

4.3.2 Bind Mount(绑定挂载)

Bind Mount就是把宿主机上的一个目录直接映射到容器里。开发时特别常用。

# 把当前代码目录挂载到容器
docker run -d --name dev -v $(pwd):/app node:18

我在项目中遇到过一个问题:开发环境用Bind Mount,代码改了容器里立刻生效,很方便。但上了生产环境,我建议换成Volume。为什么?因为Bind Mount依赖宿主机目录结构,换台机器路径不对就挂了。而Volume是Docker管理的,迁移起来省心得多。

避坑指南:我曾经把宿主机上的/etc目录挂载到容器里,结果容器里改了配置文件,宿主机也跟着变了。嗯,从那以后我每次挂载都再三确认路径。

4.4 数据持久化实战:一个完整的例子

光说不练假把式。咱们来个实战——部署一个WordPress,把数据库和网站文件都持久化。

# 1. 创建网络
docker network create wp-net

# 2. 创建数据卷
docker volume create wp-db-data
docker volume create wp-site-data

# 3. 启动MySQL
docker run -d \
  --name wp-db \
  --network wp-net \
  -v wp-db-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=root123 \
  -e MYSQL_DATABASE=wordpress \
  mysql:8.0

# 4. 启动WordPress
docker run -d \
  --name wp-app \
  --network wp-net \
  -v wp-site-data:/var/www/html \
  -p 8080:80 \
  -e WORDPRESS_DB_HOST=wp-db \
  -e WORDPRESS_DB_USER=root \
  -e WORDPRESS_DB_PASSWORD=root123 \
  wordpress:latest

这个例子你看懂了吗?关键点:

  • 两个容器通过自定义网络wp-net通信,用容器名wp-db连接数据库
  • 数据库数据存在wp-db-data卷里,删了容器数据还在
  • 网站文件存在wp-site-data卷里,上传的图片不会丢

验证持久化:

# 停掉并删除容器
docker stop wp-app wp-db
docker rm wp-app wp-db

# 重新启动
docker run -d --name wp-db --network wp-net -v wp-db-data:/var/lib/mysql ... mysql:8.0
docker run -d --name wp-app --network wp-net -v wp-site-data:/var/www/html -p 8080:80 ... wordpress:latest

# 打开浏览器访问 localhost:8080,你会发现之前的文章和配置都在!

这就是数据持久化的威力。你想想看,要是没有Volume,每次重启容器都得重新安装WordPress、重新配置,那得多崩溃。

4.5 本章小结

好,咱们捋一下这章的核心:

  • 网络模式:bridge适合单机开发,host适合性能敏感场景,none适合离线任务。但生产环境我推荐自定义网络。
  • 自定义网络:自带DNS解析,容器名即主机名,微服务通信的标配。
  • 数据持久化:Volume适合生产环境,Bind Mount适合开发调试。别搞混了。
  • 实战要点:网络+存储组合使用,才能构建出可迁移、可恢复的容器化应用。

下一章咱们会聊Docker Compose,到时候这些网络和存储的配置都会用YAML文件统一管理,那才是真正的自动化。嗯,今天就到这儿,有问题咱们评论区见。