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文件统一管理,那才是真正的自动化。嗯,今天就到这儿,有问题咱们评论区见。