Spring Boot + MySQL + Docker Compose - 无法使 Spring Boot 连接到 MySQL

Posted

技术标签:

【中文标题】Spring Boot + MySQL + Docker Compose - 无法使 Spring Boot 连接到 MySQL【英文标题】:Spring Boot + MySQL + Docker Compose - Cannot make Spring Boot connect to 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 时,它说连接被拒绝。我一直在到处寻找,无法解决。我希望任何人都可以帮助我。谢谢!

【问题讨论】:

【参考方案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

【讨论】:

以上是关于Spring Boot + MySQL + Docker Compose - 无法使 Spring Boot 连接到 MySQL的主要内容,如果未能解决你的问题,请参考以下文章

Netty实战项目:Spring boot 程序的聊天程序

Netty实战项目:Spring boot 程序的聊天程序

Spring Boot + MySQL + Docker Compose - 无法使 Spring Boot 连接到 MySQL

Spring boot??????????????????Spring boot??????MySql,Mybatis???PageHelper??????

Spring Boot 2.0:Docker Compose + Spring Boot + Nginx + Mysql 实践

spring boot mysql 事务