【问题标题】:How to create a initialised MySQL Docker image?如何创建一个初始化的 MySQL Docker 镜像?
【发布时间】:2018-04-13 09:38:55
【问题描述】:

使用 Docker 镜像mysql:5.7.21 我想基于它创建一个新的镜像,该镜像已经初始化了它的数据库。 (我想将它用于我的接受环境)。

我知道/docker-entrypoint-initdb.d,我可以休耕:

FROM mysql:5.7.21

COPY ./init /docker-entrypoint-initdb.d

但问题是它只会复制 tar/sql 文件,但直到第一次运行时才会执行。另一个缺点也是图像大小。如果您在容器内复制例如 200MB 的数据,那么这些文件将保留在图像中(作为一个层)。

所以我想知道是否有我没有想到的与 multi-stage 或新的 --squash 标志的组合(这将启用、添加文件、执行文件、删除文件)。

在搜索此问题时,我还发现了 --datadir 标志。不确定这有什么帮助。

编辑:

到目前为止,我已经休耕了:

FROM mysql:5.7.21 as builder

ENV MYSQL_ALLOW_EMPTY_PASSWORD yes
ENV MYSQL_DATABASE example

COPY ./init /docker-entrypoint-initdb.d

RUN head -n-2 < /usr/local/bin/docker-entrypoint.sh > /usr/local/bin/docker-entrypoint.sh \
    && docker-entrypoint.sh mysqld \
    && /etc/init.d/mysql start \
    && mysql -uroot -e 'FLUSH TABLES;' \
    && mysql -uroot -e 'show tables;' mysql \
    && mysql -uroot -e 'show tables;' example \
    && /etc/init.d/mysql stop \
    # This shows the files!
    && ls -la /var/lib/mysql

# This shows no files?!!
RUN ls -la /var/lib/mysql

FROM mysql:5.7.21

ENV MYSQL_ALLOW_EMPTY_PASSWORD yes
ENV MYSQL_DATABASE example

COPY --from=builder /var/lib/mysql /var/lib/mysql
RUN ls -la 

RUN ls -la /var/lib/mysql \
    && /etc/init.d/mysql start \
    && mysql -uroot -e 'show tables;' mysql \
    && mysql -uroot -e 'show tables;' example

看到上面的内联 cmets... 发生了真正奇怪的事情吗?因此,当我在/var/lib/mysql 上执行ls -la 时,在同一个RUN 中,我可以看到这些文件。但是在新层(新 RUN)中它是空的:S

【问题讨论】:

  • 您希望容器将数据存储在容器本身中吗?通常使用卷来存储数据。
  • 是的,我想将数据存储在它自己的容器中。 (在这种情况下,它只是一个 10mb db,但将来可能会增加)。它将被部署到 Docker Swarm 环境中,我想让它尽可能简单(不设置持久卷)。

标签: mysql image docker continuous-integration containers


【解决方案1】:

所以我找到了解决方案!!!我的问题在于 /var/lib/mysql 是一个卷:https://github.com/docker-library/mysql/blob/ad625c64a06e16683e997e5a0147508d115f4989/5.7/Dockerfile#L71

一个工作的多级 Dockerfile:

FROM mysql:5.7.21 as builder

ENV MYSQL_ALLOW_EMPTY_PASSWORD yes
ENV MYSQL_DATABASE example

COPY ./init /docker-entrypoint-initdb.d

RUN head -n-2 < /usr/local/bin/docker-entrypoint.sh > /usr/local/bin/docker-entrypoint.sh
RUN mkdir -p /var/lib/mysql_tmp
RUN docker-entrypoint.sh mysqld --datadir /var/lib/mysql_tmp

FROM mysql:5.7.21

ENV MYSQL_ALLOW_EMPTY_PASSWORD yes
ENV MYSQL_DATABASE example

COPY --from=builder /var/lib/mysql_tmp /var/lib/mysql_tmp

CMD ["mysqld", "--datadir", "/var/lib/mysql_tmp"]

所以我们在这里所做的是确保删除最后两行(可以更改为仅删除最后一行),因为它 contains exec "$@" 基本上意味着 exec msqld。那是 MySQL 守护进程,所以它会卡在那里。

此外,我将 datadir 从 var/lib/mysql(它是一个卷)更改为 var/lib/mysql_tmp(因为没有更好的名称)。

在最后阶段,我复制var/lib/mysql_tmp 并确保mysqld 使用该目录。

现在我可以为我的接受环境烘焙(对我来说是只读的)db。

【讨论】:

  • 我希望通过执行以下操作来设置 var/lib/mysql:- a) 运行 flyway migrate 命令 b) 以 root 用户身份运行 sql 脚本,这将创建另一个用户并授予权限 c) 运行另一个 bootstrap.sql作为新创建的用户。然后在下一阶段,与您的 Dockerfile 非常相似,使用“COPY --from”命令复制/var/lib/mysql。问题是我需要一个 mysql 守护程序运行才能执行 a)、b) 和 c)。而且,如果我在第一阶段运行 mysqld 守护程序,则 RUN 命令会卡住
【解决方案2】:

如果您检查 Dockerfile 中的 mysql:5.7.21 映像 (https://hub.docker.com/r/library/mysql/),您将看到入口点设置为 ["docker-entrypoint.sh"],因此这是运行映像时执行的第一个命令。

如果您想在创建映像期间执行它(因此,使映像大小变大,但没问题),您只需将其放入您的 Dockerfile 中:

RUN docker-entrypoint.sh /bin/true

这个入口点将执行在/docker-entrypoint-initdb.d 中找到的脚本,但是,正如您所注意到的,这些脚本也占用了空间。为了丢弃文件,您可以使用多阶段构建来复制原始数据库。

再次检查Dockerfile 以查看图像中唯一的卷是/var/lib/mysql。这应该是包含数据库上所有信息的目录,它应该是您复制的目录。结果是这样的:

FROM mysql:5.7.21 as base

COPY ./init /docker-entrypoint-initdb.d
RUN docker-entrypoint.sh /bin/true

FROM mysql:5.7.21

COPY --from=base /var/lib/mysql /var/lib/mysql

说了这么多,我不建议创建“初始化”图像,因为这有点违背使用容器的精神,但这是另一个问题;)

【讨论】:

  • 你试过了吗?因为我之前什至问过这个问题......它会因为最后一个 exec 命令而卡住。我什至用tail删除了最后两行,但目录不知何故保持空。
  • 你是对的,你应该在 docker-entrypoint.sh 中添加一些东西,比如:RUN docker-entrypoint.sh /bin/true
  • 那也行不通,因为if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then。它检查第一个参数是否为 mysqld。在这种情况下,它甚至不起作用,因为您会收到一个错误,告诉您需要设置一些环境变量。请不要在没有自己测试的情况下创建答案。
猜你喜欢
  • 2015-08-25
  • 1970-01-01
  • 1970-01-01
  • 2017-05-03
  • 2017-04-24
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
  • 2016-08-16
相关资源
最近更新 更多