Install MySQL With PhpMyAdmin Using Docker
Do these errors look familiar to you?
MySQLInterfaceError: Can't connect to MySQL server on 'mysql'
mysqli::real_connect(): (HY000/2002): php_network_getaddresses: getaddrinfo failed: Name or service not known
Frustrating, I know.
Why is it so difficult to simply connect to a MySQL database? You could fix it if you delve deep into networking, but who has time for that?
Or maybe you just want to quickly install MySQL, without bloating your machine, and continue working on your application.
By the end of this tutorial, you will have clean installs of MySQL and phpMyAdmin that are configured properly to just work. You'll accomplish this with minimal effort using a single command to start the entire application stack.
Let's get started!
Requirements
You don't need a lot of knowledge or tools to be able to follow along with this tutorial. What you'll need is:
- Docker installed on your machine. The official docs have an installation guide for macOS, Windows and Linux operating systems.
- (Optional) Docker Compose. It comes bundled with Docker Desktop.
Verify you have both installed by typing docker -v
and docker-compose -v
in your terminal. You should see a similar output:
$ docker -v
Docker version 19.03.8, build afacb8b
$ docker-compose -v
docker-compose version 1.25.4, build 8d51620a
Basic experience using the Docker command line is useful, but not required. We'll go over each step in detail and explain what we're doing.
Goals
Without phpMyAdmin or MySQL preinstalled, our goal is to quickly have a local phpMyAdmin webserver running that's connected to a MySQL database. We will download and run both through Docker, and configure them so they can communicate properly.
As a bonus, you will see how to accomplish this with just one file and a single command using Docker Compose.
Step 1 — Installing MySQL
Let's start by installing the MySQL database first. We need to have it up & running before we can connect with phpMyAdmin.
We'll grab the image from the official MySQL repository on Docker Hub using docker pull
command. As of writing, the latest version of MySQL is 8.0.19. If you want to use MySQL 5, that will work as well.
# Download MySQL 8.0.19 image from Docker Hub
docker pull mysql:8.0.19
You should see several progress bars and after a while it should have finished successfully:
Digest: sha256:b69d0b62d02ee1eba8c7aeb32eba1bb678b6cfa4ccfb211a5d7931c7755dc4a8
Status: Downloaded newer image for mysql:8.0.19
docker.io/library/mysql:8.0.19
With the MySQL image downloaded, let's run a container from it with the docker run
command. We'll give the container a name with the --name
flag and have it run in the background with the -d
flag, so we can keep using the same terminal window for subsequent commands.
MySQL requires us to provide a password for the root
database user to start the database. We can do this by assigning the password to the MYSQL_ROOT_PASSWORD
environment variable which we'll pass on to the container. Docker allows you to pass environment variables with the -e
flag. Our command to start MySQL is:
# Start a MySQL container
docker run --name mysql -d -e MYSQL_ROOT_PASSWORD=my-secret-pw mysql:8.0.19
Run this command, and you should see a random and long string displayed. That's the unique ID assigned to the container by Docker. It means MySQL is successfully up and running.
To verify this, we can list all running containers with docker ps
:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e61b2cba425 mysql:8.0.19 "docker-entrypoint.s…" 3 seconds ago Up 3 seconds 3306/tcp, 33060/tcp mysql
Step 2 — Installing phpMyAdmin
Now we're ready to move on to phpMyAdmin. Let's download it from the phpMyAdmin repository on Docker Hub. At the moment of writing, 5.0.2 is the latest version. We'll use the docker pull
command again:
# Download phpMyAdmin 5.0.2
docker pull phpmyadmin/phpmyadmin:5.0.2
After some time, you should see a successful download:
Digest: sha256:46dfe47ca8d3a172e7a203049bd33f516b179dc4a7205a88a97ba0bf9fc94c11
Status: Downloaded newer image for phpmyadmin/phpmyadmin:5.0.2
docker.io/phpmyadmin/phpmyadmin:5.0.2
Similarly to MySQL, we run this container with the --name
and -d
flags. We give it a different name because container names have to be unique.
phpMyAdmin uses the PMA_HOST
environment variable to know where to connect to the MySQL database. We set this variable to be equal to the MySQL container name, namely mysql
. I explain why in the next section, where we will create a Docker network.
Moreover, we're going to map port 8080 on the host to port 80 inside the container. The host is simply the operating system where you've installed Docker. Mapping a port from the host to the container means that when we go to localhost:8080
(in the browser for example), we want that to point to port 80 inside the phpMyAdmin container. To map a port, we use the -p
flag, and the syntax is -p <HOST_PORT>:<CONTAINER_PORT>
.
Let's see all of the above in action:
# Start a phpMyAdmin container
docker run --name phpmyadmin -d -p 8080:80 -e PMA_HOST=mysql phpmyadmin/phpmyadmin:5.0.2
We use port 80 because that's the port the phpMyAdmin web server is listening on for incoming requests. Port 8080 on the host is chosen randomly and doesn't have a particular meaning. We could've used any available port on the host.
Let's verify both containers are running side to side with docker ps
:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8980917d10d0 phpmyadmin/phpmyadmin:5.0.2 "/docker-entrypoint.…" 38 minutes ago Up 38 minutes 0.0.0.0:8080->80/tcp phpmyadmin
4e61b2cba425 mysql:8.0.19 "docker-entrypoint.s…" 2 hours ago Up 2 hours 3306/tcp, 33060/tcp mysql
Step 3 — Creating a Docker network
There is one last thing left for us to do before we can navigate to the phpMyAdmin dashboard. At this point, phpMyAdmin can't connect to MySQL because the mysql
hostname we used in the previous step doesn't translate to the IP address of the MySQL container.
Translating hostnames to IP addresses is called DNS resolution. Fortunately, Docker provides DNS resolution out of the box when we create a network. All containers inside that network will be able to communicate with each other using their names. Let's create a network:
# Create a Docker network
docker network create my-network
Now, let's connect both MySQL and phpMyAdmin containers to this network.
# Connect MySQL and phpMyAdmin containers to our network
docker network connect my-network mysql
docker network connect my-network phpmyadmin
You won't see anything printed out in the console, which is good. It means both containers are now part of our network and can communicate with each other using their names.
Navigate to localhost:8080
in your browser, and log in with username: root
and password: my-secret-pw
. You should now be inside the phpMyAdmin dashboard. Hooray 🎉.
Step 4 — (Bonus) Using Docker Compose
Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use one file to configure all of your application's containers. Then, with a single command, you create and start all containers from your configuration. In our case, the application stack is two containers and a network that connects them.
The naming convention for the configuration file is docker-compose.yml
. Inside the file, containers are defined as services
. Let's combine all the steps from this tutorial and put them in a single file:
# We're using version 3.7 of the Docker Compose file format
version: "3.7"
# Define services/containers
services:
# MySQL container
mysql:
# Use mysql:8.0.19 image
image: mysql:8.0.19
# Connect to "my-network" network, as defined below
networks:
- my-network
# Pass a list of environment variables to the container
environment:
MYSQL_ROOT_PASSWORD: my-secret-pw
# phpMyAdmin container
phpmyadmin:
# Use phpmyadmin/phpmyadmin:5.0.2 image
image: phpmyadmin/phpmyadmin:5.0.2
# Connect to "my-network" network, as defined below
networks:
- my-network
# Map port 8080 on the host to port 80 inside the container
# Syntax is: "HOST_PORT:CONTAINER_PORT"
ports:
- "8080:80"
# Pass a list of environment variables to the container
environment:
PMA_HOST: mysql
# Wait for "mysql" container to start first
depends_on:
- mysql
# Define networks
networks:
my-network:
When you pay close attention to each line, you can see how this translates to the commands we ran in previous steps. We define two containers, mysql
and phpmyadmin
. For each container, we use a combination of keys and values instead of flags to configure them.
You might've noticed a configuration key we haven't used in our commands before: depends_on
. With this, we tell Docker Compose that phpMyAdmin relies on MySQL and it should start MySQL container first. This chronological startup sequence prevents connection problems from phpMyAdmin to a MySQL database that hasn't finished initialising yet.
To start the application stack, in the same folder as the docker-compose.yml
file, run:
# Start the application stack defined in docker-compose.yml
docker-compose up -d
Similar to docker run
, the -d
flag lets us run our application stack in the background. The command to stop and remove all containers and networks is:
# Stop the application stack
docker-compose down
Conclusion
We ended up with a setup that has MySQL and phpMyAdmin running inside different containers connected through a shared network. Additionally, Docker Compose allows us to quickly start the entire application stack by using just a single command.