Docker 容器名下劃線導(dǎo)致 Nacos 注冊 400 錯(cuò)誤排查實(shí)錄

一個(gè)小小的下劃線,讓我排查了一個(gè)多小時(shí)。希望這篇文章能幫助遇到類似問題的開發(fā)者少走彎路。

背景

我們的微服務(wù)架構(gòu)分為兩個(gè) Docker Compose 項(xiàng)目:

  • 基礎(chǔ)設(shè)施層:Nacos、Redis、RabbitMQ 等中間件
  • 應(yīng)用服務(wù)層:Gateway、Auth、Order 等業(yè)務(wù)服務(wù)

兩個(gè)項(xiàng)目通過同一個(gè) Docker 外部網(wǎng)絡(luò)進(jìn)行通信:

networks:
  edniutrans_dl:
    external: true
    name: edniutrans_dl

問題現(xiàn)象

應(yīng)用服務(wù)啟動(dòng)時(shí),向 Nacos 注冊失敗,報(bào) HTTP 400 Bad Request 錯(cuò)誤:

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 控制臺(tái)可以正常訪問
  • Nacos 日志沒有任何報(bào)錯(cuò)
  • 從應(yīng)用容器可以 ping 通 nacos_dl

排查過程

1. 確認(rèn) Nacos 服務(wù)正常

從 Nacos 容器內(nèi)部測試服務(wù)注冊,成功:

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"
# 結(jié)果:成功 ?

2. 從應(yīng)用容器測試,失敗

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"
# 結(jié)果: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"
# 結(jié)果:成功 ?

關(guān)鍵發(fā)現(xiàn):用 IP 地址能成功,用主機(jī)名失?。?/p>

4. 查看詳細(xì)請求信息

使用 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 包含下劃線 _!


根本原因

根據(jù) RFC 952RFC 1123 規(guī)范,合法的主機(jī)名(hostname)只能包含:

  • 字母 a-zA-Z
  • 數(shù)字 0-9
  • 連字符 -(不能在開頭或結(jié)尾)

下劃線 _ 是不允許出現(xiàn)在主機(jī)名中的!

雖然 Linux 系統(tǒng)和 Docker DNS 對此比較寬容(能解析),但 Nacos 內(nèi)嵌的 Tomcat 服務(wù)器嚴(yán)格遵循 HTTP 規(guī)范,當(dāng)檢測到 Host 頭包含非法字符時(shí),直接返回 400 Bad Request。

這就解釋了為什么:

  • ? 用 IP 地址訪問成功(Host 頭是 IP,沒有非法字符)
  • ? 用 nacos_dl 訪問失?。℉ost 頭包含下劃線)
  • ? 從容器內(nèi)部用 127.0.0.1 訪問成功(Host 頭是 127.0.0.1)

解決方案

將容器名/服務(wù)名中的下劃線去掉或替換為連字符:

# ? 錯(cuò)誤示例
services:
  nacos_dl:
    image: nacos/nacos-server:2.0.3
    # ...

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

同時(shí)更新所有引用該服務(wù)的配置:

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

重啟服務(wù)后,問題解決!


命名規(guī)范建議

? 避免 ? 推薦
nacos_dl nacosdlnacos-dl
redis_master redis-masterredismaster
mq_server mq-servermqserver
my_service my-servicemyservice

受影響的場景

以下場景可能因主機(jī)名包含下劃線而出問題:

場景 表現(xiàn)
Nacos / Consul / Eureka 服務(wù)注冊返回 400
Nginx 反向代理 默認(rèn)拒絕帶下劃線的 Host
Tomcat 應(yīng)用 返回 400 Bad Request
SSL/TLS 證書 無法簽發(fā)證書
某些 DNS 服務(wù)器 解析失敗

為什么這個(gè)問題難以發(fā)現(xiàn)?

  1. DNS 能正常解析 - ping nacos_dl 成功,讓人以為網(wǎng)絡(luò)沒問題
  2. 錯(cuò)誤信息不明確 - Nacos 只返回 400 Bad Request,沒有具體原因
  3. Nacos 日志無報(bào)錯(cuò) - 服務(wù)端日志看不到任何異常
  4. 本地測試能通過 - 從 Nacos 容器內(nèi)部用 127.0.0.1 測試是成功的

總結(jié)

這個(gè)問題的排查過程告訴我們:

  1. 遵循標(biāo)準(zhǔn)很重要 - HTTP 規(guī)范雖然枯燥,但關(guān)鍵時(shí)刻能幫你定位問題
  2. 對比測試是利器 - 用 IP 和 hostname 分別測試,快速縮小問題范圍
  3. 善用 curl -v - 查看完整的 HTTP 請求響應(yīng),發(fā)現(xiàn)隱藏的問題

最重要的一點(diǎn):在 Docker 容器命名、域名、主機(jī)名中,永遠(yuǎn)不要使用下劃線!用連字符 - 代替。


如果這篇文章幫你避開了這個(gè)坑,歡迎點(diǎn)贊分享~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容