How to create populated MySQL Docker Image on build time
I ran into the same problem this week. I've found a working solution without the need for --volumes-from
The problem that's already stated is that /var/lib/mysql
is a volume, and since Docker is not going to support UNVOLUME
in it's Dockerfile in the near future, you can't use this location for your database storage if you want to start off with an empty database by default. (https://github.com/docker/docker/issues/18287). That's why I overwrite etc/mysqld.my.cnf
, giving mysql a new datadir.
Together with pwes' his answer, you can create a Dockerile like this:
FROM mysql:5.6ENV MYSQL_DATABASE dbENV MYSQL_ROOT_PASSWORD passCOPY db.sql /docker-entrypoint-initdb.d/db.sqlCOPY my.cnf /etc/mysql/my.cnfRUN /entrypoint.sh mysqld & sleep 30 && killall mysqldRUN rm /docker-entrypoint-initdb.d/db.sql
The only change there is in my.cnf
is the location of the datadir:
.... [mysqld]skip-host-cacheskip-name-resolveuser = mysqlpid-file = /var/run/mysqld/mysqld.pidsocket = /var/run/mysqld/mysqld.sockport = 3306basedir = /usrdatadir = /var/lib/mysql2 <-- can be anything except /var/lib/mysqltmpdir = /tmplc-messages-dir = /usr/share/mysqlexplicit_defaults_for_timestamp....
This cannot be done cleanly the exact way you want it to, at least when basing on official mysql
image, because you need to communicate with the server to import the data and the server is not run and initialized (from mysql's docker-entrypoint.sh
) until the container is run, which is only when the image is already built.
The not-so-clean way is to run the process in the container, using the /entrypoint.sh
script from mysql image, but you must take care of all the settings required by the entrypoint (like $MYSQL_ROOT_PASSWORD
) as well as a clean way to stop the daemon just after importing the data. Something like:
FROM mysql:5.6ADD data.sql /docker-entrypoint-initdb.d/00-import-data.sqlENV MYSQL_ROOT_PASSWORD somepasswordENV MYSQL_DATABASE db1RUN /entrypoint.sh mysqld & sleep 30 && killall mysqld
is a hackish way that results in pre-initialized DB, but... it doesn't work. The reason is that /var/lib/mysql
is declared as a volume in mysql's Dockerfile, and any changes to this directory during build process are lost after the build step is done. This can be observed in the following Dockerfile:
FROM mysql:5.6RUN touch /var/lib/mysql/some-file && ls /var/lib/mysqlRUN touch /var/lib/mysql/some-file2 && ls /var/lib/mysql
So I suggest going with docker commit
way you described. The end result is the same as the one you want to achieve, with an exception of Layer 2 maybe.
UPDATE: As OP commented below, the commit doesn't contain volumes either. So, the only way seems to be to either edit MySQL Dockerfile and remove VOLUME
to keep data inside the container, or to manage the volumes separately from containers.