我想在已经包含我的应用程序所需方案的 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 客户端(最佳实践指出“不要仅仅因为它们会很好而添加它们”)(我错了吗?)
有什么好办法可以做到这一点?我想到了一些办法,但它们似乎都是混乱的解决方法。
- 安装 mysql 客户端,执行我需要执行的操作,然后删除/清除它。
- 将 mysql 客户端二进制文件复制到图像中,执行我必须执行的操作,然后将其删除。
- 在另一个 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
。