使用 Docker 网桥网络时,无法在集成测试中获取 JDBC 连接

2022-09-04 04:22:32

当我在本地运行时已通过。但是当我在CI服务器上运行它时得到了这个错误。maven test

Error Message
Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
Stacktrace
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
Caused by: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
Caused by: com.mysql.jdbc.exceptions.jdbc4.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.
Caused by: java.net.UnknownHostException: mysql

运行本地测试时,它们都通过了,使用IntelliJ IDEA提供的maven测试默认设置。
由于错误抱怨数据库连接,所以我通过Jenkins Audit到数据库插件进行了检查。连接成功!

enter image description here

my 中的连接参数也与此相对应application.properties

spring.datasource.url=jdbc:mysql://mysql:3306/database?useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.maxActive=5

URL 中的 MySQL 是 MySQL docker 容器名称。如果用或私有IP更改它,错误消息是相同的,而Stacktrace在最后两行上略有不同。localhostdocker container inspect mysql

对于本地主机

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
Caused by: java.net.ConnectException: Connection refused (Connection refused)

用于私有 IP

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. 
Caused by: java.net.SocketTimeoutException: connect timed out

我认为不同的是URL中的主机,localhost用于本地测试。而 Jenkins 服务器使用 Docker 网桥网络。

容器状态为:

docker container ls
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS
                                          NAMES
51ea7c7864a4        mysql:5.7             "docker-entrypoint.s…"   19 hours ago        Up 19 hours         0.0.0.0:3306->3306/tcp                             mysql
de364f7b5eaf        maven:3-jdk-8         "/usr/local/bin/mvn-…"   21 hours ago        Up 21 hours
                                          optimistic_stallman
a6545591e358        jenkinsci/blueocean   "/sbin/tini -- /usr/…"   43 hours ago        Up 43 hours         0.0.0.0:50000->50000/tcp, 0.0.0.0:2048->8080/tcp   frosty_cray

当我在IntelliJ中运行JUnit测试时,它有时会在本地环境中失败。错误日志如下所示:

Caused by: org.h2.jdbc.JdbcSQLException: Schema "DATABASE" not found; SQL statement:
TRUNCATE TABLE database.data_log 

我已经搜索了这个问题,它说h2数据库默认使用大写。运行后,如果再次在IDE中运行JUnit测试,则会出现此问题。但这不应该与根本原因有关。maven test

搜索错误消息,找到一些类似的问题,但具有不同的嵌套异常:

无法打开 JPA 实体管理器进行交易;嵌套异常是 javax.persistence.PersistenceException

SpingREST:无法打开 JPA EntityManager 进行交易;嵌套异常是 org.hiberna

无法打开 JPA 实体管理器进行交易;org.hibernate.exception.GenericJDBCException: 無法開啟連結

无法在春季打开 JPA 实体管理器进行交易

所有这些都是关于
但我的情况。阅读将Java连接到MySQL数据库
,但是由于该插件连接正常,这意味着从Jenkins容器到MySQL容器的连接很好。nested exception is javax.persistence.PersistenceExceptionnested exception is org.hibernate.exception.JDBCConnectionException:

总结:
1.本地测试与专家通过
2.Jenkins 插件连接到 MySQL 成功
3.从 Jenkins
4 运行时,集成测试失败。本地测试环境为WIN10 64位;Jenkins在Ubuntu 16.04 64bit服务器上的docker容器中运行,MySQL 5.7容器连接到同一桥接网络。


答案 1

您应该将 docker 容器 mysql 端口绑定到 VM 中的端口。

这在下面的线程中得到了很好的解释。

值得尝试...
如何在 Docker 中连接作为容器运行的 MySQL 数据库?


答案 2

感谢@rohit-托马斯。我们将问题范围缩小到与 URL 主机相关的内容。
简单的答案是将春季引导中 JDBC URL 的主机更改为 docker 主机 IP 地址。从

application.propertiesspring.datasource.url=jdbc:mysql://mysql:3306/database?
spring.datasource.url=jdbc:mysql://172.17.0.1:3306/database?

如何从 Docker 容器内部连接到计算机的本地主机?
这篇文章也有助于作为最终的解决方案。

ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default        
    ...   
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       ...

我的结论是:
Jenkins容器从映像构建,能够使用其容器名称或docker桥接网络上的专用地址与MySQL容器进行通信。但是,由于 Jenkins 构建的应用程序无法做到这一点。由于MySQL容器端口已绑定到主机,因此应用程序可以通过主机端口与MySQL容器进行通信。

如果结论是错误的,欢迎评论。


推荐