Source: Dev.to | Dec 26, 2025 (UTC)
The “Why” Behind the Project
As someone transitioning into DevOps, I quickly realized that real learning happens through building, not just watching tutorials. While I had previously set up WordPress using manual SSH commands and Ansible playbooks, I kept hearing about containerization as a fundamental DevOps skill. I decided to bridge this gap by completing Project 1 in my 30-project DevOps roadmap: containerizing a full WordPress LEMP stack.
This post documents my hands-on journey, the challenges I faced, and the key concepts I learned along the way.
What I Built
I created a production-like WordPress environment that can be spun up with a single command:
docker-compose up -d
This command launches two containers:
-
MySQL 8.4 for the database
-
WordPress with PHP 8.3 for the application
The entire infrastructure is defined in a docker-compose.yml file—Infrastructure as Code in practice.
The Architecture: Simple but Powerful
Here’s how the pieces fit together:
User Browser → Localhost:8080 → WordPress Container → MySQL Container (db:3306)
The magic happens in the docker-compose.yml:
services:
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
– db_data:/var/lib/mysql
wordpress:
image: wordpress:latest
ports:
– “8080:80”
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DB_NAME: wordpress
depends_on:
– db
volumes:
– wp_data:/var/www/html
volumes:
db_data:
wp_data:
Challenge 1: Database Connection Issues
Problem: WordPress installation failed with “database connection error”
Solution: I learned that containers communicate via service names, not localhost. The fix was using db (the service name in docker-compose.yml) as the database host during WordPress setup.
Challenge 2: Port Conflicts on Mac
Problem: Port 80 was already in use
Solution: Changed the port mapping to "8080:80" in the docker-compose.yml file
Challenge 3: Authentication Errors with GitHub
Problem: Couldn’t push code due to password authentication deprecation
Solution: Generated a GitHub Personal Access Token and used it for command-line Git operations
1. Infrastructure as Code (IaC) Isn’t Just a Buzzword
Defining my entire stack in a YAML file felt revolutionary. This single file can:
-
Be version controlled
-
Be shared with team members
-
Deploy identical environments everywhere
-
Serve as documentation
2. Container Networking Is Magical (Once You Understand It)
The concept that wordpress container can connect to db container using just the service name (db:3306) clicked for me. Docker creates a virtual network where containers can discover each other by name.
3. Development-Production Parity Is Achievable
With this setup, I can run the exact same environment on:
-
My local MacBook
-
An AWS EC2 instance
-
A CI/CD pipeline
-
Any developer’s machine
No more “it works on my machine” problems!
4. Learning in Public Has Benefits
Documenting this journey on GitHub and writing this post helped solidify my understanding. The complete code is available here for anyone to reference or build upon.
Comparison: Before vs. After Docker
Aspect
Manual/Ansible Setup
Dockerized Setup
Setup Time
15-20 minutes
30 seconds
Reproducibility
Environment-dependent
Guaranteed consistency
Learning Curve
Lower initially
Steeper but more valuable
Portability
Server-specific
Runs anywhere with Docker
Scaling
Manual intervention
Add more containers


Залишити відповідь