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.
So I'm writing an install script and because I haven't been able to find a solid MySQL replacement on armfh (the db must be MySQL compatible), I'm using a community on that works, however it does not initiate the db as it should. it requires me to pass the following argument.
mysql -h"db" -u"root" -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < /docker-entrypoint-initdb.d/1_db.sql
From inside the docker. Problem is I want this to flow naturally as a smooth install script. I've tried using the following command to pass the document and get a password prompt:
docker exec -it db bash -c "mysql -h"db" -u"root" -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < /docker-entrypoint-initdb.d/1_db.sql"
If also tried:
docker exec -it db bash -c "mysql -h'db' -u'root' -p'$MYSQL_ROOT_PASSWORD' '$MYSQL_DATABASE' < /docker-entrypoint-initdb.d/1_db.sql
FwIW: I used the MYSQL_ROOT_PASSWORD=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1) to define the password. And if I manually enter the docker send command 1 (in quotations) the db initiates.
So to summarize my question: Is it possible to pass a command like the above to activate the 1_db.sql file from outside docker?
Any help would be amazing! Thanks in advance!
Is it possible to pass a command like the above to activate the
1_db.sql file from outside docker?
you can try something like
cat 1_db.sql | docker exec -i test bash -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD $MYSQL_DATABASE'
also, remember when you try exec bash -c "mysql -uroot -p$MYSQL_ROOT_PASSWORD"it will for MYSQL_ROOT_PASSWORD in the host, not inside container, use single quotes.
determined $MYSQL_ROOT_PASS to MySQL docker from outside docker? If so
how?
docker exec -i test bash -c 'echo mysql docker password is $MYSQL_ROOT_PASSWORD'
I have this bash script:
#!/bin/bash
docker-compose up -d
# wait for the database to come up
until mysqlshow --user=root -h localhost -P 3306 --protocol=tcp > /dev/null 2>&1; do
echo "Waiting for mysql container..."
sleep 0.5
done
RESULT=`mysqlshow --user=root -h localhost -P 3306 --protocol=tcp payments| grep -o payments`
if ! [[ $RESULT = *"payments"* ]]; then
./node_modules/.bin/sequelize db:create
fi
./node_modules/.bin/sequelize db:migrate
yarn start
The above does work but it requires mysql to be installed locally which sort of defeats the purpose of using docker.
Is there a better way:
I can check the db is up without using mysql.
I can run a create script perhaps in the container when it starts to create the db if it does not exist.
There is no shame in having tools installed on your host. These have the advantage of using your local native filesystem without weird remapping tricks and not requiring root privilege to run. Your script is fine as it is; it does not defeat the purpose of Docker at all.
One "more Dockery" approach you can take to this, particularly if you always want to run the migrations, is to move the last half of this into an ENTRYPOINT script in your application container. I might write a script like:
#!/bin/sh
if [ -n "$MYSQL_HOST" -a -z "$SKIP_DB_SETUP" ]; then
# TODO: write Node code that waits until a database connection succeeds
./node_modules/.bin/sequelize db:create || true
./node_modules/.bin/sequelize db:migrate
fi
exec "$#"
and use that as the ENTRYPOINT of my image.
I'm running a script I have created that downloads and installs WordPress. To save more time I wanted to open MAMP MYSQL and create a new database like so:
/Applications/MAMP/Library/bin/mysql --host=localhost -uroot -proot
CREATE DATABASE $1; // passed into the function as argument
exit; // to get out of MYSQL
The rest of my function:
wordpress() {
cd /Volumes/example/example/Web/dev; mkdir $1;
cd $1;
curl -O https://wordpress.org/latest.tar.gz;
tar -xvzf latest.tar.gz;
mv wordpress/* .;
rmdir wordpress/;
rm latest.tar.gz;
cp wp-config-sample.php wp-config.php;
vim -s /Volumes/example/example/Web/dev/db_overwrite.txt wp-config.php;
curl -O https://downloads.wordpress.org/plugin/wp-super-cache.latest-stable.zip;
curl -O https://downloads.wordpress.org/plugin/wp-migrate-db.latest-stable.zip;
curl -O https://downloads.wordpress.org/plugin/contact-form-7.latest-stable.zip;
curl -O https://downloads.wordpress.org/plugin/wordpress-seo.latest-stable.zip
mv wp-super-cache.latest-stable.zip wp-migrate-db.latest-stable.zip contact-form-7.latest-stable.zip wordpress-seo.latest-stable.zip wp-content/plugins;
cd wp-content/plugins;
cp /Volumes/example/example/Web/Plugins/advanced-custom-fields-pro.zip .
unzip advanced-custom-fields-pro.zip;
unzip wp-super-cache.latest-stable.zip;
unzip wp-migrate-db.latest-stable.zip;
unzip contact-form-7.latest-stable.zip;
unzip wordpress-seo.latest-stable.zip;
rm wp-super-cache.latest-stable.zip wp-migrate-db.latest-stable.zip contact-form-7.latest-stable.zip wordpress-seo.latest-stable.zip;
cd ../themes;
git clone https://github.com/example/my-template;
}
How would I add the MYSQL lines to this function and make it work as intended?
Thanks
Why not use:
/Applications/MAMP/Library/bin/mysqladmin -uroot -proot create mydatabase
mysqladmin is a command-line tool that is part of the standard MySQL client software. It should be present everywhere that the mysql tool is present.
You might like to read https://dev.mysql.com/doc/refman/5.7/en/mysqladmin.html
Another alternative is to pass the CREATE DATABASE as an argument to mysql:
/Applications/MAMP/Library/bin/mysql ... -e "CREATE DATABASE mydatabase"
I have followed the instruction in https://registry.hub.docker.com/_/mysql/ to pull an image and running a container in which it runs a MySQL server.
The container is running in the background and I would like to run some commands.
Which is the best way to connect to the container and execute this command from command line?
Thanks.
You can connect to your mysql container and run your commands using:
docker exec -it mysql bash -l
(Where mysql is the name you gave the container)
Keep in mind that anything you do will not persist to the next time your run a container from the same image.
docker exec -i some_mysql_container mysql -uroot -ppassword <<< "select database();"
To connect to the MySQL database using MySQL command line client.
I connect to the bash into the running MySQL container:
$ docker exec -t -i container_mysql_name /bin/bash
-i is the shortcut for --interactive option. This options is used for keep STDIN open even if not attached
-t is the shortcut for --tty option, used to allocate a pseudo-TTY
I run MySQL client from bash MySQL container:
$ mysql -uroot -proot
-u is shortcut for --user=name option, used to define user for login if not current user.
-p is shortcut for -password[=name] option, used to define password to use when connecting to server. If password is not given it's asked from the tty.
Disco!
In my case the <<< solution did not work.
Instead I used -e.
Example:
docker exec ${CONTAINER_NAME} mysql -u ${USER_NAME} -p${PASSWORD} -e "drop schema test; create schema test;"
For #Abdullah Jibaly solution, after tested in MySQL 5.7, it would only entered into bash terminal prompt, whereby you still need to enter mysql command second time.
In order to directly enter into MySQL command line client after run MySQL container with one line of command, just run the following:
docker exec -it container_mysql_name mysql -u username -p
Its possible with docker run, start a new container just to execute your mysql statement.
This approach helped me to workaround the access denied problem when you try to run a statement with docker exec using localhost to connect to mysql
$ docker run -it --rm mysql mysql -h172.17.0.2 -uroot -pmy-secret-pw -e "show databases;"
I use the following to create a command that will sort out at least a couple of cases with databases outside or inside the container (with -h and -P) and supporting -e:
cat > ~/bin/mysql <<'EOF'
#/bin/bash
MARGS=()
MPORT="3306"
while test $# != 0; do
if [[ $1 == -h ]]; then MHOST=$2; shift;
elif [[ $1 == -h* ]]; then MHOST=${1#"-h"};
elif [[ $1 == -e ]]; then MEXEC=$2; shift;
elif [[ $1 == -e* ]]; then MEXEC=${1#"-e"};
elif [[ $1 == --execute=* ]]; then MEXEC=${1#"--execute="};
elif [[ $1 == -P ]]; then MPORT=$2; shift;
elif [[ $1 == -P* ]]; then MPORT=${1#"-P"};
else MARGS="$MARGS $1"
fi
shift;
done
if [ -z "${MHOST+x}" ]; then
MHOST=localhost
fi
if [ $(docker inspect --format '{{ .State.Status }}' mysql) == "running" ]; then
if [ ! -z "${MHOST+x}" ]; then
if [ "$MHOST" == "localhost" -o "$MHOST" == "127.0.0.1" ]; then
CPORT=$(docker port mysql 3306/tcp)
if [ ${CPORT#"0.0.0.0:"} == $MPORT ]; then
#echo "aiming for container port ($MPORT -> $CPORT)";
MHOST=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mysql);
else
MHOST=$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p' | head -1);
fi
fi
fi
fi
if [ -z "$MEXEC" ]; then
docker run --link mysql:mysql -i --rm mysql mysql "-h" $MHOST "-P" $MPORT $MARGS
else
docker run --link mysql:mysql -i --rm mysql mysql "-h" $MHOST "-P" $MPORT $MARGS <<< $MEXEC
fi
EOF
chmod +x ~/bin/mysql
i didn't find any of these solutions to be effective for my use case: needing to store the returned data from the SQL to a bash variable.
i ended up with the following syntax when making the call from inside a bash script running on the host computer (outside the docker mysql server), basically use 'echo' to forward the SQL statement to stdin on the docker exec command.
modify the following to specify the mysql container name and proper mysql user and password for your use case:
#!/bin/bash
mysqlCMD="docker exec -i _mysql-container-name_ mysql -uroot -proot "
sqlCMD="select count(*) from DBnames where name = 'sampleDB'"
count=`echo $sqlCMD | $mysqlCMD | grep -v count`
# count variable now contains the result of the SQL statement
for whatever reason, when i used the -e option, and then provided that string within the back-quotes, the interpreter modified the quotation marks resulting in SQL syntax failure.
richard