创建具有准备好的数据库方案的 docker mysql 容器

创建具有准备好的数据库方案的 docker mysql 容器

我想在已经包含我的应用程序所需方案的 mysql 镜像上创建一个 docker 镜像。

我尝试在 Dockerfile 中添加一些行,以便将我的方案导入为 sql 文件。我这样做了(我的 Dockerfile):

FROM mysql

ENV MYSQL_ROOT_PASSWORD="bagabu"
ENV MYSQL_DATABASE="imhere"

ADD imhere.sql /tmp/imhere.sql

RUN "mysql -u root --password="bagabu" imhere < /tmp/imhere.sql"

据我了解,这不起作用,因为 mysql docker 映像不包含 mysql 客户端(最佳实践指出“不要仅仅因为它们会很好而添加它们”)(我错了吗?)

有什么好办法可以做到这一点?我想到了一些办法,但它们似乎都是混乱的解决方法。

  1. 安装 mysql 客户端,执行我需要执行的操作,然后删除/清除它。
  2. 将 mysql 客户端二进制文件复制到图像中,执行我必须执行的操作,然后将其删除。
  3. 在另一个 SQL 服务器中创建模式并直接复制数据库文件(这看起来非常混乱,在我看来就像是一个被污染的问题池)

有什么建议吗?希望以后能更容易维护,并且可能也符合最佳实践?

答案1

为了测试目的我必须这么做。

以下是我利用 dockerhub 上的实际 MySQL / MariaDB 映像和多阶段构建的方法:

FROM mariadb:latest as builder

# That file does the DB initialization but also runs mysql daemon, by removing the last line it will only init
RUN ["sed", "-i", "s/exec \"$@\"/echo \"not running $@\"/", "/usr/local/bin/docker-entrypoint.sh"]

# needed for intialization
ENV MYSQL_ROOT_PASSWORD=root

COPY setup.sql /docker-entrypoint-initdb.d/

# Need to change the datadir to something else that /var/lib/mysql because the parent docker file defines it as a volume.
# https://docs.docker.com/engine/reference/builder/#volume :
#       Changing the volume from within the Dockerfile: If any build steps change the data within the volume after
#       it has been declared, those changes will be discarded.
RUN ["/usr/local/bin/docker-entrypoint.sh", "mysqld", "--datadir", "/initialized-db", "--aria-log-dir-path", "/initialized-db"]

FROM mariadb:latest

COPY --from=builder /initialized-db /var/lib/mysql

完整工作示例在此处:https://github.com/lindycoder/prepopulated-mysql-container-example

答案2

你应该将你的初始化脚本放在一个挂载的目录中/docker-entrypoint-initdb.d- 请参阅“初始化新实例”部分MySQL Docker 镜像文档

答案3

感谢@Martin Roy

做了微小改动以适用于 mysql......

内容 Dockerfile

FROM mysql:latest as builder

# That file does the DB initialization but also runs mysql daemon, by removing the last line it will only init
RUN ["sed", "-i", "s/exec \"$@\"/echo \"not running $@\"/", "/usr/local/bin/docker-entrypoint.sh"]

# needed for intialization
ENV MYSQL_ROOT_PASSWORD=root

COPY setup.sql /docker-entrypoint-initdb.d/

# Need to change the datadir to something else that /var/lib/mysql because the parent docker file defines it as a volume.
# https://docs.docker.com/engine/reference/builder/#volume :
#       Changing the volume from within the Dockerfile: If any build steps change the data within the volume after
#       it has been declared, those changes will be discarded.
RUN ["/usr/local/bin/docker-entrypoint.sh", "mysqld", "--datadir", "/initialized-db"]

FROM mysql:latest

COPY --from=builder /initialized-db /var/lib/mysql

内容设置.sql

CREATE DATABASE myexample;

USE myexample;

CREATE TABLE mytable (myfield VARCHAR(20));

INSERT INTO mytable VALUES ('Hello'), ('Dolly');

完整工作示例在此处:https://github.com/iamdvr/prepopulated-mysql-container-example

答案4

如果您不介意对 dockerized DB 的更改是否仍放在卷中,那么 @Venkateswara Rao 和 @Martin Roy 的答案会非常有用。就我而言,我想要一个预先填充了数据的 Docker 映像,但在我们经常进行数据库迁移的项目中。因此,我想偶尔创建一个 DB 容器,运行迁移,然后以某种方式将这些更改推回去,以便下一个使用 DB 映像的用户已经应用了迁移。由于 DB 文件位于卷中,因此它们不会被卷入映像中docker commmit my-migrated-db-container my-new-db-image

我的解决方案是使用官方MySQL(我这里是 5.6)Dockerfile和入口点文件) 在删除该行后重新创建他们的工作VOLUME /var/lib/mysql。从生成的图像中,我随后使用 Venkateswara 的文件制作了一个预加载的 DB 图像,其中所有未来的 DB 数据都存储在容器本身中(而不是在卷上)。

注意:链接的 Dockerfile 文件已过时,指的是过时的 GPG 密钥服务器(即keys.openpgp.org)。您可以将这些服务器名称替换为,例如keyserver.ubuntu.com

相关内容