繁体   English   中英

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

[英]Unable to acquire JDBC Connection on integration test when using Docker bridge network

当我在本地运行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

当运行本地测试时,它们全部通过,使用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

URL中的MySQL是MySQL docker容器名称。 如果在docker container inspect mysql使用localhost或私有IP更改它,则docker container inspect mysql的错误消息是相同的,而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)

对于私人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数据库使用大写。 运行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容器连接到同一个桥接网络。

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

这在下面的主题中有很好的解释。

值得尝试...
如何连接在docker中作为容器运行的MySQL DB?

感谢@ rohit-thomas 我们将问题缩小到与URL主机相关的问题。
简单的答案是将spring boot application.properties中的JDBC URL主机更改为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
       ...

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

如果结论错误,欢迎提出意见。

您可以检查的一些内容可能有助于您解决此问题。

  • 在application.properties中尝试使用docker主机IP地址。

     spring.datasource.url = jdbc:mysql://mysql:3306/DATABASE_URI_PATH 

     spring.datasource.url = jdbc:mysql://192.168.99.100:33060/DATABASE_URI_PATH 

    注意:在docker run或docker文件中的端口时,您需要映射IP和端口。并在容器中使用相同的docker网络。

  • 验证服务器应用程序是否可以访问您的mysql,反之亦然。 进入docker容器并尝试ping。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM