This is a continuation of our previous post regarding a simple application running inside a Docker container. This post focuses on the database part of the application stack. Yes, we run the database in a separate container!
MariaDB
I’m using CentOS 7 in all of my Docker images, therefore, we get MariaDB as our default database. I actually prefer MariaDB so this is a good default for me. MariaDB is a fork of MySQL with equally active community and probably more active development compared to Oracle’s MySQL.
Prepare Files
We will still be using Supervisord to launch MariaDB. We need to prepare the following files.
Let’s organize a bit.
mkdir /path/to/docker-build cd /path-to-docker-build
Then put all the files inside that directory.
File: config_mariadb.sh
This file prepares the database and database credentials. This script is run on build process. Don’t forget to change database names/users/passwords.
#!/bin/bash __mysql_config() { # Hack to get MySQL up and running... I need to look into it more. echo "Running the mysql_config function." #yum -y erase community-mysql community-mysql-server #rm -rf /var/lib/mysql/ /etc/my.cnf #yum -y install community-mysql community-mysql-server mysql_install_db chown -R mysql:mysql /var/lib/mysql /usr/bin/mysqld_safe & sleep 10 } __start_mysql() { echo "Running the start_mysql function." mysqladmin -u root password foobar mysql -uroot -pfoobar -e "CREATE DATABASE genericdb" mysql -uroot -pfoobar -e "GRANT ALL PRIVILEGES ON genericdb.* TO 'genericdb'@'localhost' IDENTIFIED BY 'genericdb'; FLUSH PRIVILEGES;" mysql -uroot -pfoobar -e "GRANT ALL PRIVILEGES ON genericdb.* TO 'genericdb'@'%' IDENTIFIED BY 'genericdb'; FLUSH PRIVILEGES;" mysql -uroot -pfoobar -e "GRANT ALL PRIVILEGES ON *.* TO 'genericdb'@'%' IDENTIFIED BY 'genericdb' WITH GRANT OPTION; FLUSH PRIVILEGES;" mysql -uroot -pfoobar -e "GRANT ALL PRIVILEGES ON *.* TO 'genericdb'@'%' IDENTIFIED BY 'genericdb' WITH GRANT OPTION; FLUSH PRIVILEGES;" mysql -uroot -pfoobar -e "select user, host FROM mysql.user;" killall mysqld sleep 10 } # Call all functions __mysql_config __start_mysql
File: start.sh
Starts the database daemon every time the docker container is started.
#!/bin/bash __run_supervisor() { echo "Running the run_supervisor function." supervisord -n } # Call all functions __run_supervisor
File: supervisor-mariadb.ini
Supervisord configuration to start MariaDb.
[program:mariadb] command=/usr/bin/mysqld_safe stdout_logfile=/var/log/supervisor/%(program_name)s.log stderr_logfile=/var/log/supervisor/%(program_name)s.log autorestart=true
File: Dockerfile
Of course the Dockerfile.
FROM centos:centos7 MAINTAINER Leonel Baer <leonel@lysender.com> RUN yum -y update && yum clean all RUN yum -y install epel-release && yum clean all RUN yum -y install mariadb-server bind-utils pwgen supervisor psmisc \ net-tools hostname && yum clean all ADD ./start.sh /start.sh ADD ./config_mariadb.sh /config_mariadb.sh ADD ./supervisor-mariadb.ini /etc/supervisord.d/mariadb.ini RUN chmod 755 /start.sh RUN chmod 755 /config_mariadb.sh RUN /config_mariadb.sh VOLUME ["/var/lib/mysql", "/var/log/mariadb"] EXPOSE 3306 CMD ["/bin/bash", "/start.sh"]
In this Dockerfile, we only installed the softwares we need to run a MariaDB server.
Build and run
Let’s build it now. We will name our image as generic-mariadb
.
cd /path-to-docker-build docker build --rm -t generic-mariadb .
At this point, things are a bit complicated. Yes, we can run MariaDB in the container we are about to create, but we need to allow data to persist on this container. We have some options:
- Store data on the same container as the MariaDB container.
- Store data outside the container via another container called volumne container.
- Store data outside the container via host’s directory.
I based my style on this document, that is, to store data into another volumne called volume container. This way, the data is not dependent on the running MariaDB container. We can update the container or modify the image, re-run, destroy, re-run again without affecting our data.
We already have an image called generic-mariadb
but we haven’t created a container yet. Let’s create a volumne container first instead.
docker run --name=mariadb-data -v /var/lib/mysql -v /var/log/mariadb generic-mariadb true
What it does is create a container named mariadb-data
using the image generic-mariadb
then run the true
command. It does not daemonize the container though, which is what we need since it will only need to store the data and not actually run. The effect of this command is to create a container and exit at the end. If you run docker ps
, you won’t see the container running.
Next, let’s prepare the volume container by preparing it’s MariaDB instance by running the initialize script.
docker run --rm --volumes-from=mariadb-data generic-mariadb /config_mariadb.sh
The command above executes the config_mariadb.sh
script against the mariadb-data
volume container using the generic-mariadb image, although we can use any image. We pass --rm
to delete any intermediate containers since we don’t need them. It will exit at the end as well since we don’t want to daemonize it.
Now, I’m not sure why we need this though. We already prepared the data when we run the build script. Isn’t it already stored in the image? Anyway, this is based on a guide I’ve read somewhere to create a production setup. Maybe we have a different Dockerfile strategy? Anyway, just run it as it will just re-initialize the initial data.
Just don’t delete the mariadb-data
container though.
Finally, we are now ready to create our final container. With this container, it uses the volumes from mariadb-data
to store data for /var/lib/mysql
and /var/log/mariadb
as defined in Dockerfile.
docker run --name=mariadb -d -p 3306:3306 --volumes-from=mariadb-data generic-mariadb
This time, we created the container mariadb
and run it as a daemon. It uses the volumes from mariadb-data
that we’ve just prepared. We used the same port 3306
. Let’s try loggin in.
mysql --port 3306 --protocol tcp -u genericdb -pgenericdb
That’s it! We now have a database server on a Docker container. My upcoming post would be about linking a database server container to a PHP application.
MariaDB Image
You may want to re-use my existing MariaDB image at: https://hub.docker.com/r/lysender/mariadb/.
docker run --name=mariadb-data -v /var/lib/mysql -v /var/log/mariadb lysender/mariadb true docker run --rm --volumes-from=mariadb-data lysender/mariadb /config_mariadb.sh docker run --name=mariadb -d -p 3306:3306 --volumes-from=mariadb-data lysender/mariadb
Then you can login to the container and change the default root password.
docker exec -it mariadb bash > mysqladmin -u root password L0lCatMe0w
You may also want to change the database users/passwords but it might be better to create your own Dockerfile instead.
My upcoming post would be about linking a database server container to a PHP application.
wen will it be posted??
That’s a very long overdue… 😀 I’ll see if I can do it over the weekend.
anyways was very useful..please post it soon.
i want mysql server ..not able to do that..tried with mariadb …but
got error..saying..”mysql command not found”.
I have an Ubuntu 16.04 build for MySQL: https://github.com/lysender/docker-mysql
But still too lazy to blog about it. Anyway, I’ll see if I can create part 3 this weekend.