gRPC Java 报 Invalid DNS name,检查短主机名的最后一段
gRPC Java 1.84.0 使用 java.net.URI 校验地址,末段以数字开头的短 DNS 名可能在解析前被拒绝。确认实际服务的完整 DNS 名、证书标识与通道 authority,不能用固定 IP 绕过后就丢掉解析和安全约定。
Kubernetes 中的服务短名可以被 DNS 搜到,gRPC Java 却在创建通道时直接抛异常。例如目标是 otlp.1234-k8s-namespace:4317,可能出现:
IllegalArgumentException: Invalid host or port
IllegalArgumentException: Invalid DNS name
这条问题有 grpc-netty-shaded 1.84.0、JDK 11/17/21 的明确组合。要先区分“还没有接受目标字符串”与“已经发送 DNS 查询但没有找到地址”,不能一开始就调整 DNS 超时或服务网络策略。
短名的最后一个 label 触发 URI 校验
gRPC Java 构造 authority 及 DNS resolver 时使用 java.net.URI。后一条路径先为名称加上 //,再要求 getHost() 不能为 null。受这里采用的 URI 主机名规则影响,最后一段以数字开头的相对 DNS 名可能无法通过。
otlp.1234-k8s-namespace 的最后一段就是 1234-k8s-namespace。操作系统解析器能接受并补搜索域,不代表 URI 校验也接受该字符串。只加 dns:/// 仍会进入同一个 DNS resolver,不能修正里面的主机名判定。
当前正式 1.85.1 的 GrpcUtil 和 DnsNameResolver 仍采用相关 URI 入口。因此不要把升级到任意较新版本当作这条短名限制已经消失,也不要把它泛化成所有包含数字的域名都无效。数字出现在其他 label,或完整名字最后一段是正常字母标签时,条件不同。
已有完整服务名时,直接配置真实全名
如果应用运行在能解析 Kubernetes Service DNS 的环境中,可以核对实际的完整服务名。默认集群域下的形状是 服务名.命名空间.svc.cluster.local;集群域可以被管理员改成其他值,不能把示例后缀当成所有环境的事实。
例如,确认服务确实存在、完整名称可以解析,并且 TLS 证书覆盖这个名称后,可把目标配置为:
ManagedChannel channel = ManagedChannelBuilder
.forTarget("dns:///otlp.1234-k8s-namespace.svc.cluster.local:4317")
.useTransportSecurity()
.build();
这段需要 io.grpc.ManagedChannel 与 io.grpc.ManagedChannelBuilder,并由项目原来的 transport provider 提供实际连接能力。示例按已有 TLS 服务编写;现有服务的 TLS/明文方案按原约定保留。已有自定义 CA、mTLS、负载均衡或 channel 生命周期配置应继续保留,按应用正常关闭流程释放通道。
短名改全名之后,TLS 校验的目标也要一致。服务只为别的名称签发证书时,应使用组织已经批准、能正确解析且被证书覆盖的服务标识,或按原证书管理流程补齐名称;不要添加关闭校验的代码来掩盖新的身份不匹配。
固定 IP 不是同等替换
预先解析一次并把固定 SocketAddress 交给通道,可能避开这次名字解析入口,但也会改变后续再解析、服务地址更新和负载均衡行为。容器重建后地址变化,程序仍可能连旧地址;TLS authority 与目标 IP 也不能混为一谈。
类似地,手动覆盖 authority 不只是改日志里的一段文字,它可能影响 HTTP/2 authority 和服务端证书身份。只有完整理解并保留原服务身份契约时才可评估,不能作为所有 Invalid DNS name 的通用配置。
回查时先确认通道构造不再报原异常,再确认 DNS 返回预期服务地址、TLS 身份校验通过以及真实 RPC 正常。若依赖动态解析,还要按原服务变更流程核对地址刷新;第一次连接成功不足以证明之后仍跟随服务端点变化。


