使用 docker 打包一个包含固定 MySQL 数据的 web 应用程序

Posted

技术标签:

【中文标题】使用 docker 打包一个包含固定 MySQL 数据的 web 应用程序【英文标题】:Using docker to package a web app including fixed MySQL data 【发布时间】:2021-07-26 14:25:58 【问题描述】:

我有一个网站,其中包含与大型、不变的 mysql 数据库相关联的非常具体的 JS 代码。我希望能够将网站和数据库作为单个包分发,以便其他人能够在本地运行,所以我一直在研究使用 docker 来做这件事。请注意,我没有使用 docker 来测试正在运行的应用程序:只是为了将其分发给其他人查看。

据我了解,运行已填充 MySQL 数据库的 docker 映像通常在启动数据库后从 .sql 文件加载。但是,对于我的数据库内容,这导致填充数据库需要等待一个小时,因为 .sql 转储有很多 GB,并且需要很长时间才能加载。因此,我考虑将数据加载到正在运行的数据库中一次,将数据库卷 (/var/lib/mysql) 保留在映像本地,并在数据加载后使用 docker commit 创建映像的快照。

但是,这种方法似乎违背了许多标准 docker 建议:通常docker commit 不受欢迎,/var/lib/mysql 存储为单独的数据卷,而不是保存在映像本身中。尽管如此,我的用例似乎有所不同,因为(a)数据库中的数据不打算在将来更改(b)从 mysql 转储加载需要很长时间,以及(c)大型数据存储(而不是不仅仅是 js 应用程序代码)是我真正想要包含在图像中的主要内容之一。

那么我的用例是打破约定并使用docker commit 以及将 MySQL 文件保存在映像本身而不是单独的数据卷中的正当理由吗?或者,是否有其他更标准的方式来分发具有大型固定数据库存储的完全运行、完全填充的 Web 应用程序?

【问题讨论】:

“通常 docker commit 不被接受” 声明缺乏实质;你有什么要备份的吗? 建议——不能用sqlite来保存静态数据吗? 另一种方法是在你的 docker 镜像中打包一个数据库转储。您可以在启动应用程序之前恢复此转储。 感谢 cmets @ashu。这是一个关于不推荐 docker commit 的链接(第 5 点)developers.redhat.com/blog/2016/02/24/…。 Re sqlite - 我怀疑访问速度不足以满足我们的需求。重新图像中的 db 转储 - 如果转储为 .sql 格式,则加载到数据库中以将其作为分布式 Web 应用程序进行合理打包需要太长时间(请参阅问题中的讨论) 【参考方案1】:

我发现您可以使用多阶段构建,而不是使用docker commit。在构建的早期阶段,可以使用RUN 命令来填充数据库(例如,导致在/var/lib/mysql 中创建数据库文件)。如果/var/lib/mysql 是一个数据卷,那么作为构建的最后阶段,可以将整个/var/lib/mysql 目录复制到一个永久的非数据卷位置,例如/var/lib/mysql_permanent,例如使用

ENV MYSQL_DATA_DIR=/var/lib/mysql_permanent
# copy the DB files from the previous image
COPY --from=create_database "/var/lib/mysql" "$MYSQL_DATA_DIR"

然后将使用烘焙到图像中的正确基础数据库文件创建最终图像。最后一个构建阶段需要使用指定datadir=$MYSQL_DATA_DIR 的mysqld.cnf 文件运行mysqld 进程,以访问正确的文件。然后,这绕过了对docker commit 的需求,并在构建阶段完成了所有工作。

【讨论】:

以上是关于使用 docker 打包一个包含固定 MySQL 数据的 web 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

Docker Compose 项目打包部署

Flask+MySQL+Redis的Docker配置

Flask+MySQL+Redis的Docker配置

Docker入门教程:本地打包docker镜像

怎么把spring boot打包成镜像部署到docker

将php项目打包docker镜像