Denny Lim
This guide is ideal for you if:
This is a two-part tutorial:
By the end of this tutorial series, youβll understand the key components powering your WordPress website and learn the core concepts and fundamentals of containerising your applications.
The source code for this guide is available on GitHub .
The components listed above need to be broken downβmeaning we will separate them from our single-instance server to achieve scalability, enhanced security, improved performance, and greater cost efficiency.
Identify and split your application into logical services (e.g., frontend, backend, database). In our WordPress setup, we have:
Containers need to communicate with:
Ephemeral Storage (Stateless Apps)
Persistent Storage (Stateful Apps)
Dockerfile
for each service or use a pre-built image.wordpress-docker/ βββ docker-compose.yml # Orchestration βββ nginx/ β βββ nginx.conf # Custom Nginx config βββ mysql/ β βββ my.cnf # MySQL tuning βββ wordpress/ βββ wp-config.php # Custom WordPress config
docker-compose.yml
services: # Database (MySQL) mysql: image: mysql:8.0 container_name: wp-db volumes: - mysql_data:/var/lib/mysql # Persistent storage - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf networks: - wp-network environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: wpdb MYSQL_USER: wpuser MYSQL_PASSWORD: wppassword ports: # MySQL port (forward if needed for tools like MySQL Workbench) - "3306" # WordPress (PHP-FPM) wordpress: image: wordpress:6.8.1-php8.2-fpm-alpine container_name: wp-app depends_on: - mysql volumes: - wordpress_data:/var/www/html # Persistent storage networks: - wp-network environment: WORDPRESS_DB_HOST: mysql WORDPRESS_DB_USER: wpuser WORDPRESS_DB_PASSWORD: wppassword WORDPRESS_DB_NAME: wpdb ports: - "9000" # PHP-FPM port # Web (Nginx) nginx: image: nginx:alpine container_name: wp-nginx volumes: - wordpress_data:/usr/share/nginx/html - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf networks: - wp-network ports: - "8080:80" # Host machine port depends_on: - wordpress # Define networks and volumes networks: wp-network: driver: bridge volumes: wordpress_data: # WordPress files driver: local mysql_data: # Database files driver: local
Start the containers:
docker compose up -d
The -d
flag runs containers in detached mode (background).
Expected output:
β Network wordpress-docker_wp-network Created β Volume "wordpress-docker_wordpress_data" Created β Volume "wordpress-docker_mysql_data" Created β Container wp-db Started β Container wp-app Started β Container wp-nginx Started
Navigate to http://localhost:8080
and complete the WordPress installation. Create sample blog posts and upload images to test persistent storage.
Stop the containers:
docker compose down
Expected output:
β Container wp-nginx Removed β Container wp-app Removed β Container wp-db Removed β Network wordpress-docker_wp-network Removed
Start the containers:
docker compose up -d
Navigate to http://localhost:8080
, your previous posts and uploaded images should be present.
Start a fresh installation (delete persistent volumes):
To remove all containers and volumes, run:
docker compose down -v
Warning: The -v
flag removes all volumes. Avoid this in production to prevent data loss.
Expected output:
β Container wp-nginx Removed β Container wp-app Removed β Container wp-db Removed β Network wordpress-docker_wp-network Removed β Volume wordpress-docker_mysql_data Removed β Volume wordpress-docker_wordpress_data Removed
Restart the containers:
docker compose up -d
Again, navigate to http://localhost:8080
, WordPress will prompt for a fresh installation.
Deploy containers using Docker Compose or Kubernetes (K8s), depending on requirements. This guide uses DigitalOcean Managed Kubernetes (DOKS).
Important Note: This tutorial uses the wordpress
namespace. To change it, either edit all .yaml files in the deploy folder, or run the following command in terminal.
find ./deploy -type f \( -name "*.yaml" \) -exec sed -i.bak "s/namespace: wordpress/namespace: your-preferred-namespace/g" {} \;
Replace your-preferred-namespace
with your desired namespace.
Apply the .yaml
files in the deploy
folder (modify as needed).
Deploy MySQL Database (Optional)
Skip this step if using a managed MySQL service. Update WORDPRESS_DB_HOST
, WORDPRESS_DB_USER
, WORDPRESS_DB_PASSWORD
, and WORDPRESS_DB_NAME
in ./deploy/02-wordpress.yaml
accordingly.
kubectl apply -f ./deploy/01-mysql.yaml
Deploy WordPress Engine
kubectl apply -f ./deploy/02-wordpress.yaml
Deploy Nginx
kubectl apply -f ./deploy/03-nginx.yaml
Deploy Ingress
kubectl apply -f ./deploy/04-ingress.yaml