70

I am trying to create multiple databases when a MySQL container starts up. According to https://github.com/docker-library/mysql/pull/18, I can mount or copy my scripts in the /docker-entrypoint-initdb.d of the image and they will be executed automatically on start up.

However my scripts are not at all executed. Seems like the docker-entrypoint.sh doesn't see files in the /docker-entrypoint-initdb.d directory.

This is my Dockerfile:

FROM mysql
ADD script.sql /docker-entrypoint-initdb.d/script.sql
RUN chmod -R 775 /docker-entrypoint-initdb.d

ENV MYSQL_ROOT_PASSWORD mypass

This is my script.sql:

CREATE DATABASE mydb;
CREATE DATABASE mydb2;

I build and run the container:

$ docker build -t mysql .
$ docker run -v data_volume:/var/lib/mysql --name somedb -d mysql

When I access the container in tty I can see that the script.sql is in the /docker-entrypoint-initdb.d but is not executed.

I have seen the docker logs -f somedb output but there is no error.

I have tried with .sh file, I also have tried with Maria-db, the result is the same.

What could be the problem?

Canis Majoris
  • 1,016
  • 1
  • 7
  • 18
  • This blog helped me to make this work for me: https://medium.com/@lvthillo/customize-your-mysql-database-in-docker-723ffd59d8fb – DenCowboy Apr 03 '18 at 20:35

8 Answers8

89

Solution

You should clear data_volume BEFORE running the container and the SQL files will be executed.


This volume data_volume can be removed by using command:

docker volume rm data_volume

The root cause of your problem can be found in docker-entrypoint.sh. When you run a MySQL container, it checks if MySQL directory /var/lib/mysql exist or not. If the directory doesn't exist (running it the first time), it will run your SQL files.

if [ ! -d "$DATADIR/mysql" ]; then
    // Some other logic here

    for f in /docker-entrypoint-initdb.d/*; do
        case "$f" in
            *.sh)     echo "$0: running $f"; . "$f" ;;
            *.sql)    echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;;
            *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;;
            *)        echo "$0: ignoring $f" ;;
        esac
        echo
    done 

You can get more details from MySQL docker-entrypoint.sh source file.

informatik01
  • 16,038
  • 10
  • 74
  • 104
Ricky
  • 1,351
  • 1
  • 11
  • 12
  • 4
    There is a slight language barrier above, so I wanted to add to this solution to clarify it a bit, as it is the correct one: If the mysql data volume exists, it will not be overwritten by the SQLs in the entry db. For me, this meant doing `rm /my/data/volume`, as it was a disposable one. After that, things ran as they should. – Tarek Loubani Feb 23 '20 at 07:45
  • 1
    Wow, i spent hours on this one. Thank you for this! – Patrik Grinsvall Oct 14 '20 at 13:20
  • Thank @TarekLoubani for the explanation.I've updated the answer also – Ricky Jan 21 '21 at 17:15
  • THANK YOU! I ran into this as well – James Feb 08 '22 at 20:59
  • 1
    My import worked fine until I switched from `mysql:5.7` to `mysql-server:5.7`. It turns out that the entrypoint in the server image does not include the line to process .sql.gz extensions. – Zaq May 04 '22 at 01:39
  • @Zaq, I think we should check this [Dockerfile](https://github.com/mysql/mysql-docker/blob/main/mysql-server/5.7/docker-entrypoint.sh) file. It supports `*.sh` and `*.sql` files only. – Ricky May 05 '22 at 05:59
  • you saved us all ! – Omid H Mar 26 '23 at 17:04
29

So I had the same issue for hours, and then decided to look into docker-entrypoint.sh. It turns out that the script checks for $DATADIR/mysql, typical /var/lib/mysql and skips the rest of the code if the datadir exists, incl. docker-entrypoint-initdb.d

So what I did was make a simple init.sh file to remove the datadir then start docker.

docker-compose.yml:

volumes:
  - ./docker/mysql/scripts:/docker-entrypoint-initdb.d
  - ./mysql_data:/var/lib/mysql

init.sh:

#!/bin/bash
rm -rf mysql_data
docker-compose up --force-recreate

And of course add -d to docker-compose once I see it works as expected.

Veve
  • 6,643
  • 5
  • 39
  • 58
  • 9
    where did you add the init.sh file? – GeorgeGeorgitsis Jun 07 '19 at 10:24
  • 2
    @GeorgeGeorgitsis: If the Docker image finds any files with the extensions .sh or .iql inside of the /docker-entrypoint-initdb.d folder, it will execute them. I my case the init.sh it located inside ./docker/mysql/scripts/ – Kim Lundberg Stegenborg Madsen Jun 15 '19 at 16:04
  • 3
    My 5 cents: Mind that you should include execution in the permissions for the `init.sh` file on the host - otherwise you could get an error like: `/docker-entrypoint-initdb.d/init.sh: /usr/bin/env: bad interpreter: Permission denied` – Dimitar Ivanov Nov 24 '20 at 06:49
7

I had the exact same issue with the mariadb image (version: 10.4) and I solved it by making sure my container data volume is empty from any files or directories when I create the container from scratch.

This is my docker compose file:

  mariadb:
    image: mariadb:10.4
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ********
    volumes:
    - ./storage/db:/var/lib/mysql:rw
    - ./app/db/SQL:/docker-entrypoint-initdb.d/:rw
    ports:
    - 3306:3306/tcp

For me I just had to make sure this path: './storage/db' is empty from files. Please notice that the directory has to exists but be empty.

eldadfux
  • 158
  • 2
  • 7
3

I had the same problem. I solved it by changing directory owner before starting entrypoint script. Example Dockerfile:

FROM mysql:5.7.17
ADD scripts/init.sql /docker-entrypoint-initdb.d/

RUN chown -R mysql:mysql /docker-entrypoint-initdb.d/

CMD ["mysqld", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]
3

I had the same issue and like @Ricky suggested above the root cause was the volume being non empty. I ran the command docker volume ls to check if the volume was still present before running my docker-compose up and sure enough the volume was there. I deleted the volume using docker volume rm <volume name> and ran the docker-compose and voila the script I had in the docker-entrypoint-initdb.d had run and I had my data in my database. I would say don't worry about the chmod stuff (as some people have suggested) until you make sure the volume is non-existent before running the docker-compose. In case that doesn't work, you can try playing around with the file permissions.

This is what I have permissions wise in my working container in case anybody is wondering -

Permission on docker-entrypoint-initdb.d

drwxr-xr-x   1 root root 4.0K Nov 16 01:52 docker-entrypoint-initdb.d

and the following on the sql scripts -

root@f0a4da202f39:/opt/app# ls -lh /docker-entrypoint-initdb.d/
total 12K
-rw-r--r-- 1 root root 12K Nov 15 22:14 Henry.sql
Heapify
  • 2,581
  • 17
  • 17
3

As per: https://stackoverflow.com/a/67435932/15926221

If you're using "MYSQL_USER: root" as the env variable in mysql/mariadb, this can be the cause of the problem, because the root user was already pre-created.

moratsam
  • 41
  • 3
0

not really an answer to that behavior but i usually do it like this:

RUN mkdir -p /docker-entrypoint-initdb.d && mv myScript.sql /docker-entrypoint-initdb.d/myScript.sql

don't think there's anything wrong with your code but who knows. i suppose you checked 775 is the correct owner? btw im using FROM mysql:5

Zeromus
  • 4,472
  • 8
  • 32
  • 40
  • This configuration didn't solve the problem. I have checked that the file is executable. I guess the problem is in the data_volume. I keep working on it thank you. – Canis Majoris Jul 22 '16 at 08:11
0

Have you solved the issue yet?

A simple workaround is to use absolute path when reading files in /docker-entrypoint-initdb.d/

I made my test using the default config of: https://github.com/docker-library/mysql/blob/master/5.7/Dockerfile#L70

The docker-entrypoint.sh is first moved to /usr/local/bin before execution.

Then it comes to reading files in /docker-entrypoint-initdb.d/, but the following:

for f in /docker-entrypoint-initdb.d/*; do

doesn't seem to find anything.

If you replace it with:

for f in /usr/local/bin/docker-entrypoint-initdb.d/*; do

and then make sure the folder is populated by the Dockerfile command:

COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

COPY docker-entrypoint-initdb.d/ /usr/local/bin/docker-entrypoint-initdb.d/
RUN chmod -R +x /usr/local/bin/docker-entrypoint-initdb.d

From there, build a test statement in /docker-entrypoint-initdb.d/test.sql

CREATE DATABASE `test`;

Finally build and run the image and you should see your database created.

anteverse
  • 74
  • 1
  • 3