Run multiple MySQL versions in Docker on Linux

Docker is a container-based virtualisation system that makes it possible to run software separated from the host operating system. Each container sees its own isolated environment only and it’s also possible to run multiple container instances of the same software.

As an example, we’ll use Debian Linux but Docker is available on most (if not all) Linux flavors so it should be pretty easy to find instructions on how to install it elsewhere.

Installing Docker on Debian

Docker packages are available from the own repository, available here: https://download.docker.com/linux/debian/.

Most Debian versions are supported (from Wheezy to Bullseye), but older ones may not receive frequent updates (if any..) anymore.

To use them you can either directly download the packages and install them using “dpkg -i” or add this as a repository and use Debian’s own package management system for installation. This is also very useful to manage updates because otherwise, you’ll need to manually download and install each update on your own.

To add them to the repository, first, we need to make sure that a few system packages are installed, that will help us set up the new repository.

# apt-get install apt-transport-https ca-certificates curl gnupg lsb-release

Most of these should already be on your system, there is no harm done in running this again – it will simply ignore packages that are already installed.

Next, we’ll need to install their GPG key that is used to sign these repositories. This is automatically used to verify the authenticity of the packages and won’t let you install anything that’s not signed by the Docker developers.

The command below will download the GPG key, extract it and save it under /usr/share/keyrings

#  curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Once that is done, we need to add the repository to the Debian package management system by adding a new file under /etc/apt/souces.list.d:

# echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list

The only magic in this command is automagically putting the right relese after the repo url, so it will look like this (in our example we’re running this on Debian Stretch:

# cat /etc/apt/sources.list.d/docker.list 
deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian stretch stable

Now, that the new repository is set up, we can siply install Docker by running an apt-get update / apt-get install:

# apt-get update
# apt-get install docker-ce docker-ce-cli containerd.io

Docker should be now installed and ready to use.

Installing multiple MySQL versions

Oracle (the current developer of MySQL) provides officially supported MySQL containers for Docker. Currently, there are two supported versions, 5.7 and 8.0. Older software may not run well on 8.0 so it’s useful to have the capability of running different MySQL versions at the same time.

Running them isolated inside the host system also adds an extra layer of security because container applications have access to their container environment only. It’s also possible to completely separate MySQL installations and run multiple instances (at the cost of system memory required). This way, any security issue with MySQL will be better contained and affect the local container only.

To download MySQL container templates, run the following command. It will connect to the Docker container repository and fetch them, they are around 300-350MB each. These files will be saved under /var/lib/docker.

# docker pull mysql/mysql-server:5.7
# docker pull mysql/mysql-server:8.0

You can verify that they were downloaded by running “docker images”

# docker images
REPOSITORY           TAG  IMAGE ID       CREATED        SIZE
mysql/mysql-server   5.7  213f41471c5e   2 weeks ago    366MB
mysql/mysql-server   8.0  1504607f1ce7   2 weeks ago    391MB

These images function as templates for running containers that we’ll create later. Container images will contain only the differences from the templates so creating multiple containers won’t use much space initially because they are pretty similar to the original template image itself.

Now that we got the images, let’s create a container and run the first MySQL daemon (version 5.7). We’ll name the instance “mysql57”. The image would also be downloaded automatically had if we hadn’t run “docker pull” earlier.

# docker run --name mysql57 mysql/mysql-server:5.7

You’ll see a lot of messages as the container is being created and ran for the first time. It will automatically generate a new root password, look for the line “GENERATED ROOT PASSWORD”. You can see it again later by running “docker logs mysql57”.

# docker logs mysql57 2>&1 | grep GENERATED
[Entrypoint] GENERATED ROOT PASSWORD: therootpasswordishere

This command by default will run in the foreground, you can “-d” to run in the background. Let’s run another one, this time based on 8.0:

# docker run -d --name mysql8 mysql/mysql-server:8.0

Now we got two MySQL versions running, each one in its separate environment:

# docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED              STATUS                             PORTS                       NAMES
8f6872e916cc        mysql/mysql-server:8.0   "/entrypoint.sh mysq…"   44 seconds ago       Up 43 seconds (health: starting)   3306/tcp, 33060-33061/tcp   mysql8
86cce0f48bd4        mysql/mysql-server:5.7   "/entrypoint.sh mysq…"   About a minute ago   Up About a minute (healthy)        3306/tcp, 33060/tcp         mysql57

Autostarting Docker containers

Once we reboot our server, Docker images won’t autostart, because by default they are not set up to do so. There are multiple ways to autostart Docker services and it’s important to avoid mixing different ways because it may create system conflicts.

The cross-platform way to do so is to simply edit the Docker image and set up a restart policy to automatically start them. This can be done by running a “docker container update” command as follows:

# docker container update --restart unless-stopped mysql57
# docker container start mysql57 # <-- if it wasn't running..

This way containers are automatically restarted at boot unless they were stopped before. It’s also possible to set a restart policy by adding the same “–restart unless-stopped” parameter to the initial “docker run” command that creates the container.

Change the root password on new containers

Before you can use these MySQL installations, you’ll need to update the root password on each. Remember, they were automatically set to a random string that’s accessible by using the “docker logs” command.

To do this, we’ll need to run “mysql” inside the running container then update the password by running an “alter user” before we could do anything.

The “mysql” command is interactive, so you’ll need to run it by attaching the terminal to the container in interactive mode (-t -i) when executing mysql:

# docker logs mysql8 2>&1 | grep GENERATED
[Entrypoint] GENERATED ROOT PASSWORD: passwordhere
root@lampdev:/home/diab# docker exec -it mysql8 mysql -p --connect-expired-password
Enter password: passwordhere
...
mysql> alter user root@localhost identified by 'newpassword1234';

And with this, you’ve completed the basic installation of multiple MySQL daemons in Linux Docker containers.

Related Posts