Application running on Docker container – Part 2 – Database

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.

This entry was posted in Database, Linux, Web Development and tagged , , . Bookmark the permalink.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *