Using docker to package a web app including fixed MySQL data

389 Views Asked by At

I have a website with very specific JS code associated with a large, unchanging, MySQL database. I want to be able to distribute the website plus database as a single package for others to be able to run locally, so I have been investigating doing this using docker. Note that I'm not using docker for testing the running app: merely for distributing it for others to look at.

By my understanding, docker images that run a populated MySQL database usually load it up from a .sql file after starting the DB. However, for my database contents, this results in an hour-long wait to populate the database, since the .sql dump is many gigabytes, and takes that long to load. Therefore I was thinking of loading the data into the running database once, keeping the db volume (/var/lib/mysql) local to the image, and creating a snapshot of the image using docker commit once the data has been loaded.

However, this approach seems to go against many standard docker recommendations: usually docker commit is frowned upon, and /var/lib/mysql is stored as a separate data-volume, not saved in the image itself. Nevertheless, my use-case seems different, as (a) the data in the database is not intended to change in the future (b) it takes a long time to load from a mysql dump and (c) the large data store (rather than just the js app code) is one of the main things that I actually want to include in the image.

So is my use-case a valid reason to break convention and use docker commit together with saving the MySQL files in the image itself rather than a separate data volume? Or is there an alternative, more standard way of distributing a fully working, fully-populated web app with a large fixed database store?

1

There are 1 best solutions below

2
On

I found out that instead of using docker commit, you can use multi-stage builds. In an early stage of the build, a RUN command can be used to populate the database (e.g. resulting in the DB files being created in /var/lib/mysql). If /var/lib/mysql is a data volume, then as the last stage of the build, the entire /var/lib/mysql directory can be copied to a permanent, non-data volume location, e.g. /var/lib/mysql_permanent, using e.g.

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}"

The final image will then be created with the correct underlying database files baked into the image. The last build stage then needs to run the mysqld process with a mysqld.cnf file specifying datadir=${MYSQL_DATA_DIR}, to access the correct files. This then bypasses the need for docker commit, and does everything in the build stage.