【问题标题】:Spring Boot + MySQL + Docker Compose - Cannot make Spring Boot connect to MySQLSpring Boot + MySQL + Docker Compose - 无法使 Spring Boot 连接到 MySQL
【发布时间】:2020-07-12 15:56:09
【问题描述】:

我一直在尝试在后端(在 Spring Boot 上运行)容器和预构建的 MySQL 容器之间建立连接。但是,我无法连接。我的 docker compose 文件是:

version: '3.7'

services:

  test-mysql:
    image: mysql
    restart: always
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_DATABASE: testdb
      MYSQL_USER: test
      MYSQL_PASSWORD: test
      MYSQL_ROOT_PASSWORD: root

  backend:
    depends_on: 
      - test-mysql
    build: 
      context: backend
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    restart: always  

volumes:
  db_data: {}

我的应用程序属性:

spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.datasource.url=jdbc:mysql://test-mysql:3306/testdb?autoReconnect=true&failOverReadOnly=false&maxReconnects=10
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=test
spring.datasource.password=test

当我使用docker-compose up 时,Spring Boot 无法识别容器名称test-mysql。它抛出:java.net.UnknownHostException

当我将其更改为 IP 时,它说连接被拒绝。我一直在到处寻找,无法解决。我希望任何人都可以帮助我。谢谢!

【问题讨论】:

    标签: mysql spring spring-boot docker


    【解决方案1】:

    您必须在 composer 文件中提及后端 mysql 属性,如下所示,

    backend:
    depends_on: 
      - test-mysql
    build: 
      context: backend
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    restart: always
    environment:
            SPRING_DATASOURCE_URL: jdbc:mysql://test- 
               mysql:3306/testdbautoReconnect=true&failOverReadOnly=false&maxReconnects=10
            SPRING_DATASOURCE_USERNAME: test
            SPRING_DATASOURCE_PASSWORD: test
    links:
      - test-mysql:test-mysql
    

    如果这不起作用,请尝试创建一个通用 docker 网络并将其添加到您的作曲家文件中,如下所示,

    backend:
    depends_on: 
      - test-mysql
    build: 
      context: backend
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    restart: always
    environment:
            SPRING_DATASOURCE_URL: jdbc:mysql://test- 
               mysql:3306/testdbautoReconnect=true&failOverReadOnly=false&maxReconnects=10
            SPRING_DATASOURCE_USERNAME: test
            SPRING_DATASOURCE_PASSWORD: test
    networks:
          -common-network
    
    test-mysql:
    image: mysql
    restart: always
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_DATABASE: testdb
      MYSQL_USER: test
      MYSQL_PASSWORD: test
      MYSQL_ROOT_PASSWORD: root
    networks:
          -common-network
    
    #Docker Networks
    networks:
        common-network:
            driver: bridge
    
    #Volumes
    volumes:
        dbdata:
            driver: local
    

    【讨论】:

    • 您好,感谢您的回复。我仍然收到java.net.UnknownHostException
    • 另外,环境变量似乎没有覆盖 application.properties 变量。对此有任何想法吗?
    • 也尝试暴露mysql端口。 test-mysql: image: mysql restart: always ports: - "3306:3306" volumes: - db_data:/var/lib/mysql environment: MYSQL_DATABASE: testdb MYSQL_USER: test MYSQL_PASSWORD: test MYSQL_ROOT_PASSWORD: root
    • @Steven 如果这不起作用,您应该尝试像我的第二个示例一样设置网络。可能这就是问题所在。容器无法识别它们的主机。容器可以轻松地与常见的 docker 网络进行通信。
    • @Steven 在尝试第二个示例之前尝试添加链接。也更新了我的答案。链接:-test-mysql:test-mysql
    【解决方案2】:

    您可以定义一个公共网络,应用程序服务器和数据库都可以在该网络上连接。请检查下面我定义了公共网络的文件 (docker-compose.yml):backend

    # Docker Compose file Reference (https://docs.docker.com/compose/compose-file/)
    
    version: '3.7'
    
    # Define services
    services:
      # App backend service
      app-server:
        # Configuration for building the docker image for the backend service
        build:
          context: . # Use an image built from the specified dockerfile in the `springboot-app-server` directory.
          dockerfile: Dockerfile
        ports:
          - "8080:8080" # Forward the exposed port 4000 on the container to port 4000 on the host machine
        restart: always
        depends_on: 
          - db # This service depends on mysql. Start that first.
        environment: # Pass environment variables to the service
          SPRING_DATASOURCE_URL: jdbc:mysql://test-mysql:3306/testdb?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
          SPRING_DATASOURCE_USERNAME: test
          SPRING_DATASOURCE_PASSWORD: test
        networks: # Networks to join (Services on the same network can communicate with each other using their name)
          - backend
    
      # Database Service (Mysql)
      db:
        image: mysql:5.7
        ports:
          - "3306:3306"
        restart: always
        environment:
          MYSQL_DATABASE: testdb
          MYSQL_USER: test
          MYSQL_PASSWORD: test
          MYSQL_ROOT_PASSWORD: root
        volumes:
          - db-data:/var/lib/mysql
        networks:
          - backend  
    
    # Volumes
    volumes:
      db-data:
    
    # Networks to be created to facilitate communication between containers
    networks:
      backend: 
    

    我在 GitHub 上写了一篇博客和一个简单的 Spring Boot MySQL 应用程序,它讲述了如何使用 Docker Compose。请查收:http://softwaredevelopercentral.blogspot.com/2020/10/spring-boot-mysql-docker-compose-example.html

    【讨论】:

      【解决方案3】:

      如果你想在你的 spring 配置中使用这个 test-mysql

      spring.datasource.url=jdbc:mysql://test-mysql:3306/testdb?autoReconnect=true&failOverReadOnly=false&maxReconnects=10
      

      然后在服务test-mysql处添加主机名属性

      version: '3.7'
      
      services:
      
        test-mysql:
          image: mysql
          hostname: test-mysql
          ...
      

      【讨论】:

        【解决方案4】:

        我希望这已经解决了,但如果还没有,问题在于mysql docker容器启动滞后。

        另一个问题是您可能需要构建 jar 文件,然后将其复制到容器中。这是一个大问题,因为当您构建 jar 文件时,以 db 作为主机名的数据库不可用。因此,当您构建 jar 文件时,请跳过测试。 这是我创建的 bash 脚本,但您可以一个一个地运行命令:

        #!/bin/bash 
        cd storage-service
        rm -rf target/
        mvn clean compile package -Dmaven.test.skip=true
        cd ..
        
        docker-compose up
        

        如果您想在容器中初始化 db。该文件位于我有一个文件 database.env 的文件夹 env 中

        -- create the databases
        CREATE DATABASE IF NOT EXISTS model_storage;
        -- create the users for each database
        CREATE USER 'arsene'@'localhost' IDENTIFIED BY 'arsene';
        GRANT CREATE, ALTER, INDEX, LOCK TABLES, REFERENCES, UPDATE, DELETE, DROP, SELECT, INSERT ON `model_storage`.* TO 'arsene'@'localhost';
        
        FLUSH PRIVILEGES;
        

        后端服务 Dockerfile 如下所示:

        FROM adoptopenjdk/openjdk11
        COPY target/*.jar storage.jar
        ENV JAVA_OPTS=""
        ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /storage.jar" ]
        EXPOSE 8089
        

        数据库 env 文件如下所示:

        MYSQL_ROOT_PASSWORD=arsene
        MYSQL_DATABASE=model_storage
        MYSQL_USER=arsene
        MYSQL_PASSWORD=arsene
        
        DATABASE_HOST=model_storage
        DATABASE_USER=arsene
        DATABASE_PASSWORD=arsene
        DATABASE_NAME=model_storage
        DATABASE_PORT=3306
        

        如果您打算在图像中传递 JAVA_OPTS 环境。这些可以稍后使用,如下面的 docker-compose.yml 所示

        您的后端(依赖于 mysql db 的服务)需要重新启动,直到 docker-compose 能够解析 mysql 的容器名称,在我的例子中它的名称是 db。并且不要忘记在 docker-compose 后端服务映像中包含数据源连接属性,如下所示。我不是 spring boot 方面的专家,也不是 docker 方面的专家,但现在它可以工作!

        以下是我的结构方式:
        我正在使用 docker version: "3.8"

        仓储服务
        storage-service:
            container_name: storage-service
            restart: always
            build:
                context: storage-service
            image: "service_storage_image"
            depends_on:
                - db
            ports:
                - "8089:8089"
            links:
                - db  
            env_file:
                - env/database.env
            environment:
                WAIT_HOSTS: db:3306
                SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/model_storage?allowPublicKeyRetrieval=true&useSSL=false
                SPRING_DATASOURCE_USERNAME: root
                SPRING_DATASOURCE_PASSWORD: arsene
            healthcheck:
                test: "/usr/bin/mysql --user=arsene --password=arsene--execute \"SHOW DATABASES;\""
                interval: 2s
                timeout: 20s
                retries: 10
            environment:
                - JAVA_OPTS=
                -DEUREKA_SERVER=http://eureka-registry-server:7070/eureka
                -DZIPKIN_SERVER=http://zipkin:9411/
            networks:
                - private-network-mms
        

        我在 docker-compose 中的数据库是这样构造的:

        mysql数据库
        db:
            hostname: db
            container_name: db
            image: "mysql:latest"
            env_file:
                - env/database.env
            volumes:
                - type: bind
                    source: ./env/setup.sql
                    target: /docker-entrypoint-initdb.d/setup.sql
                - db_volume:/var/lib/mysql
            ports:
               - 3307:3306
            networks:
                - private-network-mms
        

        【讨论】:

          猜你喜欢
          • 2020-06-06
          • 2019-06-06
          • 2020-07-24
          • 2019-07-07
          • 2019-01-29
          • 2023-02-23
          • 2020-08-05
          • 2019-12-03
          相关资源
          最近更新 更多