How to run a SQL script at every MySQL initialization? - mysql

I would like to like to run a SQL script at MySQL initialization. This script has basically some UPDATE commands and has be run at each initialization. Basically, the ideia is to update Root and User passwords at each initialization, with vault credentials that are obtained at each database startup. The MySQL database is being deployed inside a Docker container.
In this scenario, is there a way to preset a SQL script that can be run at every database initialization inside a Docker container? If so, please give us an example of how to do implement that. I do use docker-entrypoint.sh and foreground.sh for some customizations at such container.

mysqld accepts a parameter that specifies initialization scripts and you can use that.
docker-compose.yml
version: "3.3"
services:
db:
image: mariadb:10.1
environment:
- MYSQL_ROOT_PASSWORD
volumes:
- ./init.sql:/script/init.sql
command: "--init-file /script/init.sql"
init.sql
UPDATE mysql.user SET authentication_string=PASSWORD("mihai") WHERE USER="root";
UPDATE mysql.user SET plugin="mysql_native_password";
.env
MYSQL_ROOT_PASSWORD=rootpassword
Run the container and test it:
docker-compose up -d
docker-compose exec db mysql -hlocalhost -uroot -pmihai
select plugin from mysql.user where USER='root';
You can see that the plugin has also been updated so the scripts both worked.
You can remove the command and test with the original password as well. Make sure to remove the volumes between runs.

Related

Where docker stores mysql settings

I am facing one issue with docker, L am using laradock docker env for laravel. Since it has issue with mysql version I had to run those command:
$ docker-compose exec mysql bash
$ mysql -u root -p
ALTER USER 'root'#'localhost' indentified WITH mysql_native_password BY 'root';
Also imported database through http://localhost:8080 and phpmyadmin
So I am trying to reproduce this issue again, so I deleted everything from docker with
$ docker system prune
but when I rebuild the containers
sudo docker-compose up -d nginx mysql phpmyadmin workspace
My previous database is loaded again.
So my question would be how to delete db and MySQL settings, so I can execute the alter command and import database again.
Overall I am trying to determine if this issue with MySQL will occur on another platform again, so I am trying to reproduce it from scratch and that is why I need to reset completely MySQL env and databases.
So not sure where MySQL settings are stored and how to delete them.
MySQL is storing most of the important information of your container in a volume.
Now, the command:
docker system prune
do not remove the volumes, per default.
If you also want to remove them, you can run:
docker system prune --volumes
If you do want to list or act on those specific volumes:
docker volume --help
would give you all the commands on volumes like rm, ls, ...

Docker. Create image based on MySQL with DB and User created

I want to create an image with docker for my app.
The app uses MySQL. I need my image to be based on MySQL image (mysql/mysql-server ?) .
IN the Dockerfile i need to set some instructions to create a DB with specific user/password . So, my app can work with that DB .
I don't need tables, only empty DB with specific name and user/password that can access this DB.
How can i do this?
I wanted something like
FROM mysql/mysql-server
# Create MySQL DB
mysql -u root -e "CREATE DATABASE MyDB"
But i don't know root user password here. It seems it is autogenerated ?
How can i do this?
That image auto-generates the root password by default, as stated in the image github repository (https://github.com/mysql/mysql-docker). You can set the MYSQL_ROOT_PASSWORD environment variable in your Dockerfile with the password you want.
Apart from that, if what you want is to create a database at image startup, you can use the environment variable MYSQL_DATABASE.
More info about the supported environment variables here:
https://github.com/mysql/mysql-docker#docker-environment-variables
You have 2 solutions here:
[Easy] Using the docker-compose and create a docker-compose.yml file like this one:
version: '3'
services:
mariadb:
container_name: mariadb
image: mariadb:latest
environment:
- MYSQL_DATABASE=_YOUR_DB_
- MYSQL_ROOT_PASSWORD="_YOUR_PASSWORD_"
- MYSQL_USER=_YOUR_USER_
- MYSQL_PASSWORD=_YOUR_USER_PASSWORD_
...
This configuration will bring a MariaDB database to you. also if you want to use it, you can simply check this page for the installation guide:
https://github.com/docker/compose
The final step is just to go into the directory you saved the docker-compose.yml and just run:
docker-compose up
or if you don't want to see the log inside the terminal just add -d flag to it.
2. [Little Complicated] You can create a custom image for your needs. in this case, it is better if you check the Dockerfile documents and then see this autogenerated default MariaDB Dockerfile for understanding what to do exactly to achieve your goal.

Docker - How to take a look at the Tables inside MySQL volume?

I have imported an SQL file contains my schema and all its tables, By using:
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
- ./resources/file.sql:/docker-entrypoint-initdb.d/file.sql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: db
The problem is, when I trying to retrieve data from some tables an exception in the backend appear:
throws exception:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table
'db.Configuration' doesn't exist
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'db.Configuration' doesn't exist
And some tables work perfectly like user table.
Although I have tested the SQL file in MySQL Workbench.
The question is, Is there a way I can see what tables are inside the db_data volume?
Yes, you can see All Table information from docker command line.
First, go inside docker container, run below command.
docker exec -it mysql_container_name mysql -uroot -p
where “root” is the username for MySQL database.
After running above command it will ask you a password.
Then Select Database, run below command
USE Name-Of-The-Database
get the list of all tables.
show tables;
Run any query, e.g select * from
SELECT * FROM table_name;
I have listed down some daily docker useful commands, have a look.
https://rohanjmohite.wordpress.com/2017/08/04/docker-daily-useful-commands/
please let me know in case any further more explanation required?
You can execute any SQL command directly from the host to view your database.
You are looking for this command:
docker exec -it mysql-container mysql -uroot -pmy-secret-pw -D thisdatabase -e "SELECT * FROM table_name;
where mysql-container is the name of the mysql container
where -uroot is the account for the sql container
where -pmy-secret-pw is the password for the sql container
where thisdatabase is the name of the database to inspect
where table_name is obviously the database table name of interest
TIP: if it is a new container, and you don't know the password, just run this command:
sudo docker logs mysql-container 2>&1 | grep GENERATED
One solution is to use MySQL Workbench and create a connection pointing to the docker database container. From there you can check what schema tables have been created.
If the database docker container is started, you can inspect the container and find the IPAddress using the following command:
docker inspect container-name-here
get the IPAddress and use it in the MySQLWorkbench to create the connection

MySQL container: grant access and create a new image

I'm trying to use MySQL docker container in my host system to make installation and configuration processes much easier and faster.
So, I've pulled an image from:
https://hub.docker.com/r/mysql/mysql-server/
Then started container based on this image..
Container started fine, but I was not able to connect to this DB from my host system (everything is ok if I try to connect from container). It failed with a message:
ERROR 1130 (HY000): Host '<here goes my IP>' is not allowed to connect to this MySQL server
So, as I understand, my root user has no enough permissions.
I've entered my container:
docker exec -it mysql bash
Connected to DB:
mysql -uroot -ppassword
Updated permissions for my root user:
use mysql;
UPDATE user SET Host="%" WHERE User='root';
It's updated fine.
Than I decided to save my updated image somehow... I've found this guide:
http://docs.oracle.com/cd/E52668_01/E75728/html/section_c5q_n2z_fp.html
After executing:
docker stop mysql
docker commit -m "Fixed permissions for root user" -a "Few words about author" `docker ps -l -q` myrepo/mysql:v1
docker rm mysql
docker run --name new-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=pass -d myrepo/mysql:v1
I've found that my root user hasn't permissions again.
What is wrong here?
How to public my updated image into my Dockerhub?
My original answer is for persisting the change in the MySQL data after it has been initialized. But since you want to do this in the image for every initialization automatically there is a different approach for this. You can use one of the following options:
There is an environment variable called MYSQL_ROOT_HOST for this image where you can set the host (https://github.com/mysql/mysql-docker/blob/mysql-server/5.7/docker-entrypoint.sh#L63-L69). You should be able to set this to % to allow all hosts to connect as root such as -e MYSQL_ROOT_HOST="%".
The image supports adding SQL files to /docker-entrypoint-initdb.d/ to be initialized on startup (https://github.com/mysql/mysql-docker/blob/mysql-server/5.7/docker-entrypoint.sh#L98-L105). You can create your SQL file that has UPDATE mysql.user SET Host="%" WHERE User='root'; in it and then ADD that file to /docker-entrypoint-initdb.d/ in your own image. Then, when starting a container based on that image it will initialize that SQL file.
That image specifies a default volume to hold the MySQL data at https://github.com/mysql/mysql-docker/blob/mysql-server/5.7/Dockerfile#L11. When you start the container, a volume is created for that container. When you update the permissions for the root user, it is saved in this volume (it is actually part of MySQL data for the mysql database). But once you remove the container, that volume is also lost.
There are usually two things you can do in this case to preserve the data between container restarts or even new containers:
Create a named volume and mount the data there. To do this you can run docker volume create mysqldata. Then, when starting the container mount the data with -v mysqldata:/var/lib/mysql. This volume will persist even after you stop or delete your MySQL container.
Bind mount the data to a host folder. Instead of creating a volume, you can just mount a folder such as -v /mnt/mysqldata:/var/lib/mysql. This will persist all your MySQL data on the host at /mnt/mysqldata.
Though, these are not the only ways to persist data, they are two built-in methods. There are also Docker volume plugins that allow you to use other storage mediums (examples might be https://github.com/rancher/convoy for NFS and https://github.com/NetApp/netappdvp for NetApp).
docker exec -it mysql bash
chown -R mysql:mysql /var/lib/mysql
if you change permission of volume in host, above code will correct permission denied for root.

Docker - MySQL commands within Dockerfile using RUN (ERROR 2002)

I am using Docker to create a dockerfile with mysql as the base image:
FROM mysql
#set root pass
ENV MYSQL_ROOT_PASSWORD password
#update linux
RUN apt-get update
#create database
RUN mysql -u root -ppassword -e "CREATE DATABASE dbname"
#install vim
RUN apt-get install vim -y
The dockerfile fails on the step where I try to create a database, it doesn't finish building and i receive this error:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'
When I remove the #create database run command the dockerfile will build and I am able to run a container from that image. I know that it isn't a problem with the mysql server as I can enter the container and run the mysql command manually with success and the service status is running.
Using an environment variable i.e MYSQL_ROOT_PASSWORD within the file also allows me to create a database successfully but this will only work with a single database, I need to be able to use the mysql command to make queries, such as creating additional databases / assigning users etc.
This may be because I need to specify the host and port of the docker container but this still does not allow me to connect
RUN mysql -u root -ppassword -h 127.0.0.1 -P 3308 -e "CREATE DATABASE dbname"
Strangely, doing this also often crashes the container and puts it in a state where it will crash again on start-up every time that I try to restart it again.
I think the issue might be that in the service hasn't started within the container used to build your Dockerfile.
Try starting and configuring MySQL server within a single step. As a reference please check this file: https://github.com/dockerfile/mysql/blob/master/Dockerfile
Use below-given commands in your Dockerfile:
RUN service mysql restart && echo 'CREATE DATABASE db_name;' | mysql -uroot -
pYOUR_ROOT_PASSWORD
Had the very same problem: When starting the container and running a set of RUN instructions, or .sh or .sql scripts in /docker-entrypoint-initdb.d/ no connection to the database server could be established.
I found the solution by a comment of #wpalmer on the mysql-image:
The init scripts run by the entrypoint, internally, use the variable "${mysql[#]}" to call mysql (for example, when loading .sql files placed in the docker-entrypoint-initdb.d directory. Any .sh files which are processed by the entrypoint are included by "sourcing" them, meaning that variable is available for use by any .sh files which are run).
So what this means for you, instead of providing the plain mysql command with user, pass etc. as in
RUN mysql -u root -ppassword -e "CREATE DATABASE dbname"
use the placeholder instead:
RUN "${mysql[#]}" -e "CREATE DATABASE dbname"
You can try to build other image and run the create DB from there.
Example of docker-compose.yml
web:
build: web
links:
- "db:db.local"
entrypoint: entrypoint.sh
db:
build: db
environment:
MYSQL_ROOT_PASSWORD: password
command: mysqld
For entrypoint.sh you put something like this:
#!/bin/sh
#this is a hack to wait until the DB image is up and the port is open
until mysqladmin -u root -ppassword -e -h db.local ping; do
echo "$(date) - waiting for mysql"
sleep 3
done
if ! mysql -u root -ppassword -e -h db -e 'use dbname'; then
mysql -u root -ppassword -e "CREATE DATABASE dbname"
fi
exec "$#"
You can copy your queries as .sql file into "/docker-entrypoint-initdb.d" container directory. mysql will execute them after starting container
COPY ./init/db.sql /docker-entrypoint-initdb.d/
read official doc https://hub.docker.com/_/mysql?tab=description&page=1
Initializing a fresh instance