无法将 spring-boot 2 服务连接到不同容器中的 mysql

Posted

技术标签:

【中文标题】无法将 spring-boot 2 服务连接到不同容器中的 mysql【英文标题】:Can't connect a spring-boot 2 service to mysql in a different container 【发布时间】:2019-11-10 10:41:45 【问题描述】:

我有一个连接到 my-sql 数据库的 spring-boot 2.16 服务。只要所有组件都在同一主机上,它就可以按预期工作。我试图改进解决方案,并让一个 docker 容器运行嵌入 Tomcat 的 sprin-boot 服务和另一个运行 my-sql 服务器的 docker 容器。 相同的代码不再起作用。这是一个例外:

 2019-06-28 12:23:48 ERROR com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Exception during pool initialization.
 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.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at  sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:988)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:341)
....
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:211)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:300)
... 66 common frames omitted

所以,就像找不到mysql服务器IP地址或者服务器没有运行等。 这是 docker-compse.yml 文件:

version: "2"
services:
  rdf-data:
    container_name: rdf-data
    image: mysql:latest
    environment:
      MYSQL_DATABASE: test
      MYSQL_USER: nicolas
      MYSQL_PASSWORD: mysql
      MYSQL_ROOT_PASSWORD: mysql
    ports:
      - 3306:3306
      - 33060:33060
    hostname: rdf-data
    networks:
      net1:
        ipv4_address: 192.19.0.4
  rdf-core:
    image: openjdk:8-jdk-alpine
    depends_on:
      - rdf-data
    container_name: rdf-core
    links:
      - rdf-data:rdf-data
    volumes:
      - ../docker:/usr/local/share/rdf
    ports:
      - "8080:8080"
    entrypoint: /usr/local/share/rdf/run.sh
    hostname: rdf-core
    environment:
      PROFILE: "default"
      SERVER_PORT: "8080"
  networks:
    net1:
      ipv4_address: 192.19.0.8
networks:
  net1:
    driver: bridge
    driver_opts:
      com.docker.network.enable_ipv6: "false"
  ipam:
    driver: default
    config:
      - subnet: 192.19.0.0/24
        gateway: 192.19.0.1

这里有两个容器:rfd-core 的 IP 地址为 192.19.0.8 和 rdf-data 的 IP 地址为 192.19.0.4。每个容器都能够 ping 另一个。 hst 机器能够 ping 每个容器。从主机我能够使用 my-sql 命令行客户端正确连接到在 rfd-data 上运行的 my-sql 服务器。 但是,下面显示的我的服务连接不起作用:

database=mysql
spring.datasource.url=jdbc:mysql://192.19.0.4/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=mysql
spring.datasource.driver-class=com.mysql.cj.jdbc.MysqlXADataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.hikari.connectionTimeout=30000
spring.datasource.hikari.idleTimeout=600000
spring.datasource.hikari.maxLifetime=1800000
...

我有什么遗漏的吗?

【问题讨论】:

mysqld --verbose --help | grep bind-address 检查绑定地址 由于您的服务共享同一个网络,为什么不使用 docker 提供的服务发现功能。因此,您可以使用服务名称,而不是手动设置 IP 地址。 @akuma8 :无关,但无论如何感谢您的时间。 @Ntwobike:发帖前已经检查过了。 【参考方案1】:

尝试在docker-compose文件的环境部分指定spring boot app的参数:

 rdf-core:
    image: openjdk:8-jdk-alpine
    depends_on:
      - rdf-data
    container_name: rdf-core
        links:
          - rdf-data:rdf-data
        volumes:
          - ../docker:/usr/local/share/rdf
        ports:
          - "8080:8080"
        entrypoint: /usr/local/share/rdf/run.sh
        hostname: rdf-core
        environment:
          PROFILE: "default"
          SERVER_PORT: "8080"
          spring.datasource.url=jdbc:mysql://ipaddress/test?useSSL=false
          spring.datasource.username=root
          spring.datasource.password=mysql
          spring.datasource.driver-class=com.mysql.cj.jdbc.MysqlXADataSource
          spring.datasource.driver-class-name=com.mysql.jdbc.Driver
          spring.datasource.hikari.connectionTimeout=30000
          spring.datasource.hikari.idleTimeout=600000
          spring.datasource.hikari.maxLifetime=1800000

问题的另一个可能原因:depends_on 不保证依赖容器完全运行。所以如果 MySQL 容器比 Spring Boot 容器需要更多的时间来完全启动,连接就会失败。

看看这个:

Spring Boot + docker-compose + MySQL: Connection refused

有几种可能的方法可以让一个容器等待另一个容器: 使用restart on failure 功能,或docker compose wait ( Github link)

【讨论】:

有趣。如果参数以不同的方式传递,您认为有什么特别的原因会更好吗?但我会尽力而为。 我在使用 docker-compose 启动不同的容器时遇到了类似的问题。在尝试确定问题时,我发现使用 docker compose 启动所有内容并使用 mvn spring-boot:run 启动 Spring Boot 应用程序时,它工作正常,因此读取/查找容器内的 Spring Boot 配置可能存在问题,并将它们传递到 docker-compose 文件的环境部分解决了这个问题。这可能会有所帮助***.com/questions/46057625/… 我正在用上次测试的结果更新案例。我的问题是由于使用 Spring Boot 2.1.6.RELEASE 和 mysql:latest 映像附带的 MySQL JDBC 驱动程序而产生的。它们不兼容。改用 mysql:5.7 图像解决了这个问题。非常感谢大家的帮助和支持。

以上是关于无法将 spring-boot 2 服务连接到不同容器中的 mysql的主要内容,如果未能解决你的问题,请参考以下文章

使用 spring-boot 连接到 spring-batch 和应用程序数据库

带有代理的 WCF 服务无法连接到 EntityFramework

Zuul 网关无法连接到 Docker-Compose 下的 Eureka 服务注册表

Spring Boot 无法连接到 MySQL:无法识别服务器时区值“Mitteleuropäische Zeit”

如何在 Spring-boot 上启用 TLS 1.2?

Docker 容器无法连接到 Redis