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

Shi*_*ang 12 java mysql spring jenkins docker

当我在maven test本地运行时通过.但是当我在CI服务器上运行它时出现此错误.

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
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

我的连接参数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
Run Code Online (Sandbox Code Playgroud)

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

对于localhost

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)
Run Code Online (Sandbox Code Playgroud)

对于私人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
Run Code Online (Sandbox Code Playgroud)

我认为不同的是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
Run Code Online (Sandbox Code Playgroud)

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

Caused by: org.h2.jdbc.JdbcSQLException: Schema "DATABASE" not found; SQL statement:
TRUNCATE TABLE database.data_log 
Run Code Online (Sandbox Code Playgroud)

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

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

无法打开JPA EntityManager进行交易; 嵌套异常是javax.persistence.PersistenceException

SpingREST:无法打开JPA EntityManager进行事务处理; 嵌套异常是org.hiberna

无法打开JPA EntityManager进行交易; org.hibernate.exception.GenericJDBCException:无法打开连接

无法在spring中打开JPA EntityManager进行事务处理

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

总结:
1.本地测试用maven传递
2. Jenkins插件连接到MySQL成功
3.集成测试失败从Jenkins运行
4.本地测试环境是WIN10 64bit; Jenkins在Ubuntu 16.04 64位服务器上的docker容器中运行,MySQL 5.7容器连接到同一个桥接网络.

Shi*_*ang 2

感谢@rohit-thomas。我们将问题缩小到与 URL 主机相关的问题。
简单的答案是将 Spring Boot 中的 JDBC URL 的主机更改application.properties为 docker 主机 IP 地址。从
spring.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
       ...
Run Code Online (Sandbox Code Playgroud)

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

如果结论有误,欢迎批评指正。


归档时间:

查看次数:

3017 次

最近记录:

7 年,1 月 前