我有一个网站,它有非常特定的JS代码,与一个大型、不变的MySQL数据库相关。我希望能够将网站加数据库作为一个单独的包分发给其他人,让他们能够在本地运行,所以我一直在研究使用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
。在构建的早期阶段,可以使用RUN
命令来填充数据库(例如,导致在/var/lib/mysql
中创建DB文件(。如果/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
的需求,并完成了构建阶段的所有工作。