高级java每日一道面试题-2026年01月28日-实战篇[Docker]-Docker 网络的 DNS 解析是如何工作的?如何自定义 DNS?
2026/6/17 18:33:47 网站建设 项目流程

Docker 网络 DNS 解析原理与自定义 DNS 配置深度解析

在容器化微服务中,服务实例动态启停、IP 频繁变化。硬编码 IP 不可行,而手动维护 hosts 文件更不现实。Docker 通过内置 DNS 服务器实现了自动化的服务发现,让容器之间可以直接使用服务名容器名进行通信,无需知晓底层 IP。理解这套 DNS 机制以及如何根据需求自定义 DNS 配置,是保障 Java 微服务稳定通信的基础。


一、Docker 网络 DNS 解析机制概览

不同网络驱动提供的 DNS 能力差异显著:

网络类型DNS 解析解析目标说明
默认 bridge (docker0)不支持内置 DNS容器只能通过 IP 通信;可借助--link/etc/hosts中添加条目(已废弃)
自定义 bridge内置 DNS 服务器容器名 → 容器 IP同一网络下容器名自动解析;支持别名(--network-alias
Overlay (Swarm)内置 DNS 服务器服务名 → VIP(虚拟 IP),或任务名 → 副本 IP(DNSRR)与 Swarm 服务发现深度集成;VIP 模式提供负载均衡
Host / None无特殊 DNS继承宿主机/etc/resolv.conf容器直接使用宿主机的 DNS 配置

结论:生产环境推荐始终使用自定义 bridgeoverlay网络,以获得完整的 DNS 服务发现能力。


二、内置 DNS 服务器的工作原理

Docker 守护进程为每个自定义网络(bridge 或 overlay)都维护了一个嵌入式 DNS 服务器。该服务器监听在127.0.0.11,所有连接到此网络的容器都会自动将 DNS 请求发往该地址。

2.1 容器名解析流程(自定义 bridge)

当容器 A 尝试访问容器 B(通过容器名my-app)时:

ContainerBDNS 记录表(网络内所有容器名→IP)Docker 内置 DNS(127.0.0.11:53)容器 AContainerBDNS 记录表(网络内所有容器名→IP)Docker 内置 DNS(127.0.0.11:53)容器 A查询 "my-app" 的 A 记录查找 "my-app"返回 IP: 172.18.0.3解析结果 172.18.0.3直接通过 IP 通信

关键特性

  • 动态更新:容器加入网络时,其名称和 IP 立即注册到 DNS 表;容器停止或断开网络时,记录同步移除。
  • 多副本支持:若同一网络中有多个容器使用相同的别名(--network-alias),DNS 会以轮询(Round-Robin)顺序返回多个 IP,实现简单的客户端负载均衡。
  • FQDN 支持:容器可被解析为<容器名><容器名>.<网络名>

2.2 Swarm 服务名解析(VIP 与 DNSRR)

在 Swarm 集群中,创建 overlay 网络的服务时,Docker 会为该服务分配一个虚拟 IP (VIP)。容器内 DNS 解析服务名时:

  • VIP 模式(默认):服务名解析为 VIP,VIP 通过内核 IPVS 负载均衡到各副本容器。客户端看到的是一个固定 IP,无需感知后端变化。
  • DNS Round Robin (DNSRR):服务名直接解析为所有副本容器的 IP 列表,客户端自行轮询。适合需要自定义负载均衡策略的应用。

解析时序(VIP 模式)

服务副本容器宿主机 IPVS服务 VIP (10.0.9.5)内置 DNS客户端容器服务副本容器宿主机 IPVS服务 VIP (10.0.9.5)内置 DNS客户端容器查询 "user-service"返回 VIP: 10.0.9.5发起连接 (dst: 10.0.9.5)IPVS 根据调度算法选择后端转发到具体副本 (10.0.9.6)响应

三、默认 bridge 网络的 DNS 缺陷与--link

默认 bridge 网络(docker0没有内置 DNS 服务器。容器只能通过/etc/hosts文件来解析其他容器的主机名,而该文件仅在容器启动时由 Docker 写入。要实现容器名解析,传统做法是使用--link参数,Docker 会在被链接容器的信息注入到当前容器的/etc/hosts和环境变量中。

问题

  • 单向性:link 是单向的,且被依赖容器重启后 IP 变化会导致 hosts 条目失效。
  • 维护困难:在大规模场景下,手动管理 link 关系几乎不可行。
  • 已废弃:Docker 官方已不推荐使用--link,建议迁移至自定义网络。

四、容器 DNS 配置来源与resolv.conf生成

每个容器的/etc/resolv.conf文件决定了它使用的 DNS 服务器。Docker 按以下规则生成该文件:

  1. 默认行为:Docker 守护进程复制宿主机的/etc/resolv.conf到容器,并过滤掉本地回环地址(127.0.0.*)等不适用条目。
  2. 加入自定义网络后:Docker 会在容器resolv.conf最前面插入内置 DNS 地址127.0.0.11。这样容器的 DNS 查询会优先发往内置 DNS,未命中(如外部域名)再转发给宿主机 DNS。
  3. Daemon 全局配置:可以通过--dns--dns-search--dns-opt参数在docker run时覆盖,或在daemon.json中设置全局默认值。
  4. Docker Composedns关键字可在服务级别配置。

生成逻辑架构图

容器内 /etc/resolv.conf 生成

宿主机 /etc/resolv.conf
nameserver 8.8.8.8

daemon.json dns 配置

docker run --dns ...

docker-compose dns 配置

优先级合并

内置 DNS 127.0.0.11
(若加入自定义网络)

自定义 DNS 服务器

宿主机 DNS 服务器
(过滤后的)

容器内实际看到的resolv.conf可能类似:

nameserver 127.0.0.11 # 内置 DNS(若有自定义网络) nameserver 8.8.8.8 # 自定义或宿主机 DNS

五、如何自定义 DNS 配置

Docker 允许在多个层面灵活指定 DNS 配置:

配置方式作用范围说明
docker run --dns单个容器指定 DNS 服务器地址;可多次使用以添加多个
docker run --dns-search单个容器指定 DNS 搜索域
docker run --dns-opt单个容器传递 DNS 选项(如ndots:5
daemon.json中的dns所有容器(全局默认)例如{"dns": ["8.8.8.8", "1.1.1.1"]}
Docker Composedns服务级别的容器定义在服务定义中
Docker Composeextra_hosts服务级别的容器添加静态主机名映射到/etc/hosts

自定义 DNS 的常见场景

  • 内部企业 DNS:需要解析企业内部域名(如数据库中间件地址)。
  • 加速外部解析:使用更快的公共 DNS(如 DNSPod、Google DNS)。
  • 测试环境域名劫持:将特定域名指向测试服务器。
  • NDOTS 调整:优化短名称查询次数,适用于 Kubernetes 等分多级域名的环境。

六、Java 应用视角下的实践建议

Spring Boot 等 Java 微服务大量依赖 DNS 进行服务发现(例如数据库 URL 中使用服务名,或 Feign 调用其他微服务)。在 Docker 环境中应注意:

  • 始终使用自定义网络,确保容器名或服务名可解析。
  • 使用环境变量注入外部域名,避免硬编码。
  • 若需要连接外部数据库(非容器化),可通过--dns或配置extra_hosts来解析数据库主机名。
  • JVM 的 DNS 缓存:Java 默认会永久缓存 DNS 解析结果(除非设置networkaddress.cache.ttl),在频繁变动 IP 的环境中应设置较短的 TTL,以确保能快速感知容器 IP 变化。

七、思维导图总结

Docker DNS 解析

内置 DNS 原理

127.0.0.11 嵌入式服务器

动态注册容器名与 IP

支持别名多记录轮询

Swarm 服务发现

VIP 模式 + IPVS 负载均衡

DNSRR 模式返回副本 IP 列表

默认 bridge 限制

无内置 DNS

--link 已废弃

resolv.conf 生成

宿主机 DNS 被复制并过滤

内置 DNS 优先

可被 --dns 覆盖

自定义 DNS

docker run --dns

daemon.json 全局配置

docker-compose dns

extra_hosts 静态映射

Java 最佳实践

使用自定义网络

设置 JVM DNS 缓存 TTL

外部域名用环境变量

通过上述体系,您可以在面试中清晰阐述 Docker 的 DNS 解析机制、不同网络模式下的行为差异,以及如何根据实际需求定制 DNS 配置,体现对容器网络服务发现的深刻理解。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询