如何在构建时创建填充的MySQL Docker镜像

Mor*_*sen 19 mysql database docker

我想创建一个已填充数据的MySQL Docker镜像.

我想创建这样的3层:

        |---------------------|---------------------|
Layer 3 | Customer 1 Database | Customer 2 Database |
        |---------------------|---------------------|
Layer 2 |   Database image with tables but no data  |
        |-------------------------------------------|
Layer 1 |                mysql:5.6.26               |
        |-------------------------------------------|
Run Code Online (Sandbox Code Playgroud)

我现在的问题是如何为第2层和第3层创建正确的Dockerfile?我的empty_with_tables.sql文件被加载到第2层,customer1.sql和customer2.sql被加载到第3层的两个图像中.我读了一些关于将SQL文件放入'/docker-entrypoint-initdb.d'的内容.但这会导致数据在第一次启动图像时出现.这不是我想要的.我希望数据在图像中准备就绪(例如,在测试中可以快速获得).

我可以启动mysql映像,从命令行加载数据并执行'commit'但这不可重现,需要在SQL文件中的数据更改时再次执行此操作.

如何才能做到这一点?

最好的祝福,

  • 莫滕格林赫曼森

Meg*_*ubs 18

本周我遇到了同样的问题.我找到了一个无需工作的解决方案--volumes-from

已经说过的问题/var/lib/mysql是卷,并且由于Docker UNVOLUME在不久的将来不会支持它的Dockerfile,如果你想在默认情况下从空数据库开始,就不能将这个位置用于数据库存储.(https://github.com/docker/docker/issues/18287).这就是我覆盖的原因etc/mysqld.my.cnf,给mysql一个新的datadir.

与pwes的回答一起,你可以像这样创建一个Dockerile:

FROM mysql:5.6

ENV MYSQL_DATABASE db
ENV MYSQL_ROOT_PASSWORD pass
COPY db.sql /docker-entrypoint-initdb.d/db.sql
COPY my.cnf /etc/mysql/my.cnf
RUN /entrypoint.sh mysqld & sleep 30 && killall mysqld
RUN rm /docker-entrypoint-initdb.d/db.sql
Run Code Online (Sandbox Code Playgroud)

唯一的变化是my.cnfdatadir的位置:

.... 
[mysqld]
skip-host-cache
skip-name-resolve
user        = mysql
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
port        = 3306
basedir     = /usr
datadir     = /var/lib/mysql2 <-- can be anything except /var/lib/mysql
tmpdir      = /tmp
lc-messages-dir = /usr/share/mysql
explicit_defaults_for_timestamp
....
Run Code Online (Sandbox Code Playgroud)


pwe*_*wes 7

这不能以你想要的方式干净地完成,至少在基于官方mysql图像时,因为你需要与服务器通信以导入数据,并且服务器不运行和初始化(从mysql的docker-entrypoint.sh),直到容器运行,仅在图像已经构建时.

不那么干净的方法是使用/entrypoint.shmysql映像中的脚本在容器中运行进程,但是你必须处理入口点所需的所有设置(比如$MYSQL_ROOT_PASSWORD)以及一个干净的方法来停止守护进程导入数据后.就像是:

FROM mysql:5.6

ADD data.sql /docker-entrypoint-initdb.d/00-import-data.sql
ENV MYSQL_ROOT_PASSWORD somepassword
ENV MYSQL_DATABASE db1
RUN /entrypoint.sh mysqld & sleep 30 && killall mysqld
Run Code Online (Sandbox Code Playgroud)

是一种导致预先初始化数据库的hackish方式,但是......它不起作用.原因是它/var/lib/mysql在mysql的Dockerfile 中被声明为一个卷,并且在构建过程完成后,在构建过程中对该目录的任何更改都将丢失.这可以在以下Dockerfile中观察到:

FROM mysql:5.6

RUN touch /var/lib/mysql/some-file && ls /var/lib/mysql
RUN touch /var/lib/mysql/some-file2 && ls /var/lib/mysql
Run Code Online (Sandbox Code Playgroud)

所以我建议docker commit按照你描述的方式进行.最终结果与您想要实现的结果相同,但第2层可能除外.

更新:如下面的OP所述,提交也不包含卷.因此,唯一的方法似乎是编辑MySQL Dockerfile并删除VOLUME以将数据保存在容器内,或者从容器中单独管理卷.

  • 你好!对不起,我的答复很晚!commit方法没有问题吗?在正式的Dockerfile中,定义了一个卷('VOLUME / var / lib / mysql'),这就是数据库所在的位置。因此,提交将不会在新映像中包含这些文件(我对'docker diff &lt;containerid&gt;'进行了检查)。而且我不能“取消体积”安装吗? (2认同)

Cho*_*meh 5

基于MegaWubs的答案,我发现此Dockerfile就足够了。

FROM mysql:5.6
RUN sed -i 's|/var/lib/mysql|/var/lib/mysql2|g' /etc/mysql/my.cnf
Run Code Online (Sandbox Code Playgroud)

  • 使用mysql:5.7,我使用了:```RUN sed -i's | / var / lib / mysql | / var / lib / mysql2 | g'/ etc / mysql / mysql.conf.d / mysqld.cnf`` ` (2认同)

Phi*_*aty 5

MegaWubs 的回答很好,除了这个“sleep 30”迫使你猜测 initdb 的执行时间。为了避免这种情况,我在 /docker-entrypoint-initdb.d 中放置了一个小的 shell 脚本,在其他脚本之后执行:

/docker-entrypoint-initdb.d/
  |- 01_my_data1.sql
  |- 02_my_data2.sql
  ...
  |- 99_last_processed_file.sh
Run Code Online (Sandbox Code Playgroud)

99_last_processed_file.sh

#!/usr/bin/env bash
touch /tmp/server_can_shutdown.txt
Run Code Online (Sandbox Code Playgroud)

——

同时,在 Dockerfile 中,我运行另一个脚本来代替 Mortenn 的 "sleep && killall" :

# Dockerfile
# ...
COPY wait_then_shutdown.sh /tmp/wait_then_shutdown.sh
RUN /entrypoint.sh mysqld & /tmp/wait_then_shutdown.sh  # <-- 
RUN rm /docker-entrypoint-initdb.d/*
Run Code Online (Sandbox Code Playgroud)

wait_then_shutdown.sh

#!/usr/bin/env bash
while [ ! -f /tmp/server_can_shutdown.txt ] # <-- created by 99_last_processed_file.sh
do
  sleep 2
done
kill $(pidof mysqld)
Run Code Online (Sandbox Code Playgroud)

——

现在,mysqld仅在 /docker-entrypoint-initdb.d 中处理所有其他文件时停止


Mor*_*sen -3

因此,我对这个问题的解决方案只是不将所有内容分层,而是创建一个基础映像并使用 --volumes-from 从纯数据容器注入数据库文件。

  • 您能提供更多信息吗?我也想做。 (7认同)
  • @Morten Green 请花点时间分享您的工作,我们在这里互相帮助。 (3认同)