DEV Community

Cover image for Docker Compose: Running WordPress and MySQL as a Multi-Container Application
Rahimah Sulayman
Rahimah Sulayman

Posted on

Docker Compose: Running WordPress and MySQL as a Multi-Container Application

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The core configuration is contained in:

compose.yml
Enter fullscreen mode Exit fullscreen mode

Creating the Project Workspace

The project begins with a dedicated directory:

mkdir my-wordpress-site
cd my-wordpress-site
Enter fullscreen mode Exit fullscreen mode

This keeps the Compose configuration and project documentation organized in a single workspace.

Project 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
Enter fullscreen mode Exit fullscreen mode

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

Compose file created


Inspecting compose.yml

Before starting the application, the Compose configuration can be inspected directly from the terminal:

cat compose.yml
Enter fullscreen mode Exit fullscreen mode

Compose file content


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
Enter fullscreen mode Exit fullscreen mode

Image

image: mysql:8.0
Enter fullscreen mode Exit fullscreen mode

Docker Compose uses the official MySQL 8.0 image rather than building a custom database image.

Restart Policy

restart: always
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Image

image: wordpress:latest
Enter fullscreen mode Exit fullscreen mode

The official WordPress image is used as the application container.

Port Mapping

ports:
  - "8080:80"
Enter fullscreen mode Exit fullscreen mode

This maps:

Host port 8080 → Container port 80
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Service Dependency

depends_on:
  - db
Enter fullscreen mode Exit fullscreen mode

This establishes a dependency relationship between WordPress and the database service.

WordPress Persistent Storage

volumes:
  - wp_data:/var/www/html
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Docker Compose up


Verifying the Services

After starting the environment, the service status can be checked with:

docker compose ps
Enter fullscreen mode Exit fullscreen mode

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

Compose services status


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
Enter fullscreen mode Exit fullscreen mode

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

Compose logs


Managing Persistent Volumes

The Compose configuration defines two named volumes:

volumes:
  db_data:
  wp_data:
Enter fullscreen mode Exit fullscreen mode

These are mounted into the respective services:

db_data
   │
   └── /var/lib/mysql

wp_data
   │
   └── /var/www/html
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Warning: docker compose down -v removes the project's named volumes and therefore deletes the persistent data stored in them. Use this carefully when working with real application data.

Docker Compose down


Verifying the Cleanup

The cleanup can be verified using:

docker compose ps
docker ps -a
docker volume ls
Enter fullscreen mode Exit fullscreen mode

The verification confirms that the project's containers and named volumes have been removed.

Cleanup verification


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
Enter fullscreen mode Exit fullscreen mode

Check service status

docker compose ps
Enter fullscreen mode Exit fullscreen mode

Inspect logs

docker compose logs --tail 20
Enter fullscreen mode Exit fullscreen mode

Stop and remove services

docker compose down -v
Enter fullscreen mode Exit fullscreen mode

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:

https://github.com/rahimahisah17/my-wordpress-site

Top comments (1)

Collapse
 
rahimah_dev profile image
Rahimah Sulayman

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.