在开发过程中,我们使用 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: yaml
namespace: ${NACOS_NAMESPACE}
shared-configs:
- data-id: shared-mysql.yaml
group: DEFAULT_GROUP
refresh: false
其中,shared-mysql.yaml
是存储数据库连接信息的配置文件,Spring Boot 项目会从 Nacos 中读取该文件并解析为 MySQL 配置。
shared-mysql.yaml
文件内容如下:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql:3306/db
username: root
password: xxxx
hikari:
max-lifetime: 30000
maximum-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 failure
The 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.Driver
url: jdbc:mysql://mysql:3306/db
username: root
password: xxxx
hikari:
max-lifetime: 30000
maximum-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.Driver
url: jdbc:mysql://<服务器公网IP>:3306/db
username: root
password: xxxx
hikari:
max-lifetime: 30000
maximum-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 配置的理解偏差,导致了数据库连接地址的配置错误。
希望这篇文章能够帮助大家避免类似的配置误区,快速定位并解决类似问题。如果你有其他问题,欢迎留言讨论!