Introduction
Managing containers individually with docker run works well for simple applications, but once an application depends on multiple services, managing each container separately quickly becomes inefficient.
A typical WordPress deployment, for example, requires more than the WordPress application itself. It also needs a database service, networking between the services, configuration, and persistent storage.
This is where Docker Compose becomes useful.
In this project, I configured a multi-container WordPress environment using Docker Compose, with WordPress and MySQL defined as separate services and managed through a single compose.yml file.
What is Docker Compose?
Docker Compose is a tool for defining and managing multi-container applications using a YAML configuration file.
Instead of manually creating and configuring each container with multiple docker run commands, the required services and their configuration can be declared in one file.
For this project, the architecture is:
Docker Compose
│
┌───────────┴───────────┐
│ │
▼ ▼
WordPress Service MySQL Service
wordpress:latest mysql:8.0
│ │
└─────── Network ───────┘
│
Persistent Volumes
┌─────┴─────┐
▼ ▼
wp_data db_data
The two services work together:
- WordPress provides the web application.
- MySQL provides the database.
- Docker Compose networking allows WordPress to communicate with MySQL.
- Named volumes provide persistent storage.
Project Architecture
The environment consists of two services:
| Service | Image | Purpose |
|---|---|---|
wordpress |
wordpress:latest |
Web application |
db |
mysql:8.0 |
Database |
The WordPress container exposes port 80 internally, which is mapped to port 8080 on the host.
The MySQL service is not exposed directly to the host because WordPress communicates with it through the internal Docker network.
Project Structure
my-wordpress-site/
├── screenshots/
├── compose.yml
└── README.md
The core configuration is contained in:
compose.yml
Creating the Project Workspace
The project begins with a dedicated directory:
mkdir my-wordpress-site
cd my-wordpress-site
This keeps the Compose configuration and project documentation organized in a single workspace.
Defining the Docker Compose Configuration
The environment is defined in compose.yml.
The file contains two services:
services:
db:
image: mysql:8.0
wordpress:
image: wordpress:latest
The services section is the foundation of the Compose configuration. Each service represents a containerized component of the application.
The complete configuration defines:
- Container images
- Environment variables
- Service dependencies
- Port mapping
- Persistent volumes
- Service-to-service communication
Inspecting compose.yml
Before starting the application, the Compose configuration can be inspected directly from the terminal:
cat compose.yml
Configuring the MySQL Service
The database service is defined as:
db:
image: mysql:8.0
restart: always
environment:
MYSQL_ROOT_PASSWORD: supersecretpassword
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpressuser
MYSQL_PASSWORD: wordpresspassword
volumes:
- db_data:/var/lib/mysql
Image
image: mysql:8.0
Docker Compose uses the official MySQL 8.0 image rather than building a custom database image.
Restart Policy
restart: always
This instructs Docker to automatically restart the container when appropriate.
Environment Variables
The database configuration is supplied through environment variables:
MYSQL_ROOT_PASSWORD: supersecretpassword
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpressuser
MYSQL_PASSWORD: wordpresspassword
These variables configure the initial MySQL database, user, and credentials.
Production note: Credentials should not be committed directly into a public repository. In production environments, use environment files, Docker secrets, or an appropriate secrets-management solution.
Persistent Database Storage
volumes:
- db_data:/var/lib/mysql
The named volume db_data is mounted to MySQL's data directory.
This allows database data to persist independently of the container lifecycle.
Configuring the WordPress Service
The WordPress service is defined as:
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8080:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpressuser
WORDPRESS_DB_PASSWORD: wordpresspassword
WORDPRESS_DB_NAME: wordpress
volumes:
- wp_data:/var/www/html
Image
image: wordpress:latest
The official WordPress image is used as the application container.
Port Mapping
ports:
- "8080:80"
This maps:
Host port 8080 → Container port 80
This allows the WordPress application to be accessed through port 8080 on the host.
Database Connection
The WordPress container is configured to connect to MySQL using:
WORDPRESS_DB_HOST: db:3306
This is an important Docker Compose concept.
db is not a hostname from the host machine. It is the service name defined in the Compose file.
Docker Compose creates a network for the application, allowing services to communicate with each other using their service names.
The connection therefore looks like:
WordPress
│
│ db:3306
▼
MySQL
Service Dependency
depends_on:
- db
This establishes a dependency relationship between WordPress and the database service.
WordPress Persistent Storage
volumes:
- wp_data:/var/www/html
The wp_data named volume stores WordPress application data outside the container's writable layer.
Starting the Multi-Container Application
Once the Compose configuration is ready, the complete environment can be started with:
docker compose up -d
The up command creates and starts the services defined in compose.yml.
The -d option starts them in detached mode, allowing the terminal to remain available while the containers run in the background.
docker compose
│
└── up
│
└── -d
│
├── MySQL container
└── WordPress container
Verifying the Services
After starting the environment, the service status can be checked with:
docker compose ps
This provides a quick overview of the containers managed by the Compose project.
It can be used to verify:
- Service names
- Container status
- Ports
- Running state
Inspecting Container Logs
Logs are essential when troubleshooting containerized applications.
Docker Compose provides a convenient way to inspect logs from all services:
docker compose logs --tail 20
The --tail 20 option limits the output to the most recent 20 log lines.
This is useful for identifying:
- Startup issues
- Configuration problems
- Database connection errors
- Application errors
- Service initialization messages
Managing Persistent Volumes
The Compose configuration defines two named volumes:
volumes:
db_data:
wp_data:
These are mounted into the respective services:
db_data
│
└── /var/lib/mysql
wp_data
│
└── /var/www/html
Named volumes are useful because container storage is otherwise tied to the container's lifecycle.
For a database-backed application, separating persistent data from the container itself is particularly important.
Cleaning Up the Environment
Once the deployment has been verified, the entire Compose environment can be removed with:
docker compose down -v
The down command stops and removes the containers and the Compose network.
The -v option additionally removes the named volumes created by the project.
In this lab, that means:
WordPress container → removed
MySQL container → removed
Compose network → removed
wp_data volume → removed
db_data volume → removed
Warning:
docker compose down -vremoves the project's named volumes and therefore deletes the persistent data stored in them. Use this carefully when working with real application data.
Verifying the Cleanup
The cleanup can be verified using:
docker compose ps
docker ps -a
docker volume ls
The verification confirms that the project's containers and named volumes have been removed.
Docker Compose vs. Individual docker run Commands
Without Compose, running this type of environment manually would require separate commands for the database and WordPress containers, along with their networking, environment variables, volumes, and port configuration.
Docker Compose consolidates those requirements into a single declarative configuration.
| Manual Docker | Docker Compose |
|---|---|
Multiple docker run commands |
One compose.yml
|
| Configuration spread across commands | Configuration centralized in YAML |
| Manual container relationships | Services defined together |
| Manual volume configuration | Named volumes declared in Compose |
| Multiple commands to start services | docker compose up -d |
| Individual cleanup commands | docker compose down |
This becomes increasingly valuable as application architectures grow.
Key Docker Compose Commands
The main commands used in this project were:
Start services
docker compose up -d
Check service status
docker compose ps
Inspect logs
docker compose logs --tail 20
Stop and remove services
docker compose down -v
Skills Demonstrated
This project demonstrates practical experience with:
- Docker Compose
- Multi-container application architecture
- YAML configuration
- WordPress containerization
- MySQL containerization
- Docker networking and service discovery
- Docker named volumes
- Persistent application storage
- Environment-based service configuration
- Container lifecycle management
- Container log inspection
- Docker CLI
- Linux command-line operations
- Technical documentation
- Git and GitHub project management
Conclusion
Docker Compose provides a practical way to define, configure, and manage applications composed of multiple containers.
By defining WordPress and MySQL as services in a single compose.yml, the application environment becomes easier to deploy, inspect, manage, and remove.
The key concepts demonstrated in this implementation include:
- Declarative multi-container configuration
- Service-to-service communication
- Docker Compose networking
- Persistent volumes
- Environment variables
- Container lifecycle management
- Log-based troubleshooting
The same principles can be extended to more complex architectures involving application servers, databases, caches, message brokers, reverse proxies, and other supporting services.
Project Repository
The complete project, including the compose.yml configuration and implementation screenshots, is available on GitHub:








Top comments (1)
Have you used Docker Compose for local development? I'd be interested to know what services you typically run together besides a database and application container.