容器之间是如何通过容器名称或服务名称进行域名解析(DNS)的?
在 Docker 中,容器之间能够通过容器名称(Container Name)或服务名称(Service Name)进行域名解析,核心依赖于 Docker 内部实现的 嵌入式 DNS 服务器(Embedded DNS Server)。
下面为您详细拆解其工作原理、实现机制以及不同场景下的应用。
1. 核心前提:用户自定义网络(User-Defined Bridge)
这是最关键的一点:只有在使用“用户自定义网络”(如自己创建的 bridge 网络)时,Docker 的 DNS 解析才会生效。
- 默认的
bridge网络(不推荐): 如果你直接运行docker run而不指定网络,容器会被加入到默认的bridge网络中。在这个网络里,Docker 不提供容器名 DNS 解析,容器间只能通过 IP 地址通信。 - 自定义网络(推荐): 当你创建并使用自定义网络时,Docker 会为该网络启动一个内置的 DNS 服务器(IP 通常为
127.0.0.11)。
快速验证:
# 1. 创建一个自定义网络
docker network create my-net
# 2. 运行容器 A 并加入网络
docker run -d --name web-server --network my-net nginx
# 3. 运行容器 B 并通过容器名 ping 容器 A
docker run --rm --network my-net alpine ping -c 2 web-server
输出中会显示 web-server 被成功解析成了对应的容器 IP。
2. 内部工作原理(DNS 解析流程)
当容器 B 尝试连接 http://web-server 时,幕后发生了以下步骤:
修改
/etc/resolv.conf:
当容器启动并加入自定义网络时,Docker 会自动修改容器内的/etc/resolv.conf文件,将其中的nameserver指向127.0.0.11(这是 Docker 嵌入式 DNS 服务的监听地址)。发起 DNS 查询:
容器 B 的应用程序发起对web-server的域名解析请求,请求被发送到127.0.0.11:53。Docker 内部 DNS 拦截并解析:
Docker 守护进程(Docker Daemon)维护着一个动态的“容器名-IP”映射表。每当有新容器启动、停止或加入网络时,这个表就会实时更新。- Docker DNS 发现查询的是
web-server,并在映射表中找到了它在my-net网络中的 IP(例如172.18.0.2),然后将该 IP 返回给容器 B。
- Docker DNS 发现查询的是
外部域名转发(备用):
如果容器查询的是一个外部域名(如baidu.com),Docker 内部 DNS 无法解析,它会将请求转发给宿主机配置的 DNS 服务器(如8.8.8.8或本地 DNS)。
3. 不同场景下的解析方式
场景 A:Docker Compose(最常见)
在 Docker Compose 中,解析更加简单和直观。
- 服务名(Service Name)即域名:在同一个yaml
version: '3' services: web: image: nginx db: image: postgresdocker-compose.yml中,Docker 会自动创建一个默认网络。web容器可以直接通过db这个域名连接到数据库容器。
场景 B:网络别名(Network Aliases)
有时你希望一个容器有多个名字,或者用一个别名来代表它。
docker run -d --name my-mysql --network my-net --network-alias database mysql
此时,其他容器既可以通过 my-mysql(容器名)解析,也可以通过 database(别名)解析。
场景 C:Docker Swarm 模式(服务发现与负载均衡)
在 Docker Swarm 集群中,解析机制升级为 VIP(Virtual IP) 机制:
- 你创建了一个名为
search-api的服务,副本数(replicas)为 3。 - 其他容器解析
search-api时,Docker DNS 不会直接返回那 3 个容器的实际 IP,而是返回一个 虚拟 IP (VIP)。 - 当流量到达 VIP 时,Docker 内核的 IPVS(IP Virtual Server)会自动将请求负载均衡到后端那 3 个实际的容器中。
4. 总结
| 机制 | 默认 bridge 网络 | 用户自定义 bridge 网络 | Docker Compose | Docker Swarm |
|---|---|---|---|---|
| DNS 解析 | ❌ 不支持 | 支持 | 支持 | 支持 |
| 解析对象 | 无 | 容器名、容器ID、别名 | 服务名 (Service Name) | 服务名 (Service Name) |
| 负载均衡 | 无 | 无 | 无 | 支持 (通过 VIP/DNS RR) |