Set up MySQL using Dockerfile - mysql

I'm just getting started with Docker and was able to set up MySQL according to my needs, by running tutum/lamp and doing a bunch of exec. For example:
docker run -d -p 80:80 -p 3306:3306 --name test tutum/lamp
...
docker exec test mysqldump --host somehost --user someuser --password --databases somedatabase > dump.sql
docker exec test mysql -u root < dump.sql
However, I'm having issues converting this to a Dockerfile. Specifically, the following results in ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock':
FROM tutum/lamp
EXPOSE 80 3306
...
RUN mysqldump --host=$DB_IP --user=$DB_USER --password=$DB_PASSWORD --databases somedatabase > dump.sql
RUN mysql -u root < dump.sql

You will need to override run.sh in order to do that, because when you run a container it will install mysql for the first time.
That is why you can not connect to mysql prior to that (in my previous answer I wasn't aware of that).
I've managed to execute mysql command by adding this to Dockerfile
FROM tutum/lamp
ADD . /custom
RUN chmod 755 /custom/run.sh
CMD ["/custom/run.sh"]
Then in the same folder create a file run.sh
#!/bin/bash
VOLUME_HOME="/var/lib/mysql"
sed -ri -e "s/^upload_max_filesize.*/upload_max_filesize = ${PHP_UPLOAD_MAX_FILESIZE}/" \
-e "s/^post_max_size.*/post_max_size = ${PHP_POST_MAX_SIZE}/" /etc/php5/apache2/php.ini
if [[ ! -d $VOLUME_HOME/mysql ]]; then
echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME"
echo "=> Installing MySQL ..."
mysql_install_db > /dev/null 2>&1
echo "=> Done!"
/create_mysql_admin_user.sh
else
echo "=> Using an existing volume of MySQL"
fi
( sleep 20 ; mysql -u root < /custom/dump.sql ; echo "*** IMPORT ***" ) &
exec supervisord -n
This file is the same as /run.sh with one line added to run sql import after 20 seconds to make sure mysql service is up and running (there must be more elegant way to run a command just after mysql is started, of course).

Related

mysql command not found in docker bash shell script

I have a shell script that copies a .sql script to a docker container and executes it.
When I execute the line:
docker exec -it $existingMySQLContainer bash -c '"mysql -u root -proot < setup_db.sql"'
on my host machine outside of the script, it works. But when I execute it from within the script, I get:
bash: mysql -u root -proot < setup_db.sql: command not found
Why doesn't this work within the script?
Script:
#!/bin/sh
# check to see if the container with the name exists.
existingMySQLContainer=$(docker ps -a -q -f name="local-test-mysql-db")
if [ ! -z "$existingMySQLContainer" ]
then
# conatiner has been found so tear it down for a clean database
echo "Found existing local test db " $existingMySQLContainer
docker rm -f $existingMySQLContainer
fi
docker run --name local-test-mysql-db -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=root mysql:8
# run the docker container
existingMySQLContainer=$(docker ps -a -q -f name="local-test-mysql-db")
docker cp setup_db.sql $existingMySQLContainer:/setup_db.sql
docker exec -it $existingMySQLContainer bash -c '"mysql -u root -proot < setup_db.sql"'
I tried arranging the double quotes in various ways and no success.
Removing the doubles quotes to give just
Removing doubles quotes so the last line is:
ocker exec -it $existingMySQLContainer bash -c '"mysql -u root -proot < setup_db.sql"'
gives:
bash: mysql -u root -proot < setup_db.sql: command not found
SOLUTION
Docker MySQL just hadn't finished loading yet. I was trying to access it before it had finished loading.

Bash: file not created with '>' command

I'm writing a script to create backups of a MySQL database running in a docker container. The database is correctly up and running.
My current code is
#!/bin/bash
PATH=/usr/bin:/usr/local/bin:/root/.local/bin:$PATH
docker-compose exec -T db mkdir -p /opt/booking-backup
docker_backup_path="/opt/booking-backup/dump_prod_$(date +%F_%R).sql"
copy_backup_path="/root/backup_scripts/booking_prod/dump_prod_$(date +%F_%R).sql"
docker-compose exec db mysqldump --add-drop-database --add-drop-table --user=root --password="pw" booking > "$docker_backup_path"
docker-compose exec db mysqldump --add-drop-database --add-drop-table --user=root --password="pw" booking > "/opt/booking-backup/dump_prod.sql"
[ -d ./backup ] || mkdir ./backup
docker cp $(docker-compose ps -q db):$docker_backup_path $copy_backup_path
However, when I execute it it throws this error:
Error: No such container:path: f0baa241becd20d2690bb901fb257a4bbec8cac17e6f1ce6d50adb9532bbae03:/opt/booking-backup/dump_prod_2019-05-28_14:23.sql
What makes this weirder is that I have the exact same code (but with booking switched out for abc, and with PSQL instead of MySQL) that works correctly.
It appears that this line
docker-compose exec db mysqldump --add-drop-database --add-drop-table --user=root --password="pw" booking > $docker_backup_path
does not create the output file, but when I use tee I can see the contents of the dump and they are correct.
What's going wrong here?
The shell redirections
docker-compose exec db mysqldump ... > "$docker_backup_path"
docker-compose exec db mysqldump ... > "/opt/booking-backup/dump_prod.sql"
# -----------------------------------^ here
... will be expanded by your local shell, not inside the container. Meaning the files are written to your local filesystem not to the container's filesystem.

mysqldump in Jenkinsfile can't connect to server

This is the stage in Jenkinsfile where the problem comes from :
stage ('Build & Run container') {
imageMysql = docker.build('backend-server-mysql-dev', '--no-cache -f build/docker/mysql/Dockerfile .')
containerMysql = imageMysql.run("--name backend-server-mysql-dev -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_ROOT_USER=root -e MYSQL_PASSWORD=mahmoud -e MYSQL_DATABASE=soextremedb")
sh 'docker ps | docker exec -it backend-server-mysql-dev /bin/bash | ls -l | mysqldump -u root -proot soextremedb < soextremedb.sql'
}
This is the error message:
Shell Script -- docker ps | docker exec -it backend-server-mysql-dev /bin/bash | ls -l | mysqldump -u root -proot soextremedb < soextremedb.sql -- (self time 566ms)
[soextremeBackEnd_Dev-MBC6SQWYSNVE6ADN2QOAOGZ4YYVT5E6K7Y2FUP6ROOROWRMCPFOA] Running shell script
+ docker ps
+ docker exec -it backend-server-mysql-dev /bin/bash
+ ls -l
+ mysqldump -u root -proot soextremedb
**mysqldump: Got error: 2002: "Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")" when trying to connect the input device is not a TTY**
I think there are a couple of issues with the sh command.
First, | is used to send the output of one command on to the next command, but it looks like you're just trying to execute a sequence of commands. For that, you can use ; or &&. You might take a look at this answer for a great summary of shell operators.
Then, for your docker exec command, I think you actually want to call a series of commands non-interactively: leave off off the -it and use /bin/bash -c to pass a command string to the shell.
This will give you something like:
sh 'docker ps ; docker exec backend-server-mysql-dev /bin/bash -c "ls -l ; mysqldump -u root -proot soextremedb < soextremedb.sql"'

How to import an existing MySQL-Database in my MySQL-Docker Container?

I have created a docker container based on the official image of MySQL from Docker Hub. It works fine, but I have some troubles with the database import.
My file with the SQL-Instructions is already stored in the folder /docker-entrypoint-initdb.d of my container, but it doesn't work! I have copied my sql-import.sql to /var/lib/docker/volumes/mysql-dump/_data, but I can only see the name of my database when I call "SHOW DATABASES;" within my container. There is no table available when I call "SHOW TABLES FROM myDB;". What can I do to import the content of my MySQL Database?
Here is my Dockerfile:
FROM mysql:5.7
ADD ./init-scripts/*.sql /docker-entrypoint-initdb.d/
ADD ./config/my.cnf /root/
RUN cd /root/ && \
chmod 0600 my.cnf && \
mv my.cnf .my.cnf
ENV MYSQL_DATABASE=regex
ENV MYSQL_ROOT_PASSWORD=mypassword
EXPOSE 3306
There are several methods to import. With docker exec if your contener is running:
Solution 1:
docker exec -i <id_conteneur> /usr/bin/mysql -u <fooUser> -e "CREATE DATABASE mydb"
cat schema.sql | docker exec -i <id_conteneur> /usr/bin/mysql -u <fooUser> --password=<password> <database>
Solution 2:
In a bash script:
#!/bin/bash
/usr/bin/mysqld_safe --skip-grant-tables &
mysql -u <fooUser> -e "CREATE DATABASE mydb"
mysql -u <fooUser> mydb < schema.sql
And add to your DockerFile with Run command:
ADD create_db.sh /tmp/create_db.sh
RUN /tmp/create_db.sh

Can't MariaDB inside docker container

I need to run MariaDB inside existing Docker container.
Building and installation works just fine, but when Docker executes
RUN mysql < init.sql
to load DB schema I get
Can't connect to MySQL server (111 Connection refused)
However when I run the container and execute
docker exec -it silly_allen /bin/bash -c "mysql < init.sql"
it works just fine.
What might be the problem?
Thanks!
EDIT: Here's part of Dockerfile related to DB.
FROM centos:7
WORKDIR /root
...
RUN echo "[mariadb]" >> /etc/yum.repos.d/MariaDB.repo
RUN echo "name = MariaDB" >> /etc/yum.repos.d/MariaDB.repo
RUN echo "baseurl = http://yum.mariadb.org/10.1/centos7-amd64" >> /etc/yum.repos.d/MariaDB.repo
RUN echo "gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB" >> /etc/yum.repos.d/MariaDB.repo
RUN echo "gpgcheck=1" >> /etc/yum.repos.d/MariaDB.repo
RUN rpm --import https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
RUN yum install -y MariaDB-server MariaDB-client
RUN yum clean all
RUN echo "[mysqld]" > /etc/my.cnf
RUN echo "bind-address=0.0.0.0" >> /etc/my.cnf
RUN /etc/init.d/mysql restart
ADD init.sql /root
RUN mysql < /root/init.sql
...
According to Docker's best practices, you should be having 1 container per process that you want to run.
Also, there's an official mariadb image which allows you to mount a directory as volume, that could contain SQL dumps. These dumps are auto-imported when the container gets created, so this might prove to be handy.
I'd suggest instead of having one very large dockerfile, you break it up in separate services with docker-compose
If you do however want to keep this the way it is, I'd suggest you move the ADD init.sql ... part to the top, and concatenate the server starting up part and the dump import, because each RUN command is a separate layer with Docker. So you'd need something like what's described in the answer of this StackOverflow question:
RUN /bin/bash -c "/usr/bin/mysqld_safe &" && \
sleep 5 && \
mysql -u root -e "CREATE DATABASE mydb" && \
mysql -u root mydb < /root/init.sql
So that the server initializes and the dump gets imported in one layer
From what I can see, you are trying to run mysql < init.sql before starting the database. The error shows that this command requires the database to be running.
To solve this problem, add a startup script into you container containing:
mysqld
mysql < init.sql
And change your Dockerfile CMD to call this script.
This way is right:
# cat Dockerfile
...
ADD init.sql /tmp
ADD initdb.sh /tmp
RUN /tmp/initdb.bash
CMD ["/usr/bin/mysqld_safe --datadir=/var/lib/mysql"]
And the script:
# cat dump/initdb.bash
#!/bin/bash
set -e
set -x
mysqld_safe --datadir='/var/lib/mysql' --user=root &
until mysqladmin ping >/dev/null 2>&1; do
sleep 0.2
done
mysql -e 'create database init;' && \
mysql init < /tmp/init.sql && \
echo "Successfully imported" && exit 0