Docker 容器如何通过内置 DNS 实现服务发现?

来源:网站运营作者:马来西亚程序员头衔:程序员
导读:本期聚焦于马来西亚程序员创作的《Docker 容器如何通过内置 DNS 实现服务发现?》,敬请观看详情。当多个容器组成应用时,IP地址随生命周期频繁变化,手动配置通信目标几乎不可维护。Docker通过内置DNS解析器和服务发现机制,把容器名称、网络别名和服务名直接映射到实际网络地址,让服务调用不再依赖固定IP。本文从127.0.0.11嵌入式DNS服务器讲起,解释自定义网络中的名称解析规则、DNS查询流程以及容器别名的作用。随后结合Docker Compose与Swarm编排场景,说明服务发现如何跟随容器扩缩容自动更新,并给出--dns、--dns-search等参数的使用方式。最后梳理跨网络解析失败、DNS缓存导致地址不刷新等常见问题的排查方法。理解这些机制后,你可以构建更稳定的容器通信方案,避免将IP写死在配置里。

在容器化环境里,服务实例的IP地址会随着重启、扩容和迁移不断变化。如果仍然像传统物理机那样把IP地址写进配置文件,维护成本会非常高。Docker从1.10版本开始引入内置DNS服务器,为自定义网络中的容器提供名称解析能力。容器不再需要知道对方的准确IP,而是可以通过容器名、网络别名或服务名直接访问。

Docker 容器如何通过内置 DNS 实现服务发现?

一、Docker内置DNS服务器与解析流程

Docker为每个自定义网络维护一个嵌入式DNS服务器,监听地址固定为127.0.0.11,使用UDP 53端口。当容器加入自定义网络后,Docker会修改容器内的/etc/resolv.conf文件,将nameserver指向127.0.0.11。这意味着容器内部发起的所有DNS查询,首先都会发往Docker守护进程维护的DNS组件,而不是直接到达宿主机或外部DNS。

该内置DNS并不像传统DNS服务器那样维护完整的域名区域。它主要维护三类映射:容器名称、网络别名以及服务发现中的服务名与VIP。解析时,Docker会按照以下顺序查找:先匹配完整的容器名,再匹配网络别名,最后处理外部域名。若查询的名称不属于当前网络中的容器或服务,Docker内置DNS会将请求转发给宿主机配置的DNS或用户通过--dns指定的上游DNS服务器,从而兼容访问互联网域名。

理解这个流程的关键在于网络隔离。同一个自定义网络中的容器共享同一个内置DNS作用域,能够互相通过名称解析;而不同自定义网络之间,即使知道容器名称也无法解析,除非让容器加入多个网络或者使用外部DNS方案。这种隔离避免了名称冲突,也提高了多环境部署的清晰度。

# 创建两个自定义网络并观察隔离效果
docker network create backend
docker network create frontend

# 启动一个容器加入 backend
docker run -d --name api --network backend busybox sleep 3600

# 同一网络内可以通过名称解析
docker run --rm --network backend busybox ping -c 1 api

# 从另一个网络无法解析 api
docker run --rm --network frontend busybox nslookup api

二、自定义网络中的容器名称与网络别名

在Docker默认的bridge网络上,早期版本依赖--link参数才能实现名称解析,这种方式已不推荐使用。切换到自定义网络后,Docker会为每个容器自动注册其名称。通过docker network create创建的网络默认为桥接网络,支持内置DNS。容器启动时使用--network参数加入该网络,随后就能用容器名访问其他容器。

网络别名是更灵活的服务发现方式。一个容器可以设置多个别名,例如--network-alias db--network-alias database。当多个容器共享同一个网络别名时,DNS查询会返回该别名对应的所有容器IP。这种机制可以作为简单的负载均衡,只是需要注意它依赖DNS轮询,而应用层如果缓存解析结果,可能不会均匀分布请求。

下面的示例展示如何创建自定义网络,并让两个Redis容器共享别名cache。通过nslookup cache可以看到返回两个IP地址,实现了最基本的服务发现和冗余。

docker network create appnet

docker run -d --name redis1 --network appnet --network-alias cache redis:7
docker run -d --name redis2 --network appnet --network-alias cache redis:7

docker run --rm --network appnet alpine nslookup cache
# 输出中会包含 redis1 和 redis2 的IP地址

容器也可以加入多个网络,并获得每个网络内的解析能力。例如API服务可以同时加入backendfrontend,这样既能被前端访问,又能连接数据库。加入多个网络后,容器的/etc/resolv.conf中的搜索域会包含这些网络的域名,但需要注意如果不同网络中注册了相同名称,查询结果可能存在歧义。因此建议通过规划网络别名来避免冲突。

三、Docker Compose 与 Swarm 中的服务发现

Docker Compose在启动一组服务时,会默认创建一个项目级别的网络,并将所有服务加入该网络。Compose内部使用Docker DNS机制,允许服务之间用服务名直接通信。例如docker-compose.yml中定义了webdb两个服务,web应用连接数据库时只需使用主机名db,无需关心容器实际IP。即使数据库容器重建,名称解析也会自动更新。

version: "3"
services:
  web:
    image: nginx
    networks:
      - appnet
  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: secret
    networks:
      - appnet

networks:
  appnet:
    driver: bridge

在Swarm模式下,服务发现进一步提升。Docker为每个Swarm服务分配一个虚拟IP(VIP),当其他服务通过服务名访问时,内置DNS返回VIP地址,随后由Swarm的负载均衡机制将请求分发到具体任务副本。这种VIP模式避免了客户端缓存单个容器IP导致扩缩容后连接失败的问题。如果使用--endpoint-mode dnsrr,则DNS直接返回副本IP列表,适合某些需要自己实现负载均衡的中间件。

Swarm滚动更新时,服务名保持不变,DNS解析结果会从旧VIP切换到新VIP,或者返回最新任务列表。这让服务发现具备动态性。需要特别注意的是,VIP模式在同一时间只返回一个虚拟IP,应用层连接建立后通常不会再重新解析,因此单次连接不受扩缩容影响,但新建立的连接会被正确路由到健康的副本。对于长连接场景,建议配合健康检查和优雅退出机制。

四、DNS参数配置与常见问题排查

Docker允许通过运行参数调整DNS行为。--dns可以为容器指定外部DNS服务器,比如公司内网DNS或公共DNS;--dns-search添加搜索域;--dns-opt传递额外的DNS选项,例如超时时间。这些设置会写入容器的/etc/resolv.conf,并且优先级高于宿主机的DNS配置。在内置DNS无法解析外部域名时,这些上游DNS服务器就起到回退作用。

docker run -d --name app --dns 223.5.5.5 --dns-search ippipp.com --dns-opt timeout:2 nginx

排查解析问题时,可以先检查容器内部是否能看到127.0.0.11这个nameserver。使用docker exec app cat /etc/resolv.conf查看配置。如果nameserver不是127.0.0.11,说明容器可能没有正确加入自定义网络,或者使用了特殊网络模式。接着可以用nslookupping测试名称解析。如果外部域名解析失败但容器名称可解析,通常是上游DNS配置问题或网络隔离导致。

跨网络无法解析是最常见的情况。例如web服务在默认bridge网络中,数据库在自定义网络中,此时web容器无法通过名称解析数据库。解决方法是把web也加入自定义网络,或者统一使用Compose网络。另一个常见问题是应用层DNS缓存,某些程序在启动时解析一次并长期持有IP,容器重启后IP变化导致连接失败。优化思路包括设置合理的TTL、使用连接池,或在应用内部实现重新解析机制。

还需要注意,Docker内置DNS不会缓存查询结果,它每次都会根据当前网络状态返回实时信息。但部分客户端或语言运行时会缓存DNS结果,例如Java的InetAddress缓存。如果遇到地址不更新,排查时应区分是Docker解析问题还是客户端缓存问题。可以通过在容器内多次运行nslookup确认Docker域名解析是否已经更新。

Docker DNS服务发现容器网络修改时间:2026-08-23 10:13:41

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。