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

12

我正在尝试设置一个依赖于 Docker Compose 中名为 teste 的 MySQL 数据库的 Spring Boot 应用程序。在执行 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

注:该文件为Docker Compose的配置文件,用于定义和运行多个容器的服务。
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"]
3个回答

6

我面临同样的问题,如果您不想使用任何自定义脚本,可以使用健康检查和 depends on 轻松解决这个问题。以下是一个使用它们的示例:

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

5
Docker compose总是按依赖顺序或文件中的顺序依次启动和停止容器,但docker-compose不能保证它会等待依赖容器运行。您可以在此处参考了解更多详细信息。因此,问题在于当您的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"]

在这里需要考虑的另外两个重要事项是:

  • 不要使用链接,它们已经过时,你应该使用用户定义的网络代替。如果您没有明确定义任何网络,则docker-compose文件中的所有服务都将在单个用户定义的网络中。因此,您只需从组合文件中删除链接即可。
  • 如果您仅在用户定义的网络内部使用docker容器,则无需发布端口。

1
非常感谢您的答案,它帮助我让我的docker-compose工作起来了。然而,由于wait-for-it.sh中默认的15秒超时时间不够,我浪费了很多时间尝试但没有成功,所以我不得不增加这个超时时间。如果我知道这个超时时间可以更改,我就不会浪费那么多时间了。您能否更新您的答案,告诉用户默认超时时间可以更改呢? - Moussa
好的,至少,@Moussa,我已经阅读了您的评论并立即增加了超时间隔 :) - pzelenovic
谢谢!我已经尝试了几个小时。在Docker Compose Up日志中,MySQL始终在应用启动之前启动,因此我认为MySQL已经完全启动,但是我仍然得到了连接被拒绝的错误!只有使用这个脚本我才能让它运行!顺便说一句,在您的主机上将.sh脚本的权限更改为777,否则您将遇到权限错误。 - ACV

1
你的配置看起来不错,我只是建议:
  • 删除 links: db。在用户自定义桥接网络中没有价值
  • 除非你想从docker-compose外部连接,否则删除对db的端口暴露 - 所有端口都会在用户自定义桥接网络内自动暴露。

我认为问题在于数据库容器启动需要比Web容器更长的时间。 depends_on 只控制顺序,但不能保证数据库已准备就绪。如果可能的话,请设置多个连接尝试或在 Web 容器中添加 socket-wait 过程。


这确实听起来像是mysql容器尚未完全启动的问题。您可以查看https://github.com/jwilder/dockerize进行等待。您需要将此应用程序添加到镜像中,然后在启动Java应用程序之前等待。 - Gerben Jongerius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接