如何在 Docker Compose 中初始化 MySql 数据库

Posted

技术标签:

【中文标题】如何在 Docker Compose 中初始化 MySql 数据库【英文标题】:How to init MySql Database in Docker Compose 【发布时间】:2019-06-26 01:21:47 【问题描述】:

场景: 我在 Spring 中开发了一个使用 mysql 8 数据库的微服务。 这个数据库必须被初始化(创建一个数据库,一些表和数据)。 在我的主机上,我使用 data.sql 和 schema.sql 脚本初始化了数据库。 问题是,我必须设置:

spring.datasource.initialization-mode=always

第一次执行。这将以我想要的方式初始化我的数据库。 对于未来的运行,我必须评论这个命令。非常难看的解决方案,但我找不到更好的解决方案,我现在没有对此question 作出任何回应。 我认为测试它是可以的,但我肯定必须改进它。 目前我想通过 docker compose 使用 docker 运行我的服务。

预期: 这是 docker-compose 文件。相当简单。我是 docker 世界的新手,所以我想一步一步来。

version: '3' 
services:usermanagement-service:
build:
  ./UserManagementService
restart:
  on-failure
ports:
  - "7778:7778"
links:
  - mysqldb
depends_on:
  - mysqldb   mysqldb:
build:
  ./CustomMySql
volumes:
  - ./mysql-data:/var/lib/mysql
restart:
  on-failure
environment:
  MYSQL_ROOT_PASSWORD: root
  MYSQL_DATABASE: userdb
  MYSQL_USER: testuser
  MYSQL_PASSWORD: testuser
expose:
  - "3600"

我期待的是,我的数据库会使用用户进行初始化,并且在第一次运行时,我的微服务会使用数据初始化数据库。 所以在下次开始撰写之前,我必须评论命令并重建图像。 (我知道,丑)

问题: 因此,除了这个丑陋的解决方案之外,我还遇到了运行时问题。 在docker-compose up 上,我的微服务比数据库的初始化速度更快。所以它试图调用 db 导致错误的结果。 由于restart on failure,微服务再次出现。 现在它可以工作了,因为 db 的 init 已经完成。

解决方案: 我搜索了 www,这似乎是一个已知问题,可以在 wait-for-it.sh 文件中解决。这必须包含在 Dockerfile 中的 COPY 中。 所以我不是专家,但我正在寻找一个好的解决方案:

在 spring 中初始化数据库并让我的服务等到 mysql 准备好 或者在第一次运行时通过卷从我的容器中初始化数据库,当然可以解决这个初始化问题。

我不知道什么是最佳做法

【问题讨论】:

不是您问题的直接解决方案。但是,如果您使用 Flyway 之类的数据库迁移工具,则无需注释/取消注释配置属性。 Flyway会根据当前数据库状态自动运行迁移脚本。 【参考方案1】:

仅在第一次运行时加载您的 sql 文件:

您可以使用下面的撰写文件

version: '2.1'
services:

  usermanagement-service:
    build: ./UserManagementService
    restart: on-failure
    ports:
      - "7778:7778"
    depends_on:
      mysqldb:
        condition: service_healthy

  mysqldb:
    image: mysql
    volumes:
      - ./mysql-data:/var/lib/mysql
      - ./mysql-init-files:/docker-entrypoint-initdb.d
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: userdb
      MYSQL_USER: testuser
      MYSQL_PASSWORD: testuser
    ports:
      - "3600:3306"
    healthcheck:
      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
      timeout: 20s
      retries: 10

您必须使用Volumes for more info 将data.sqlschema.sql 文件放在./docker-entrypoint-initdb.d 目录下。

仅当数据库的数据目录为空(数据库服务的第一次运行)时才会加载此文件夹中的 SQL 文件。 (即)在您的情况下,./mysql-data 文件夹应该是空的

第二个问题:

您可以使用healthcheckservice_healthy,而不是使用wait-for-it.sh。这里usermanagement-service将在mysqldb在指定的时间间隔内成功执行["CMD", "mysqladmin" ,"ping", "-h", "localhost"]后启动。有关 healthcheck 和 depends_on 的更多详细信息,请参阅 here。

从here 得到test 命令。

【讨论】:

感谢您的回答。但是我在使用 depends_on 语法时遇到了问题:services.usermanagement-service.depends_on 包含无效类型,它应该是一个数组:github.com/moby/moby/issues/30404 条件不再支持 您可以将 docker-compose.yml 文件的版本设置为2.1。喜欢here 但是是否有必要让版本适合我的docker引擎版本,比如here 如果你在集群中部署它是必要的,否则它会起作用。我的 docker 引擎版本是 18.09.1,我的 compose 文件版本是 2.1,它就像一个魅力。在上面的link中提到了2.1版本的compose文件将适用于v1.12.0之后发布的所有docker引擎版本。

以上是关于如何在 Docker Compose 中初始化 MySql 数据库的主要内容,如果未能解决你的问题,请参考以下文章

Docker中的SpringBoot + Postgres:在docker-compose上:无法初始化JPA EntityManagerFactory:无法加载类

Docker compose 等待数据库服务初始化

如何在Docker中初始化数据库后启动flyway

如何在 docker-compose.yml 中重建 docker 容器?

docker-compose部署nacos单机版(简洁优化版)

Docker部署Docker-compose部署mysql容器及创建数据库失败问题