Quarkus应用外部地址DNS查询返回回环地址问题排查
1. Java默认DNS缓存导致的陈旧结果
Java会默认缓存DNS解析结果,正缓存默认永久有效,负缓存默认10秒。如果Quarkus应用启动时,无头服务还未完成Pod IP绑定,Java可能缓存了初始的错误解析结果(比如回环地址),后续即使底层系统DNS已经更新,也不会主动重新解析。
可以通过JVM启动参数调整缓存策略:
networkaddress.cache.ttl:控制正缓存时长(单位秒,设为0表示不缓存)networkaddress.cache.negative.ttl:控制负缓存时长(单位秒)
示例启动参数:-Dnetworkaddress.cache.ttl=60 -Dnetworkaddress.cache.negative.ttl=0
2. JVM优先读取/etc/hosts而非系统DNS
Java解析主机名时,会优先读取容器内的/etc/hosts文件内容。如果Pod启动时,/etc/hosts被写入了my-headless-service 127.0.0.1的记录(比如镜像自带配置、初始化脚本添加),Java会直接使用这条记录,完全忽略Kubernetes DNS服务返回的正确IP。
可以进入Pod执行cat /etc/hosts检查是否存在该错误记录,若有则需要排查Pod的初始化逻辑或镜像配置。
3. Quarkus扩展或自定义配置修改了解析逻辑
部分Quarkus扩展(如网络相关、健康检查扩展)可能会覆盖默认的DNS解析行为,比如启用了本地DNS缓存、或注册了自定义的域名解析器。此外,application.properties中的相关配置也可能影响解析结果,比如quarkus.dns.cache.enabled等参数。
可以检查应用配置文件,或排查是否引入了可能修改网络解析的扩展,必要时禁用相关配置验证。
4. JVM未继承容器的DNS配置
容器的/etc/resolv.conf通常会配置Kubernetes DNS服务器地址,但JVM可能未使用该配置,而是采用了默认的DNS解析路径。可以通过在代码中打印以下系统属性,确认JVM使用的DNS提供者:
System.out.println(System.getProperty("sun.net.spi.nameservice.provider.1"));
若输出不是dns,sun,说明JVM使用了自定义的DNS提供者,需要调整配置让其使用系统DNS。
5. 负缓存导致解析失败后不再重试
如果应用启动初期尝试解析无头服务失败,Java会缓存这个“域名不存在”的负结果,在缓存时长内不会再次发起解析请求。此时即使后续Kubernetes DNS已返回正确IP,Java仍会沿用之前的错误结果(可能表现为回环地址或解析异常)。
通过设置networkaddress.cache.negative.ttl=0可以禁用负缓存,让JVM每次解析都重新查询DNS。
内容的提问来源于stack exchange,提问作者Herr Derb

