Dockerizing and Orchestrating Legacy WooCommerce Systems on Modern OVH Infrastructure
Deconstructing the Legacy WooCommerce Monolith
Many organizations find themselves with mature WooCommerce installations that have grown organically over years, often becoming tightly coupled monoliths. These systems, while functional, present significant challenges for modern deployment, scaling, and maintenance. Key components typically include the PHP application layer (WooCommerce, WordPress core, themes, plugins), a MySQL database, and potentially a caching layer (e.g., Redis, Memcached) and a search engine (e.g., Elasticsearch). The goal is to disentangle these components into manageable, independently scalable containers on a robust cloud infrastructure like OVHcloud.
Containerizing WooCommerce Components
The first step is to containerize each logical component. This involves creating Dockerfiles for each service.
Dockerfile for the PHP Application Layer
We’ll base this on an official PHP-FPM image, ensuring compatibility with WordPress and WooCommerce. Key considerations include installing necessary PHP extensions, configuring PHP-FPM, and setting up the web server (Nginx is a common and performant choice).
Create a directory structure like this:
docker-compose.ymlphp/Dockerfilephp.iniwww.conf
nginx/Dockerfilenginx.confconf.d/default.conf
php/Dockerfile:
# Use an official PHP image with FPM and a specific version
FROM php:8.2-fpm
# Set working directory
WORKDIR /var/www/html
# Install necessary extensions for WordPress and WooCommerce
RUN apt-get update && apt-get install -y \
libzip-dev \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libwebp-dev \
libssl-dev \
libonig-dev \
libxml2-dev \
unzip \
git \
&& docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
&& docker-php-ext-install -j$(nproc) gd zip pdo_mysql opcache exif intl \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
# Copy custom PHP configuration
COPY php.ini /usr/local/etc/php/conf.d/custom.ini
COPY www.conf /usr/local/etc/php-fpm.d/zz-custom.conf
# Ensure correct permissions for WordPress files
RUN chown -R www-data:www-data /var/www/html && chmod -R 755 /var/www/html
# Expose port 9000 for PHP-FPM
EXPOSE 9000
# Default command to run PHP-FPM in the foreground
CMD ["php-fpm"]
php/php.ini (example customizations):
memory_limit = 512M upload_max_filesize = 64M post_max_size = 64M max_execution_time = 300 date.timezone = UTC opcache.enable=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=10000 opcache.revalidate_freq=2 opcache.validate_timestamps=1 opcache.enable_cli=1
php/www.conf (PHP-FPM pool configuration):
[www] user = www-data group = www-data listen = 9000 pm = dynamic pm.max_children = 50 pm.min_spare_servers = 5 pm.max_spare_servers = 10 pm.start_servers = 2 pm.idle_timeout = 10s request_terminate_timeout = 120s catch_workers_output = yes
Dockerfile for the Nginx Web Server
Nginx will serve static assets and proxy PHP requests to PHP-FPM.
nginx/Dockerfile:
FROM nginx:alpine # Remove default Nginx configuration RUN rm /etc/nginx/conf.d/default.conf # Copy custom Nginx configuration COPY nginx.conf /etc/nginx/nginx.conf COPY conf.d/default.conf /etc/nginx/conf.d/default.conf # Copy custom Nginx site configuration COPY conf.d/default.conf /etc/nginx/conf.d/default.conf # Expose port 80 EXPOSE 80
nginx/nginx.conf (basic configuration):
user nginx;
worker_processes auto;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
gzip on;
gzip_disable "msie6";
# Add other gzip settings as needed
include /etc/nginx/conf.d/*.conf;
}
nginx/conf.d/default.conf:
server {
listen 80;
server_name localhost; # Replace with your domain
root /var/www/html;
index index.php index.html index.htm;
# Serve static files directly
location ~* \.(jpg|jpeg|gif|png|css|js|ico|woff|woff2|ttf|svg|eot)$ {
expires 30d;
add_header Cache-Control "public";
}
# Pass PHP scripts to PHP-FPM
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000; # 'php' is the service name in docker-compose
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Deny access to sensitive files
location ~ /\.ht {
deny all;
}
# Handle WordPress permalinks
location / {
try_files $uri $uri/ /index.php?$args;
}
}
Database and Caching Services
For the database, we’ll use an official MySQL image. For caching, Redis is a common choice.
Orchestration with Docker Compose
docker-compose.yml will define and link these services. This is crucial for local development and can be adapted for single-node deployments on OVHcloud.
version: '3.8'
services:
php:
build:
context: ./php
dockerfile: Dockerfile
container_name: woocommerce_php
volumes:
- ./wordpress:/var/www/html # Mount your WordPress files here
environment:
PHP_FPM_USER: www-data
PHP_FPM_GROUP: www-data
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress_user
WORDPRESS_DB_PASSWORD: your_db_password
WORDPRESS_DB_NAME: wordpress_db
REDIS_HOST: redis
depends_on:
- db
- redis
networks:
- woocommerce_network
nginx:
build:
context: ./nginx
dockerfile: Dockerfile
container_name: woocommerce_nginx
ports:
- "80:80"
- "443:443" # For SSL
volumes:
- ./wordpress:/var/www/html # Mount your WordPress files here
- ./nginx/conf.d:/etc/nginx/conf.d # Custom Nginx configs
# Add SSL certificates if using HTTPS
# - ./certs:/etc/nginx/certs
depends_on:
- php
networks:
- woocommerce_network
db:
image: mysql:8.0
container_name: woocommerce_db
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: your_root_password
MYSQL_DATABASE: wordpress_db
MYSQL_USER: wordpress_user
MYSQL_PASSWORD: your_db_password
networks:
- woocommerce_network
redis:
image: redis:alpine
container_name: woocommerce_redis
networks:
- woocommerce_network
volumes:
db_data:
networks:
woocommerce_network:
driver: bridge
To start the services locally:
docker-compose up -d
You’ll need to populate the ./wordpress directory with your existing WooCommerce installation files and ensure the database credentials match your current setup or are configured for a new database.
Deployment on OVHcloud Infrastructure
OVHcloud offers several services suitable for containerized applications, including Public Cloud instances (VMs) and Managed Kubernetes (K8s). For a legacy system, starting with Public Cloud instances is often simpler, allowing you to run Docker Compose directly or use Docker Swarm.
Option 1: Public Cloud Instances with Docker Compose/Swarm
Provision one or more OVHcloud Public Cloud instances (e.g., General Purpose or Compute Optimized). Install Docker and Docker Compose on these instances.
Steps:
- Launch an instance (e.g., Ubuntu 22.04 LTS).
- Install Docker:
curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh
- Install Docker Compose:
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose
- Transfer your
docker-compose.ymland associated Dockerfiles/configs to the instance. - Mount your WordPress files. This is critical. You can use OVHcloud’s Object Storage with tools like
s3fsor NFS for persistent storage, or directly mount a volume if the instance has sufficient disk space. For simplicity, we’ll assume direct volume mounting or a shared filesystem for now. - Run
docker-compose up -d.
Database Migration: The existing MySQL data needs to be migrated. Dump your current database:
mysqldump -u your_user -p your_database > wordpress_backup.sql
Then, import it into the containerized MySQL instance. You can exec into the running container:
docker exec -i woocommerce_db mysql -u root -p'your_root_password' wordpress_db < wordpress_backup.sql
Persistent Storage: For production, the db_data volume and the WordPress files volume (./wordpress) must be persistent. OVHcloud offers block storage that can be attached to instances and mounted. For the WordPress files, consider using OVHcloud Object Storage with tools like rclone or s3fs to mount it as a filesystem, or a managed NFS service.
Option 2: OVHcloud Managed Kubernetes (K8s)
For true scalability and resilience, migrating to OVHcloud Managed Kubernetes is the strategic long-term solution. This involves converting your docker-compose.yml into Kubernetes manifests (Deployments, Services, PersistentVolumeClaims, etc.).
Key Kubernetes Objects:
- Deployments for PHP, Nginx, and Redis.
- StatefulSets for MySQL, ensuring stable network identifiers and persistent storage.
- Services to expose Nginx internally and externally.
- PersistentVolumeClaims (PVCs) to request storage from OVHcloud’s block storage or other CSI drivers.
- Ingress Controller (e.g., Nginx Ingress Controller) to manage external access, SSL termination, and routing.
Example Nginx Ingress Manifest Snippet:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: woocommerce-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
# Add SSL termination annotations if using cert-manager
spec:
rules:
- host: your-domain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service # Name of your Nginx Kubernetes Service
port:
number: 80
Database Considerations in K8s: Running MySQL directly in K8s can be complex. Consider using OVHcloud’s managed database services (e.g., Managed Databases for MySQL) or a robust Kubernetes-native database solution like Percona XtraDB Cluster or Vitess for high availability.
Security and Performance Enhancements
SSL Termination: Offload SSL termination to the Ingress Controller in Kubernetes or to a Load Balancer in front of your Docker Swarm/Compose setup. For Docker Compose, configure Nginx to handle SSL certificates.
Caching: Ensure Redis is properly configured and utilized by WooCommerce (e.g., using a plugin like W3 Total Cache or LiteSpeed Cache configured for Redis). For static assets, leverage Nginx’s caching capabilities and consider a CDN.
Database Optimization: Regularly analyze and optimize MySQL queries. Use tools like pt-query-digest. Ensure the database container has adequate resources.
Security Hardening: Regularly update base images, apply security patches, and restrict network access between containers using network policies (in K8s) or Docker network configurations.
Monitoring and Logging
Implement robust monitoring and logging. For Docker Compose, you can use tools like cadvisor, node-exporter, and promtail to ship logs and metrics to Prometheus and Grafana. In Kubernetes, the ecosystem is more mature with solutions like the ELK stack (Elasticsearch, Logstash, Kibana) or Grafana Loki for logging, and Prometheus/Grafana for metrics.
Example Log Shipping with Promtail (for Docker Swarm/Compose):
# promtail-config.yml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://your-loki-server:3100/loki/api/v1/push
scrape_configs:
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 15s
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: 'woocommerce_(.*)' # Adjust regex to match your container names
target_label: container_name
- source_labels: [__meta_docker_container_label_com_docker_compose_project]
target_label: compose_project
- source_labels: [__meta_docker_container_label_com_docker_compose_service]
target_label: compose_service
- target_label: __path__
replacement: /var/lib/docker/containers/${__meta_docker_container_id}/${__meta_docker_container_name}-json.log # Adjust path if needed
# Add more relabeling rules to filter/enrich logs as needed
Deploy Promtail as a Docker service, ensuring it can access the Docker socket and has the correct configuration to send logs to your Loki instance.
Conclusion
Containerizing and orchestrating a legacy WooCommerce system on OVHcloud infrastructure offers significant advantages in terms of scalability, resilience, and manageability. The choice between Docker Compose on instances and Managed Kubernetes depends on the organization’s current maturity, operational capacity, and future scaling requirements. A phased approach, starting with containerization and potentially moving to Kubernetes, is often the most pragmatic path.