Reputation: 1116
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?
Upvotes: 80
Views: 132231
Reputation: 1571
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.
Upvotes: 110
Reputation: 41
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.
Upvotes: 3
Reputation: 2891
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
Upvotes: 3
Reputation: 198
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.
Upvotes: 9
Reputation: 524
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.
Upvotes: 30
Reputation: 63
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"]
Upvotes: 3
Reputation: 74
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.
Upvotes: 0
Reputation: 4532
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
Upvotes: 0