Spring Boot + docker-compose + MySQL:连接被拒绝

Posted

技术标签:

【中文标题】Spring Boot + docker-compose + MySQL:连接被拒绝【英文标题】:Spring Boot + docker-compose + MySQL: Connection refused 【发布时间】:2019-06-06 07:10:30 【问题描述】:

我正在尝试设置一个 Spring Boot 应用程序,该应用程序依赖于 docker-compose 中名为 testemysql 数据库。发出docker-compose up 后,我得到:

Caused by: java.net.ConnectException: Connection refused (Connection refused)

我在 Linux Mint 上运行,我的 docker-compose 版本是 1.23.2,我的 Docker 版本是 18.09.0。

application.properties

# JPA PROPS
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy

spring.datasource.url=jdbc:mysql://db:3306/teste?useSSL=false&serverTimezone=UTC
spring.datasource.username=rafael
spring.datasource.password=password

spring.database.driverClassName =com.mysql.cj.jdbc.Driver

docker-compose.yml

version: '3.5'
services:
  db:
    image: mysql:latest
    environment:
      - MYSQL_ROOT_PASSWORD=rootpass
      - MYSQL_DATABASE=teste      
      - MYSQL_USER=rafael
      - MYSQL_PASSWORD=password
    ports:
      - 3306:3306
  web:
    image: spring-mysql
    depends_on:
      - db
    links:
      - db
    ports:
      - 8080:8080
    environment:
      - DATABASE_HOST=db
      - DATABASE_USER=rafael
      - DATABASE_NAME=teste
      - DATABASE_PORT=3306

和 Dockerfile

FROM openjdk:8
ADD target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

【问题讨论】:

【参考方案1】:

Docker compose 总是按依赖顺序启动和停止容器,如果没有给出,则在文件中按顺序启动和停止容器。但是 docker-compose 不保证它会等到依赖容器运行。您可以在此处refer 了解更多详情。所以这里的问题是当您的spring-mysql 容器尝试访问数据库时,您的数据库还没有准备好。因此,推荐的解决方案是您可以使用wait-for-it.sh 或类似的脚本来包装您的spring-mysql 应用程序,从ENTRYPOINT 开始。

例如,如果您使用wait-for-it.sh,则您的 Dockerfile 中的ENTRYPOINT 应在将上述脚本复制到项目根目录后更改为以下内容:

ENTRYPOINT ["./wait-for-it.sh", "db:3306", "--", "java", "-jar", "app.jar"]

这里要考虑的另外两个重要的事情是:

不要使用它们是deprecated的链接,你应该使用用户定义的网络。如果您没有明确定义任何网络,则 docker-compose 文件中的所有服务都将位于单个用户定义的网络中。因此,您只需从撰写文件中删除链接。 如果只在用户定义的网络中使用,则不需要发布 docker 容器的端口。

【讨论】:

非常感谢这个帮助我完成 docker-compose 工作的答案。但是我已经浪费了很多时间尝试这个但没有成功,因为wait-for-it.sh 中的默认超时时间为 15 秒是不够的,所以我不得不增加它。如果我知道可以更改此超时,我不会浪费那么多时间,您能否更新您的答案以告诉用户可以更改默认超时。 至少,@Moussa,我已经阅读了您的评论并立即增加了超时间隔:) 谢谢!我已经尝试了几个小时。在 docker compose up 日志中,它总是在应用程序启动之前显示 Mysql Started,所以我假设 mysql 完全启动,但我仍然被拒绝连接!只有使用这个脚本,我才能让它运行!顺便说一句,您的主机上将该 .sh 脚本的权限更改为 777 否则您将收到权限错误。【参考方案2】:

你的配置看起来不错,我只推荐:

删除links: db。在user-defined bridge 网络中没有任何价值 删除为 db 公开的端口,除非您想从外部 docker-compose 连接 - 所有端口都在 user-defined bridge 网络内自动公开。

我认为问题在于数据库容器的启动时间比 Web 容器要多。 depends_on 只是控制顺序,但不保证您的数据库准备就绪。如果可能,设置多次连接尝试或将套接字等待过程放入您的 Web 容器中。

【讨论】:

这听起来确实像是 mysql 容器尚未完全启动的问题。您可以查看github.com/jwilder/dockerize 等待。您必须将此应用程序添加到图像中,然后在启动 java 应用程序之前等待。【参考方案3】:

我遇到了同样的问题,如果您不想使用任何自定义脚本,可以使用运行状况检查和依赖项轻松解决。使用这些的示例如下:

services:
  mysql-db:
    image: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=vikas1234
      - MYSQL_USER=vikas
    ports:
      - 3306:3306
    restart: always
    healthcheck:
      test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
      timeout: 20s
      retries: 10

  app:
    image: shop-keeper
    container_name: shop-keeper-app
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 8080:8080
    depends_on:
      mysql-db:
        condition: service_healthy
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql-db:3306/shopkeeper?createDatabaseIfNotExist=true
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: vikas1234

【讨论】:

以上是关于Spring Boot + docker-compose + MySQL:连接被拒绝的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Spring Boot 应用程序 pom 同时需要 spring-boot-starter-parent 和 spring-boot-starter-web?

《02.Spring Boot连载:Spring Boot实战.Spring Boot核心原理剖析》

spring-boot-quartz, 依赖spring-boot-parent

spring-boot系列:初试spring-boot

Spring Boot:Spring Boot启动原理分析

Spring Boot:Spring Boot启动原理分析