6.23 Docker Compose in Action: MySQL Setup Example
Docker Compose – is a tool for defining and running multi-container Docker applications. It allows you to describe the configuration of services (containers) in a single YAML file, and then launch several containers at once with a single command — all configured to work together. Simply put, Docker Compose lets you spin up the entire service stack of your application (e.g., web server + database) with one action, instead of starting each container manually. This is especially useful when your app consists of multiple interconnected components — such as a website and its required database.
In this guide, we’ll explore how to use Docker Compose with a practical example of deploying MySQL. We’ll show you how to create a docker-compose.yml
file with MySQL, set up persistent data storage using volumes, and configure a network to connect the containers. You’ll also learn how to start and test the MySQL container, how to connect to the database both from the host and from another container (such as phpMyAdmin), and finally — some key tips on security and password management (using a .env
file).
Requirements:
Setting up docker-compose.yml
for MySQL
Let’s start by preparing the docker-compose.yml
file, where we’ll describe the MySQL database service (and additionally - phpMyAdmin for convenient management). Below is an example of the file contents with comments on the main settings:
version: '3.8' # Compose file format version
services:
db:
image: mysql:8.0 # Official MySQL 8.0 image
container_name: mysql-db # Container name (optional, for convenience)
ports:
- "3306:3306" # Port forwarding for MySQL to the host (for external connections). Note: if you already have MySQL installed, choose a different port to avoid conflicts, e.g. 3307:3307
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} # Root password (taken from .env)
MYSQL_DATABASE: ${MYSQL_DATABASE} # Database name to create (from .env)
MYSQL_USER: ${MYSQL_USER} # Additional DB user (from .env)
MYSQL_PASSWORD: ${MYSQL_PASSWORD} # Additional user password (from .env)
volumes:
- db_data:/var/lib/mysql # Named volume for storing DB data
networks:
- app-network # Connection to custom network
phpmyadmin:
image: phpmyadmin:latest # phpMyAdmin image
container_name: myadmin # phpMyAdmin container name
depends_on:
- db # db container must start first
ports:
- "8080:80" # phpMyAdmin will be available on port 8080
environment:
PMA_HOST: db # DB host for connection (MySQL service name)
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} # Root password for access
networks:
- app-network
# Define named volume and network
volumes:
db_data: # Volume for MySQL data (Docker stores its data)
networks:
app-network: # Custom network for our services
driver: bridge
In this Compose file, two services are defined:
-
db
- container with MySQL. It has environment variables MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD (passwords and names will be set through an external.env
file, which we’ll discuss below). Also, a volume db_data is mounted to the /var/lib/mysql directory inside the container - this is where MySQL stores its data. By using a named volume, the database data will persist between container restarts (even if the container is deleted, the volume remains until explicitly removed). Port 3306 is forwarded to the host to allow external connections to MySQL if needed (e.g., from localhost or remotely). -
phpmyadmin
- container with phpMyAdmin, a web interface for managing MySQL. We added it as an example to demonstrate connecting to the database from another container. This container depends ondb
(via depends_on, ensuring MySQL starts first), and the environment variables specify where to connect: PMA_HOST: db means phpMyAdmin will look for the MySQL service by the hostnamedb
. In Docker Compose, a common network is created by default for all application services, and they can access each other by service names. We explicitly specified the app-network for clarity - both containers are in it, so phpMyAdmin can connect to MySQL by the name db. We forwarded phpMyAdmin’s port 80 to 8080 on the host - opening a browser at http://<your server>:8080/ will take you to the phpMyAdmin interface.Configuring Environment Variables in the .env File
The .env
file: Note that in docker-compose.yml
we use ${…} constructs - these are references to environment variables. We will set the values of these variables in a separate .env file (in the same directory as docker-compose.yml
). Docker Compose automatically picks up variables from the .env file located in the project directory. Using a separate .env file simplifies configuration management and prevents duplication of passwords and other secrets in different parts of the configuration.
Create a .env
file next to docker-compose.yml
and add the following lines (replace the examples with your own values):
MYSQL_ROOT_PASSWORD=StrongRootPass123 # required password for MySQL root user
MYSQL_DATABASE=myappdb # name of the database to create on startup
MYSQL_USER=myuser # name of the additional user
MYSQL_PASSWORD=UserPass456 # password for the additional user
- MYSQL_ROOT_PASSWORD is a required variable, without it the MySQL container will not start. According to the documentation, it sets the password for the MySQL “root” superuser. Use a sufficiently strong password.
- MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD – these variables are optional. If specified, a new database with the given name will be automatically created when the container first starts, along with a user named MYSQL_USER with password MYSQL_PASSWORD who is granted permissions to this database. This is convenient, for example, to immediately prepare a separate administrator for the application. (If you don’t need an additional user and database, you can omit these variables).
After preparing docker-compose.yml
and .env
, we are ready to start our services. Next, we’ll look at the steps for starting and testing - they are practically the same for different Linux distributions, but we’ll provide separate notes for Debian/Ubuntu and CentOS/AlmaLinux/RockyLinux.
Starting and Testing
- Start Docker Compose: while in the directory with the
docker-compose.yml
file, run the compose startup command
docker compose up -d
- -d will run the containers in the background (daemonized). After executing the command, compose will build and start the services specified in the file. You’ll see output indicating that the containers have been created and started. For example:
Docker Compose automatically created the app-network network and db_data volume for our project (if they weren’t created before). By default, if not specified otherwise, Compose forms the network name based on the project name (usually matching the folder name) with a suffix. In our case, we explicitly set the network name, so it’s called exactly that. All project containers are connected to this network and can communicate with each other using service names.
- Check that the containers are running: execute the container list command
docker compose ps
or similarly
docker ps
, which will show all running Docker containers
docker ps
The output should show at least two containers - MySQL and phpMyAdmin - with the status “Up”.
For example:
- View MySQL logs: on first startup, it’s useful to verify that the database is initialized
docker compose logs -f db
This will show the logs of the db container (our MySQL). You should see messages indicating that the MySQL server is running and listening on port 3306, and possibly that the myappdb database and myuser user have been created (if you specified them). After the line “[Server] /usr/sbin/mysqld: ready for connections.” you can consider the DB ready for use.
- Connecting to the database from the host system Now let’s try to connect to MySQL running inside the container, for example from the server command line. For this, the MySQL client must be installed on the host. In Debian/Ubuntu you can install the package: sudo apt install mysql-client. After that, connect using the command to the local server port:
mysql -h 127.0.0.1 -P 3306 -u root -p
When executing, you’ll be prompted for a password - enter the one you specified in the MYSQL_ROOT_PASSWORD variable in the .env
file. If everything is done correctly, you’ll enter the MySQL console in the container. You can execute the query SHOW DATABASES; to see the list of databases (there should be myappdb and system databases).
-
Connecting to the database from another container In our example, the phpMyAdmin container is already running, connected to the same Compose project. Open a web browser and go to http://<server_address>:8080/. You should see the phpMyAdmin interface. The Server field already has db filled in (since we specified PMA_HOST: db), you just need to enter Username = root and Password = your MYSQL_ROOT_PASSWORD (alternatively, you can log in as user myuser with password UserPass456 - then you can also leave db in the server field, this will connect to the same DB). If authentication is successful, you’ll get web access to your database. Thus, phpMyAdmin, being in the same network as MySQL, accessed it by the internal hostname and successfully connected.
-
Stopping containers After work, you can stop and remove the running containers with the command:
docker compose down
This command will stop the services and detach the volumes, but won’t delete the named volume with data db_data(to delete volumes, you need to add the -v flag). This means that when you next run up the data in the database will be preserved. If you want to completely reset the environment (delete containers, network, and volume with data), use:
docker compose down -v