在開發過程中,我們使用 Nacos 來管理 Spring Boot 項目的配置,其中包括數據庫連接配置。然而,在實際操作中,由于一些概念的混淆,我們遇到了一些連接問題。本文將分享我的故障排查過程,幫助大家避免類似的錯誤。
問題背景
在我的項目中,使用了 Nacos 來管理 Spring Boot 配置。數據庫的連接信息(如 MySQL 配置)存儲在 Nacos 配置中心的 shared-mysql.yaml
文件中。原本以為是 Nacos 直接連接 MySQL 容器,但事實上,Spring Boot 項目從 Nacos 拉取配置后,最終是通過本機連接開發服務器上的 MySQL。由于在配置時產生了一些混淆,導致項目無法成功連接到 MySQL 數據庫。
1. 項目與 Nacos 配置的集成
我們使用 Nacos 來管理數據庫連接配置,具體配置如下:
spring:cloud:nacos:username: ${NACOS_USERNAME}password: ${NACOS_PASSWORD}server-addr: ${NACOS_ADDR}discovery:namespace: ${NACOS_NAMESPACE}config:file-extension: yamlnamespace: ${NACOS_NAMESPACE}shared-configs:- data-id: shared-mysql.yamlgroup: DEFAULT_GROUPrefresh: false
其中,shared-mysql.yaml
是存儲數據庫連接信息的配置文件,Spring Boot 項目會從 Nacos 中讀取該文件并解析為 MySQL 配置。
shared-mysql.yaml
文件內容如下:
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://mysql:3306/dbusername: rootpassword: xxxxhikari:max-lifetime: 30000maximum-pool-size: 10
這部分配置在容器化的環境中是可以工作的,mysql
是 Docker 容器的主機名,它會被解析為對應容器的 IP 地址。
2. 問題現象
啟動 Spring Boot 項目時并沒有出現問題,測試請求登錄接口報錯:
2025-05-07 20:20:18.740 INFO 33828 --- [nio-9091-exec-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2025-05-07 20:20:19.747 ERROR 33828 --- [nio-9091-exec-1] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization.com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failureThe last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174) ~[mysql-connector-j-8.0.32.jar:8.0.32]at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) ~[mysql-connector-j-8.0.32.jar:8.0.32]at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:824) ~[mysql-connector-j-8.0.32.jar:8.0.32]at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:444) ~[mysql-connector-j-8.0.32.jar:8.0.32]at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:237) ~[mysql-connector-j-8.0.32.jar:8.0.32]
進一步排查發現,問題的根源是 Spring Boot 項目無法連接到 MySQL 容器。錯誤信息中提到的 mysql:3306
主機名無法解析為正確的 MySQL 主機地址,導致數據庫連接失敗。
但是我就納悶了,我已經配置了容器的網絡,mysql跟nacos都處于同一個網絡內,所以我覺得連接信息寫容器名稱應該能夠連接上數據庫,但是,我發現有一點我混淆了。
3. 排查過程
3.1 確認 Nacos 配置是否正確
首先,我們檢查了 Nacos 配置是否正確注冊和讀取。通過以下配置,項目應該能夠從 Nacos 中獲取 shared-mysql.yaml
文件內容:
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://mysql:3306/dbusername: rootpassword: xxxxhikari:max-lifetime: 30000maximum-pool-size: 10
在這里,url
地址使用了容器名稱 mysql
作為主機名。然而,mysql
是在 Docker 容器內部使用的主機名,外部的 Spring Boot 項目并不能直接解析該主機名。因此,項目無法通過此地址連接到 MySQL。
3.2 理解問題的根本
經過分析,問題并不在于 Nacos 配置本身,而在于數據庫連接的主機地址錯誤。實際上,Spring Boot 項目需要通過宿主機的 IP 地址連接到 MySQL,而不是通過容器名稱 mysql
。我在url上直接寫容器名稱是以為直接在Nacos容器連接mysql容器,并且已經配置了他們在同一個網絡,但其實項目只是將配置讀取再從本機連接服務器的,所以url中的容器名稱需要更改為服務器IP公網地址。
3.3 解決方案:修改 MySQL 主機地址
為了解決這個問題,我們修改了 shared-mysql.yaml
配置中的 url
地址,將 mysql:3306
替換為開發服務器的 公網 IP 地址:
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://<服務器公網IP>:3306/dbusername: rootpassword: xxxxhikari:max-lifetime: 30000maximum-pool-size: 10
這樣,Spring Boot 項目就能夠通過宿主機的公網 IP 地址連接到 MySQL,問題得到了解決。
3.4 確認 Nacos 服務地址與權限
此外,我們還需要確認 Nacos 服務地址是否正確配置,以及是否可以正常訪問。可以使用以下命令進行驗證:
curl http://<NACOS_ADDR>:8848/nacos/v1/ns/catalogs
如果無法訪問 Nacos,可能是網絡問題或 Nacos 地址配置錯誤。
3.5 檢查 MySQL 容器的訪問權限
由于 MySQL 容器默認只允許本地連接,我們需要確保它允許外部訪問。可以通過以下命令設置 MySQL 允許外部主機連接:
docker exec -it mysql mysql -uroot -pxxxx
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
4. 完整解決方案
4.1 修改 Nacos 配置文件
將 shared-mysql.yaml
配置中的 url
地址從 mysql:3306
改為 公網IP:3306
,并將配置發布到 Nacos。
4.2 確保 Nacos 配置服務可用
檢查 Nacos 服務是否正常運行,確保 NACOS_ADDR
配置正確,能夠從項目中訪問到。
4.3 確保 MySQL 容器外部可訪問
通過以下命令確認 MySQL 容器允許外部連接:
docker exec -it mysql mysql -uroot -pxxxx
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
4.4 項目配置驗證
確認項目的 application.yml
配置正確,并確保 Spring Boot 項目能夠從 Nacos 獲取正確的 MySQL 配置信息。
4.5 網絡連接測試
驗證 Spring Boot 項目是否能正常連接到 MySQL,尤其是是否能成功解析 MySQL 主機地址。
5. 總結
通過調整 Nacos 配置文件中的 MySQL 主機地址,并確保 MySQL 容器允許外部訪問,最終解決了 Spring Boot 項目無法連接 MySQL 的問題。這個問題的根源是對容器網絡與 Nacos 配置的理解偏差,導致了數據庫連接地址的配置錯誤。
希望這篇文章能夠幫助大家避免類似的配置誤區,快速定位并解決類似問題。如果你有其他問題,歡迎留言討論!