Docker 容器名下划线导致 Nacos 注册 400 错误排查实录

一个小小的下划线,让我排查了一个多小时。希望这篇文章能帮助遇到类似问题的开发者少走弯路。

背景

我们的微服务架构分为两个 Docker Compose 项目:

  • 基础设施层:Nacos、Redis、RabbitMQ 等中间件
  • 应用服务层:Gateway、Auth、Order 等业务服务

两个项目通过同一个 Docker 外部网络进行通信:

networks:
  edniutrans_dl:
    external: true
    name: edniutrans_dl

问题现象

应用服务启动时,向 Nacos 注册失败,报 HTTP 400 Bad Request 错误:

NacosException: failed to req API:/nacos/v1/ns/instance 
after all servers([nacos_dl:8848]) tried: 
ErrCode:400, ErrMsg: HTTP Status 400 – Bad Request

奇怪的是:

  • Nacos 控制台可以正常访问
  • Nacos 日志没有任何报错
  • 从应用容器可以 ping 通 nacos_dl

排查过程

1. 确认 Nacos 服务正常

从 Nacos 容器内部测试服务注册,成功:

docker exec -it nacos_dl curl -X POST \
  "http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=test&ip=127.0.0.1&port=8080"
# 结果:成功 ✅

2. 从应用容器测试,失败

docker exec -it app-container curl -X POST \
  "http://nacos_dl:8848/nacos/v1/ns/instance?serviceName=test&ip=172.22.0.3&port=8080"
# 结果:400 Bad Request ❌

3. 换成 IP 地址测试,成功

docker exec -it app-container curl -X POST \
  "http://172.22.0.8:8848/nacos/v1/ns/instance?serviceName=test&ip=172.22.0.3&port=8080"
# 结果:成功 ✅

关键发现:用 IP 地址能成功,用主机名失败!

4. 查看详细请求信息

使用 curl -v 查看完整的 HTTP 请求:

docker exec -it app-container curl -v \
  "http://nacos_dl:8848/nacos/v1/ns/instance/list?serviceName=test"

输出:

> GET /nacos/v1/ns/instance/list?serviceName=test HTTP/1.1
> Host: nacos_dl:8848
> User-Agent: curl/7.60.0
> Accept: */*
>
< HTTP/1.1 400

问题锁定:Host 请求头是 nacos_dl:8848,其中 nacos_dl 包含下划线 _


根本原因

根据 RFC 952RFC 1123 规范,合法的主机名(hostname)只能包含:

  • 字母 a-zA-Z
  • 数字 0-9
  • 连字符 -(不能在开头或结尾)

下划线 _ 是不允许出现在主机名中的!

虽然 Linux 系统和 Docker DNS 对此比较宽容(能解析),但 Nacos 内嵌的 Tomcat 服务器严格遵循 HTTP 规范,当检测到 Host 头包含非法字符时,直接返回 400 Bad Request。

这就解释了为什么:

  • ✅ 用 IP 地址访问成功(Host 头是 IP,没有非法字符)
  • ❌ 用 nacos_dl 访问失败(Host 头包含下划线)
  • ✅ 从容器内部用 127.0.0.1 访问成功(Host 头是 127.0.0.1)

解决方案

将容器名/服务名中的下划线去掉或替换为连字符:

# ❌ 错误示例
services:
  nacos_dl:
    image: nacos/nacos-server:2.0.3
    # ...

# ✅ 正确示例
services:
  nacosdl:  # 或者 nacos-dl
    image: nacos/nacos-server:2.0.3
    # ...

同时更新所有引用该服务的配置:

environment:
  spring.cloud.nacos.config.server-addr: nacosdl:8848
  spring.cloud.nacos.discovery.server-addr: nacosdl:8848

重启服务后,问题解决!


命名规范建议

❌ 避免 ✅ 推荐
nacos_dl nacosdlnacos-dl
redis_master redis-masterredismaster
mq_server mq-servermqserver
my_service my-servicemyservice

受影响的场景

以下场景可能因主机名包含下划线而出问题:

场景 表现
Nacos / Consul / Eureka 服务注册返回 400
Nginx 反向代理 默认拒绝带下划线的 Host
Tomcat 应用 返回 400 Bad Request
SSL/TLS 证书 无法签发证书
某些 DNS 服务器 解析失败

为什么这个问题难以发现?

  1. DNS 能正常解析 - ping nacos_dl 成功,让人以为网络没问题
  2. 错误信息不明确 - Nacos 只返回 400 Bad Request,没有具体原因
  3. Nacos 日志无报错 - 服务端日志看不到任何异常
  4. 本地测试能通过 - 从 Nacos 容器内部用 127.0.0.1 测试是成功的

总结

这个问题的排查过程告诉我们:

  1. 遵循标准很重要 - HTTP 规范虽然枯燥,但关键时刻能帮你定位问题
  2. 对比测试是利器 - 用 IP 和 hostname 分别测试,快速缩小问题范围
  3. 善用 curl -v - 查看完整的 HTTP 请求响应,发现隐藏的问题

最重要的一点:在 Docker 容器命名、域名、主机名中,永远不要使用下划线!用连字符 - 代替。


如果这篇文章帮你避开了这个坑,欢迎点赞分享~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容