Docker-based Multiple MySQL

Preparing a MySQL multiple-server test environment using Docker images.

In a previous article, I showed how I build a Docker-based MySQL Test Environment when testing out various MySQL features. In this article, I will expand on this and prepare three separate MySQL instances, each with their own persistent data directories which will survive a full Docker image re-build, and connect them together in a regular MySQL replication topology of primary and two read-only replicas.

Folder structure

Assuming you already have Docker installed on your machine (go here if you have not yet done this), create the following folder structure as shown below.

$ tree -d test
test
└── data
    ├── mysql1
    ├── mysql2
    └── mysql3

All the files we create for this test environment will go inside the test folder, and all the MySQL data files for the test instances will be stored within the data/mysqlx folders.

Docker parameter file

Create a file in the test folder called docker-compose.yml containing the following content. This file defines three separate Docker containers based on the same starting MySQL image (mysql:5.7). Each of these containers will mount the data folders under the data folder into the default data file location for MySQL on each of the containers when they are created. They all use the same default password for the root user, and have sequential ports (33061 to 33063) mapped to allow access from the host machine.

version: '2'
services:

  # --------------------------------------------------------------
  mysql1:
    image: mysql:5.7
    container_name: mysql-test-1
    volumes:
      - ./data/mysql1:/var/lib/mysql
    environment:
      - "MYSQL_ROOT_PASSWORD=secret"
    ports:
        - "33061:3306"

  # --------------------------------------------------------------
  mysql2:
    image: mysql:5.7
    container_name: mysql-test-2
    volumes:
      - ./data/mysql2:/var/lib/mysql
    environment:
      - "MYSQL_ROOT_PASSWORD=secret"
    ports:
        - "33062:3306"

  # --------------------------------------------------------------
  mysql3:
    image: mysql:5.7
    container_name: mysql-test-3
    volumes:
      - ./data/mysql3:/var/lib/mysql
    environment:
      - "MYSQL_ROOT_PASSWORD=secret"
    ports:
        - "33063:3306"

Build and run

From within the test folder, you can now fire up this environment by downloading the MySQL 5.7 Docker image (if required) and starting up the three containers in background ‘daemon’ mode.

$ docker-compose up -d
Creating network "test_default" with the default driver
Pulling mysql1 (mysql:5.7)…
5.7: Pulling from library/mysql
d599a449871e: Pull complete
f287049d3170: Pull complete
08947732a1b0: Pull complete
96f3056887f2: Pull complete
871f7f65f017: Pull complete
1dd50c4b99cb: Pull complete
5bcbdf508448: Pull complete
02a97db830bd: Pull complete
c09912a99bce: Pull complete
08a981fc6a89: Pull complete
818a84239152: Pull complete
Digest: sha256:5779c71a4730da36f013a23a437b5831198e68e634575f487d37a0639470e3a8
Status: Downloaded newer image for mysql:5.7
Creating mysql-test-1 … done
Creating mysql-test-3 … done
Creating mysql-test-2 … done

This will automatically start three instances of MySQL, which will, in turn, create all the necessary folders and files required in the data folders to allow these instances to run.

$ tree -d data
data
├── mysql1
│   ├── mysql
│   ├── performance_schema
│   └── sys
├── mysql2
│   ├── mysql
│   ├── performance_schema
│   └── sys
└── mysql3
    ├── mysql
    ├── performance_schema
    └── sys

You can also confirm the running MySQL containers with the following command, showing the base image used and what ports are mapped to each of the containers.

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                NAMES
9966a7c53eca        mysql:5.7           "docker-entrypoint.s…"   11 hours ago        Up 11 hours         33060/tcp, 0.0.0.0:33061->3306/tcp   mysql-test-1
ed2625f793ed        mysql:5.7           "docker-entrypoint.s…"   11 hours ago        Up 11 hours         33060/tcp, 0.0.0.0:33063->3306/tcp   mysql-test-3
b6d37464375e        mysql:5.7           "docker-entrypoint.s…"   11 hours ago        Up 11 hours         33060/tcp, 0.0.0.0:33062->3306/tcp   mysql-test-2

Testing

You can see that each of the containers has the port 33060/tcp open, and an additional port has been opened on each container that is mapped to the regular MySQL port 3306. This allows us to connect to each of the MySQL instances using an address such as localhost:33061.

$ mysqlsh --sql -h localhost -P 33061 -u root -psecret
mysqlsh: [Warning] Using a password on the command line interface can be insecure.
Creating a session to 'root@localhost:33061'
Fetching schema names for autocompletion... Press ^C to stop.
Your MySQL connection id is 7
Server version: 5.7.28 MySQL Community Server (GPL)
No default schema selected; type \use <schema> to set one.
MySQL Shell 8.0.12

Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type '\help' or '\?' for help; '\quit' to exit.


 MySQL  localhost:33061 ssl  SQL > show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.0174 sec)

I wouldn’t normally supply the password on the command line using -p{password} as it would be stored in the shell history and visible on the system process list, but as this is just a test environment, I’m happy to do so.

Stop and clean-up

When you are happy that everything is working as expected, stop the Docker container by running the following command. This helps to free up resources on your host machine – many times I’ve realised I’ve still got a number of Docker containers still running that I’d forgotten about 🙂

$ ./docker-stop.sh
Stopping mysql-test-1 ... done
Stopping mysql-test-3 ... done
Stopping mysql-test-2 ... done
Removing mysql-test-1 ... done
Removing mysql-test-3 ... done
Removing mysql-test-2 ... done
Removing network test_default

The next post in this series will add regular replication configuration between the hosts, and updates to the Docker compose file to supply tailored MySQL configuration files to each of the containers so that they will work as intended.

Leave a Reply

%d bloggers like this: