Docker 容器的 DNS 是怎么实现的!

在日常使用 Docker 构建微服务架构的过程中,我们经常会遇到一个问题:多个容器之间是如何通过名字互相访问的?DNS 是怎么做到的?

从底层机制讲清楚 Docker 的 DNS 系统


1. 容器间通信的前提:同一个网络

Docker 默认会创建一个叫 bridge 的网桥网络。所有未指定网络的容器,都会被分配到这个 bridge 网络中。

在这个默认网络中,虽然每个容器都有一个独立的 IP 地址,但要实现通过容器名访问其他容器,就必须依赖 Docker 提供的 DNS 服务。

注意:只有在用户自定义的 bridge 网络中,容器名解析才默认开启!默认的 bridge 网络不支持容器名解析!


2. Docker 的内置 DNS 是如何工作的?

Docker 在每个容器启动时,会将容器的 /etc/resolv.conf 文件指向一个特殊的 DNS 地址:127.0.0.11

这个地址并不是真的公网 DNS,而是 Docker Daemon 内置的 DNS 服务器

这个 DNS 有以下作用:

  • 解析外部域名(比如访问百度、Google)
  • 解析容器内部服务名(比如 web, db 等容器名)

它的背后是 Docker 的 embedded DNS server,工作机制大概如下:

1 容器发出 DNS 查询请求(查某个服务名)
2 请求发到 127.0.0.11(docker 的内部 DNS)
3 Docker DNS 根据网络配置,找到对应容器的 IP 地址
4 将结果返回给发起请求的容器


3. 实验验证:容器名访问是否生效?

我们创建一个自定义网络,并启动两个容器测试下

# 创建一个自定义 bridge 网络
docker network create mynet

# 启动容器A,名字叫 web
docker run -it --rm --name web --network mynet busybox sh

# 启动容器B,在这个网络中尝试 ping web
docker run -it --rm --network mynet busybox sh

在 B 容器中输入:

ping web

你会发现,DNS 能自动解析出 web 的 IP,这就说明 Docker 的内置 DNS 正常工作啦


4. 自定义服务名(别名)怎么设置?

有时候我们希望容器访问的名字不是容器名,而是我们指定的服务名。Docker 也支持这一点:

docker run -it --rm \
  --network mynet \
  --name mydb \
  --network-alias database \
  busybox sh

然后在其他容器中,就可以通过 database 这个名字访问它


5. 与外部 DNS 的协同

Docker 的 embedded DNS 并不是万能的,它在无法解析服务名时,会把请求转发给 /etc/resolv.conf 中指定的上游 DNS。

这意味着:

  • 外部网络访问正常(比如你容器内 ping www.baidu.com
  • 内部容器名也能解析
  • Docker DNS 是中间层代理

这个设计非常巧妙!兼顾了内外网的域名解析。


6. 容器 DNS 失效的常见问题

  • 没有使用自定义网络,导致 DNS 解析失败
  • 使用了 host 网络,容器直接共享宿主机网络,无法使用 Docker 的 DNS
  • resolv.conf 修改或者挂载了宿主机 DNS 文件
  • 某些 VPN 环境导致容器 DNS 路由异常

解决方法建议:

  • 尽量使用自定义 bridge 网络
  • 检查 /etc/resolv.conf 是否被覆盖
  • 检查 Docker 网络配置 docker network inspect

总结

Docker 容器之间的 DNS 解析,其实是靠 Docker Daemon 内置的 DNS 服务(监听在 127.0.0.11)来实现的,它能让容器通过服务名互相访问,还支持 alias、自定义网络、多级域名等能力。

原文链接:,转发请注明来源!