Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL Docker container is not saving data to new image

I'm trying to create a MySQL Docker container that is preset with a certain schema and seed data so that I can have other containers connect to it as a db. I'm using the trusted dockerfile/mysql image as a base, and I wrote a Dockerfile to create a new image from that base and add my schema.sql into it. After building that image (mysql:base), I've been trying to run bash in new container, then go into mysql and create my database and then import the schema. I then exit the container and try to commit the container to a new Docker image. However, the resulting image does not persist any of the changes I made to the MySQL db. It does persist other files that I wrote in the container, but not the db.

Here is the Dockerfile I use to build the initial image (myorg/mysql:base).

FROM dockerfile/mysql:latest
MAINTAINER (me)

ADD schema.sql /data/schema.sql

EXPOSE 3306

# Define working directory.
WORKDIR /data

CMD ["mysqld_safe"]

After building that, I go into the image:

docker run -i -t myorg/mysql:base bash

And run MySQL to import the schema:

myslqd_safe &
141218 00:15:56 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql

mysql -u root

mysql> CREATE DATABASE mydb;
exit;

mysql -u root -D mydb < schema.sql

I can go into mysql and verify the schema has been imported successfully:

 mysql -u root -D mydb -e "SELECT * from tokens;"

Also, if I go into /var/lib/mysql I can see that there is a mydb directory that contains .frm files corresponding to the db.

But when I exit and try to commit that container to a new image:

docker commit -m="import schema.sql" -a="Me" 72c2ff39dd65 myorg/mysql:seed

And then go into the new image:

docker run -i -t --rm myorg/mysql:seed bash

The db files are no longer in /var/lib/mysql, and running mysql -u root -e "SHOW DATABASES" does not show the mydb database, only the default mysql, information_schema, and performance_schema dbs. I found that if I created a new textfile in the container (echo 'test' > newfile), that file would be present in the committed image, but not the db.

I wonder if this has something to do with the fact that the trusted image Dockerfile has VOLUME ["/etc/mysql", "/var/lib/mysql"] so it mounts the db directory as a volume. My Dockerfile does not have this command, but I don't know if it's inherited anyway (I don't really understand how volumes work well enough to know how this might affect my build). I don't need the db mounted as a volume because I need another container to connect to it over a network connection (I'm going to use docker links for that).

FWIW, I am running boot2docker 1.3.2 on OS X 10.9.5.

like image 393
Taylor H Avatar asked Dec 19 '14 19:12

Taylor H


People also ask

How do I save a Docker image after making changes?

Hence, if you want the changes to persist, you can use the Docker commit command. The commit command will save any changes you make to the container and create a new image layer on top of it.


2 Answers

As another answer and you have stated volumes cannot be committed and child containers do in fact inherit volume definitions from parents. Hence any changes to the volume will be discarded. I would like to add data such as mysql database files should always be in volumes for several reasons and you should not be trying to commit it into your image.

  1. If you have to migrate containers there is no easy way to extract data from containers if its not in a volume.
  2. If you want to start multiple containers that share data you have to have data in a volume.
  3. If you want to change your container definition with say new volumes or ports you have to delete and recreate it. If you have data in the container you will loose it. (See this question for an example of this case.)
  4. The union file system is slower than normal file systems which will slow down your application or database.

So what should you do instead?

  1. Use a data only container that can be linked with any instance of the service container. Then you can use volumes-from to get your data into the service container.
  2. Use a host mounted volume so that you can restart containers and mount the same location into new containers.
like image 184
Usman Ismail Avatar answered Oct 10 '22 22:10

Usman Ismail


You are probably better off rolling your own mysql. That way there are no surprises, no hidden "magic" in there.

If you look at an example dockerfile for mysql core, you can see the VOLUME declaration for /var/lib/mysql.

Docs on docker volumes.

Data volumes

A data volume is a specially-designated directory within one or more containers that bypasses the Union File System to provide several useful features for persistent or shared data:

  • Data volumes can be shared and reused between containers
  • Changes to a data volume are made directly
  • Changes to a data volume will not be included when you update an image
  • Volumes persist until no containers use them
like image 24
user2105103 Avatar answered Oct 10 '22 21:10

user2105103