当我们使用 Docker 搭建应用时,经常会遇到 多个容器需要互相通信 的情况,比如 Web 容器访问数据库容器,Nginx 容器反向代理后端服务容器。那么问题来了:这些容器是如何联网的?又是如何通过名称解析对方的?
这篇文章将带你深入理解 Docker 的网络模型、自定义网络配置、容器 DNS 原理,并通过一个 Web + 数据库的实际案例让你真正掌握容器互联的能力
一、Docker 的网络模型有哪些?
Docker 安装后默认提供了几种内置网络类型,可以通过以下命令查看:
docker network ls
你会看到类似以下几种:
网络模式 | 简介说明 |
bridge(默认) | 容器使用虚拟网桥与主机通信,最常用模式 |
host | 容器共享主机网络(无隔离) |
none | 容器没有网络功能 |
overlay | 用于 Swarm 集群跨主机通信(高级用法) |
bridge 模式(默认,最常用)
- 每个容器分配一个私有 IP,由 Docker 虚拟网桥 docker0 统一管理
- 容器之间可以用 IP 通信,也可以通过容器名通信(需在同一网络中)
举例:
docker run -d --name web nginx
docker run -d --name redis redis
如果都使用默认 bridge 网络,它们之间无法通过名字访问对方,只能通过 IP。但这个 IP 可能重启后变化
host 模式(共享主机网络)
- 容器直接使用宿主机的网络,没有网络隔离
- 使用宿主机的 IP 和端口
举例:
docker run --net=host nginx
它适用于一些需要完整访问宿主网络的高性能服务,但缺乏隔离性,慎用!
none 模式(完全隔离)
容器完全没有网络,适合某些只进行计算或处理的服务(例如加密任务、文件处理等)。
docker run --net=none alpine
二、自定义网络和容器互联
Docker 支持创建自定义网络,让多个容器通过容器名互相访问,这是微服务架构下的主流做法。
创建一个自定义网络
docker network create my-net
启动两个容器并加入该网络
docker run -d --name web --network my-net nginx
docker run -d --name db --network my-net mysql
这样,web 容器就可以通过 db:3306 直接访问数据库容器了!
这是实现容器互通、服务发现的关键前提。
三、容器内部的 DNS 实现原理
Docker 自带了一个轻量级的内置 DNS 服务器,当多个容器加入同一个自定义网络后,它们的容器名会自动注册到这个 DNS 中。
实现机制:
- 每个容器启动时都会被分配一个 hostname(容器名)
- 加入同一个自定义网络的容器,会注册 DNS 记录
- Docker 会自动为 /etc/resolv.conf 配置内部 DNS
- 所以容器内部的 ping 容器名、curl 容器名:端口 是可行的
四、实战:Web + 数据库 组合部署示例
我们来部署一个简单的 Web 服务(用 Nginx 做前端),后台连接 MySQL 数据库。
步骤 1:创建网络
docker network create web-net
步骤 2:运行 MySQL 容器
docker run -d \
--name mysql \
--network web-net \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7
步骤 3:运行 Nginx 容器(作为前端)
docker run -d \
--name web \
--network web-net \
-p 8080:80 \
nginx
测试互通性
进入 web 容器:
docker exec -it web bash
测试是否能解析并 ping 通 mysql 容器:
ping mysql
如果能通,说明 DNS 正常,网络互通,容器名解析成功
五、网络清理与管理命令汇总
- 查看网络:
docker network ls
- 查看容器所连接的网络:
docker network inspect my-net
- 删除网络(需确保无容器连接):
docker network rm my-net
总结回顾
知识点 | 说明 |
bridge 模式 | 默认模式,常见于单机部署 |
host 模式 | 性能高但缺乏隔离,慎用 |
自定义网络 | 支持容器名通信,是推荐做法 |
内置 DNS | 实现服务自动发现的关键 |
多容器互联实战 | 创建自定义网络 + 各容器加入其中 |