In this tutorial I will show how to set up a MySQL docker container for use by a separate Docker container running Wildfly Application Server. See part 1 of the tutorial on how to set up Docker and create a Wildfly container.
MySQL Docker image
Build a MySQL image based on Debian
Create a Dockerfile like the one below
FROM debian:stretch-slim # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN groupadd -r mysql && useradd -r -g mysql mysql RUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr && rm -rf /var/lib/apt/lists/* # add gosu for easy step-down from root ENV GOSU_VERSION 1.7 RUN set -x \ && apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \ && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \ && wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \ && export GNUPGHOME="$(mktemp -d)" \ && gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \ && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \ && rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc \ && chmod +x /usr/local/bin/gosu \ && gosu nobody true \ && apt-get purge -y --auto-remove ca-certificates wget RUN mkdir /docker-entrypoint-initdb.d RUN apt-get update && apt-get install -y --no-install-recommends \ # for MYSQL_RANDOM_ROOT_PASSWORD pwgen \ # for mysql_ssl_rsa_setup openssl \ # FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db: # File::Basename # File::Copy # Sys::Hostname # Data::Dumper perl \ && rm -rf /var/lib/apt/lists/* RUN set -ex; \ # gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported key='A4A9406876FCBD3C456770C88C718D3B5072E1F5'; \ export GNUPGHOME="$(mktemp -d)"; \ gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \ gpg --export "$key" > /etc/apt/trusted.gpg.d/mysql.gpg; \ rm -rf "$GNUPGHOME"; \ apt-key list > /dev/null ENV MYSQL_MAJOR 5.7 ENV MYSQL_VERSION 5.7.21-1debian9 RUN echo "deb http://repo.mysql.com/apt/debian/ stretch mysql-${MYSQL_MAJOR}" > /etc/apt/sources.list.d/mysql.list # the "/var/lib/mysql" stuff here is because the mysql-server postinst doesn't have an explicit way to disable the mysql_install_db codepath besides having a database already "configured" (ie, stuff in /var/lib/mysql/mysql) # also, we set debconf keys to make APT a little quieter RUN { \ echo mysql-community-server mysql-community-server/data-dir select ''; \ echo mysql-community-server mysql-community-server/root-pass password ''; \ echo mysql-community-server mysql-community-server/re-root-pass password ''; \ echo mysql-community-server mysql-community-server/remove-test-db select false; \ } | debconf-set-selections \ && apt-get update && apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql /var/run/mysqld \ && chown -R mysql:mysql /var/lib/mysql /var/run/mysqld \ # ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime && chmod 777 /var/run/mysqld \ # comment out a few problematic configuration values && find /etc/mysql/ -name '*.cnf' -print0 \ | xargs -0 grep -lZE '^(bind-address|log)' \ | xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/' \ # don't reverse lookup hostnames, they are usually another container && echo '[mysqld]\nskip-host-cache\nskip-name-resolve' > /etc/mysql/conf.d/docker.cnf VOLUME /var/lib/mysql COPY docker-entrypoint.sh /usr/local/bin/ RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat ENTRYPOINT ["docker-entrypoint.sh"] EXPOSE 3306 CMD ["mysqld"]
Download this file and place it in the same directory. Then create the image by executing
sudo docker build -t j-lawyer-mysql-server .
This will give the image the name „j-lawyer-mysql-server“.
Start the image
Replace „secretpwd“ with a password to use for the MySQL root user.
sudo docker run --name j-lawyer-mysql-server -e MYSQL_ROOT_PASSWORD=secretpwd -d mysql:5.7
If you’d like to test the image using a MySQL command line client or to set up databases, execute
sudo docker run -it --link j-lawyer-mysql-server:mysql --rm mysql sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"'
This way, you can create databases and schema objects and execute queries. If you just need a Bash for your MySQL container, do a
docker exec -it j-lawyer-mysql-server bash
Note that the –link switch is deprecated and not to be used for production anymore.
Linking application and database containers
As mentioned, linking containers is deprecated. There are other ways of accomplishing the same thing, e.g. creating a wrapper script that starts multiple services or using supervisord. Personally, I prefer having several lightweight containers instead of one larger, so I will continue with using Docker Compose.
Installing Docker Compose
sudo curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m)-o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Then verify the installation by calling
docker-compose --version
Defining your stack
Create a new directory
mkdir j-lawyer-server-stack
cd j-lawyer-server-stack
Create a stack definition
touch j-lawyer-server-stack.yaml
Edit the file and use the following content:
# Use root/example as user/password credentials version: '3.1' services: db: image: j-lawyer-mysql-server restart: always environment: MYSQL_ROOT_PASSWORD: secret-pwd server: image: j-lawyer-server restart: always ports: - 8000:8080
This will define a stack consisting of a MySQL container „db“ based on „j-lawyer-mysql-server“ and a Wildfly container „server“ based on „j-lawyer-server“. Port 8000 will be exposed for the Wildfly containers port 8080.
Launch the stack
sudo docker-compose -f j-lawyer-server-stack.yaml up
If you fire up http://localhost:8000 you will see the Wildfly welcome page. When executing a
sudo docker container ls
you will see both containers defined in your stack, up and running:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1ce321e41104 j-lawyer-server "/usr/local/j-lawyer…" 8 minutes ago Up 8 seconds 0.0.0.0:8000->8080/tcp j-lawyer-server-stack_server_1 676ced50956c j-lawyer-mysql-server "docker-entrypoint.s…" 8 minutes ago Up 9 seconds 3306/tcp j-lawyer-server-stack_db_1
Now, let’s verify the Wildfly container has access to the MySQL container, by starting a Bash inside the Wildfly container in your stack. Note the container name, taken from the output of the last command:
sudo docker exec -it j-lawyer-server-stack_server_1 bash
The host name of the MySQL container matches the MySQL containers logical name in your stack definition (.yaml), in our case „db“. Let’s see if we can ping this:
ping db
You will see this works. Your MySQL container can be reached from within your Wildfly container.
Next Steps
In this tutorial, parts 1 and 2, we have installed Docker, set up a Wildfly image as well as a MySQL image, and defined a stack combining the two. Everything else is pretty straight forward, e.g.
- Add a datasource configuration for Wildfly in your Wildfly image, pointing to MySQL on the host „db“.
- Add RUN entries in your MySQL image to create a database and some schema objects
- Add COPY entries to your Wildfly image to add e.g. a web application archive (.WAR)