Running WordPress on Kubernetes might seem like using a sledgehammer to crack a nut, but when you need scalability, high availability, and the ability to handle traffic spikes during your viral blog post moments, Kubernetes becomes your best friend.
In this comprehensive guide, we’ll walk you through everything you need to know about deploying WordPress on Kubernetes in a production-ready configuration. No shortcuts, no “works on my machine” solutions—just battle-tested practices that you can deploy with confidence.

Understanding WordPress on Kubernetes Architecture

Before diving into commands, let’s understand how all the pieces fit together:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
┌─────────────────────────────────────────────────────────────┐
│ Load Balancer │
│ (Ingress Controller) │
└──────────────────────┬──────────────────────────────────────┘

┌──────────────┴──────────────┐
│ │
┌───────▼────────┐ ┌────────▼────────┐
│ WordPress Pod 1│ │ WordPress Pod 2 │
│ │ │ │
│ - PHP-FPM │ │ - PHP-FPM │
│ - Nginx/Apache │ │ - Nginx/Apache │
└────────┬───────┘ └────────┬────────┘
│ │
└──────────┬─────────────────┘

┌──────────▼─────────┐
│ MySQL Service │
└──────────┬─────────┘

┌───────────────┼───────────────┐
│ │ │
┌───▼────┐ ┌───▼────┐ ┌───▼────┐
│MySQL-0 │ │MySQL-1 │ │MySQL-2 │
│Primary │───▶│Replica │───▶│Replica │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
┌───▼────┐ ┌───▼────┐ ┌───▼────┐
│ PVC │ │ PVC │ │ PVC │
│ (50Gi) │ │ (50Gi) │ │ (50Gi) │
└────────┘ └────────┘ └────────┘

┌──────────────────┐
│ Shared Storage │
│ (WordPress Files)│
│ - Themes │
│ - Plugins │
│ - Uploads │
└──────────────────┘

Prerequisites and Environment Setup

  • A running Kubernetes cluster (v1.24+)
  • kubectl configured to interact with your cluster
  • Helm installed (v3.8+)
  • A Storage Class for persistent storage
  • An Ingress Controller (nginx or traefik)

Resource Requirements

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Minimum cluster resources needed
Total CPU: 4 cores
Total Memory: 8 GB RAM
Storage: 100 GB persistent storage

Per WordPress Pod:
Requests:
CPU: 250m
Memory: 512Mi
Limits:
CPU: 500m
Memory: 1Gi

Per MySQL Pod:
Requests:
CPU: 500m
Memory: 1Gi
Limits:
CPU: 1000m
Memory: 2Gi

Quick Environment Verification

Run these commands to verify your setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Check cluster connectivity
kubectl cluster-info

# Verify kubectl version
kubectl version --client

# List available storage classes
kubectl get storageclass

# Check if ingress controller is installed
kubectl get pods -n ingress-nginx

# Verify Helm installation
helm version

Setting Up MySQL Database with StatefulSet

WordPress needs a reliable database. Let’s deploy MySQL with high availability using StatefulSets.

Step 1: Create Namespace and Secrets

1
2
3
4
5
6
7
8
9
10
# Create a dedicated namespace
kubectl create namespace wordpress

# Create MySQL root password secret
kubectl create secret generic mysql-pass \
--from-literal=password='YourSecurePassword123!' \
-n wordpress

# Verify secret creation
kubectl get secrets -n wordpress

Step 2: Deploy MySQL with Persistent Storage

Create a file named mysql-deployment.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
apiVersion: v1
kind: Service
metadata:
name: wordpress-mysql
namespace: wordpress
labels:
app: wordpress
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: wordpress
tier: mysql
clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
namespace: wordpress
labels:
app: wordpress
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: standard # Adjust to your storage class
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress-mysql
namespace: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
- name: MYSQL_DATABASE
value: wordpress
- name: MYSQL_USER
value: wordpress
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
livenessProbe:
exec:
command:
- mysqladmin
- ping
- -h
- localhost
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
command:
- mysqladmin
- ping
- -h
- localhost
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 1
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pvc

Apply the MySQL configuration:

1
2
3
4
5
6
7
8
# Deploy MySQL
kubectl apply -f mysql-deployment.yaml

# Watch the deployment
kubectl get pods -n wordpress -w

# Verify MySQL is running
kubectl get all -n wordpress

Expected output:

1
2
3
4
5
6
7
8
NAME                                READY   STATUS    RESTARTS   AGE
pod/wordpress-mysql-7b4c9f5d-xk9j8 1/1 Running 0 2m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/wordpress-mysql ClusterIP None <none> 3306/TCP 2m

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/wordpress-mysql 1/1 1 1 2m

Step 3: Verify Database Connectivity

1
2
3
4
5
6
7
8
# Test MySQL connection
kubectl run -it --rm mysql-client \
--image=mysql:8.0 \
--restart=Never \
-n wordpress \
-- mysql -h wordpress-mysql -u wordpress -p'YourSecurePassword123!' -e "SHOW DATABASES;"

# Expected output should show the wordpress database

Deploying WordPress Application

Now that MySQL is running, let’s deploy the WordPress application.

Step 1: Configure Shared Storage for WordPress

WordPress files (themes, plugins, uploads) need to be shared across all pods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# wordpress-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-pvc
namespace: wordpress
labels:
app: wordpress
spec:
accessModes:
- ReadWriteMany # Important: Allows multiple pods to write
resources:
requests:
storage: 50Gi
storageClassName: nfs # Use NFS or other RWX-capable storage

Apply the PVC:

1
kubectl apply -f wordpress-pvc.yaml

Step 2: Deploy WordPress Application

Create wordpress-deployment.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
apiVersion: v1
kind: Service
metadata:
name: wordpress
namespace: wordpress
labels:
app: wordpress
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: wordpress
tier: frontend
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
namespace: wordpress
labels:
app: wordpress
spec:
replicas: 2 # Run 2 instances for high availability
selector:
matchLabels:
app: wordpress
tier: frontend
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: wordpress
tier: frontend
spec:
initContainers:
# Fix permissions for WordPress
- name: volume-permissions
image: busybox:latest
command: ['sh', '-c', 'chown -R 33:33 /var/www/html']
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html
containers:
- name: wordpress
image: wordpress:6.4-php8.2-apache
env:
- name: WORDPRESS_DB_HOST
value: wordpress-mysql
- name: WORDPRESS_DB_USER
value: wordpress
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
- name: WORDPRESS_DB_NAME
value: wordpress
- name: WORDPRESS_TABLE_PREFIX
value: wp_
- name: WORDPRESS_DEBUG
value: "0"
# Performance optimizations
- name: PHP_MEMORY_LIMIT
value: 256M
- name: PHP_MAX_EXECUTION_TIME
value: "300"
- name: PHP_UPLOAD_MAX_FILESIZE
value: 64M
- name: PHP_POST_MAX_SIZE
value: 64M
ports:
- containerPort: 80
name: wordpress
protocol: TCP
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
httpGet:
path: /wp-admin/install.php
port: 80
initialDelaySeconds: 90
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /wp-admin/install.php
port: 80
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wordpress-pvc

Deploy WordPress:

1
2
3
4
5
6
7
8
# Apply WordPress configuration
kubectl apply -f wordpress-deployment.yaml

# Watch the deployment
kubectl get pods -n wordpress -w

# Check deployment status
kubectl get all -n wordpress

Step 3: Configure Horizontal Pod Autoscaling

Enable automatic scaling based on CPU usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# wordpress-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: wordpress-hpa
namespace: wordpress
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: wordpress
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 60

Apply the HPA:

1
2
3
4
kubectl apply -f wordpress-hpa.yaml

# Verify HPA is working
kubectl get hpa -n wordpress

Setting Up Ingress and SSL

Make WordPress accessible from the internet with HTTPS.

Step 1: Install cert-manager for SSL

1
2
3
4
5
6
7
8
9
# Add Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io
helm repo update

# Install cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

# Verify installation
kubectl get pods -n cert-manager

Step 2: Create ClusterIssuer for Let’s Encrypt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# letsencrypt-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# Production Let's Encrypt server
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected] # Change this
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx

Apply the issuer:

1
kubectl apply -f letsencrypt-issuer.yaml

Step 3: Configure Ingress with SSL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# wordpress-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wordpress-ingress
namespace: wordpress
annotations:
# SSL configuration
cert-manager.io/cluster-issuer: "letsencrypt-prod"
# Nginx specific annotations
nginx.ingress.kubernetes.io/proxy-body-size: "64m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
# Security headers
nginx.ingress.kubernetes.io/configuration-snippet: |
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
spec:
ingressClassName: nginx
tls:
- hosts:
- your-domain.com # Change this
- www.your-domain.com # Change this
secretName: wordpress-tls
rules:
- host: your-domain.com # Change this
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wordpress
port:
number: 80
- host: www.your-domain.com # Change this
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wordpress
port:
number: 80

Apply the ingress:

1
2
3
4
5
6
7
8
# Apply ingress configuration
kubectl apply -f wordpress-ingress.yaml

# Watch certificate creation
kubectl get certificate -n wordpress -w

# Verify ingress
kubectl describe ingress wordpress-ingress -n wordpress

Step 4: Update DNS Records

Point your domain to the ingress controller’s load balancer:

1
2
3
4
5
6
# Get the load balancer IP
kubectl get svc -n ingress-nginx ingress-nginx-controller

# Add these DNS records:
# A Record: your-domain.com -> LOAD_BALANCER_IP
# A Record: www.your-domain.com -> LOAD_BALANCER_IP

Implementing Backup Strategy

Protect your WordPress data with automated backups.

Step 1: Install Velero for Backup

1
2
3
4
5
6
7
8
9
10
11
12
13
# Download Velero
wget https://github.com/vmware-tanzu/velero/releases/download/v1.12.0/velero-v1.12.0-linux-amd64.tar.gz
tar -xvf velero-v1.12.0-linux-amd64.tar.gz
sudo mv velero-v1.12.0-linux-amd64/velero /usr/local/bin/

# Install Velero (example with AWS)
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.8.0 \
--bucket wordpress-backups \
--backup-location-config region=us-east-1 \
--snapshot-location-config region=us-east-1 \
--secret-file ./credentials-velero

Step 2: Create Backup Schedule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# wordpress-backup-schedule.yaml
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: wordpress-daily-backup
namespace: velero
spec:
# Daily at 2 AM
schedule: "0 2 * * *"
template:
# Include only WordPress namespace
includedNamespaces:
- wordpress
# Include PVs
storageLocation: default
volumeSnapshotLocations:
- default
# Backup TTL (30 days)
ttl: 720h0m0s
# Backup hooks for database consistency
hooks:
resources:
- name: mysql-backup-hook
includedNamespaces:
- wordpress
labelSelector:
matchLabels:
app: wordpress
tier: mysql
pre:
- exec:
container: mysql
command:
- /bin/bash
- -c
- mysqldump --all-databases > /tmp/backup.sql
onError: Fail
timeout: 3m

Apply the backup schedule:

1
2
3
4
5
6
7
8
9
10
kubectl apply -f wordpress-backup-schedule.yaml

# Verify backup schedule
velero schedule get

# Manually trigger a backup
velero backup create wordpress-manual-backup --from-schedule wordpress-daily-backup

# Check backup status
velero backup describe wordpress-manual-backup

Step 3: Test Backup Restoration

1
2
3
4
5
6
7
8
# List available backups
velero backup get

# Restore from backup
velero restore create --from-backup wordpress-daily-backup-20251228

# Monitor restore progress
velero restore describe wordpress-daily-backup-20251228

Performance Optimization

Implementing Redis Cache

Add Redis for object caching:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# redis-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress-redis
namespace: wordpress
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
ports:
- containerPort: 6379
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "200m"
volumeMounts:
- name: redis-data
mountPath: /data
volumes:
- name: redis-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: wordpress-redis
namespace: wordpress
spec:
ports:
- port: 6379
targetPort: 6379
selector:
app: redis

Deploy Redis:

1
kubectl apply -f redis-deployment.yaml

Update WordPress deployment to use Redis:

1
2
3
4
5
# Add to WordPress container env:
- name: WORDPRESS_REDIS_HOST
value: wordpress-redis
- name: WORDPRESS_REDIS_PORT
value: "6379"

Configuring CDN

Set up CloudFlare or similar CDN:

  1. Point domain to CloudFlare nameservers
  2. Enable SSL/TLS (Full mode)
  3. Enable caching for static assets
  4. Configure page rules for WordPress admin

Update WordPress to use CDN for static assets:

1
2
// Add to wp-config.php via ConfigMap
define('WP_CONTENT_URL', 'https://cdn.your-domain.com/wp-content');

Security Hardening

Step 1: Create Network Policies

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: wordpress-network-policy
namespace: wordpress
spec:
podSelector:
matchLabels:
app: wordpress
policyTypes:
- Ingress
- Egress
ingress:
# Allow traffic from ingress controller
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 80
egress:
# Allow DNS
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# Allow MySQL access
- to:
- podSelector:
matchLabels:
app: wordpress
tier: mysql
ports:
- protocol: TCP
port: 3306
# Allow Redis access
- to:
- podSelector:
matchLabels:
app: redis
ports:
- protocol: TCP
port: 6379
# Allow internet access (for plugin downloads, etc.)
- to:
- namespaceSelector: {}
ports:
- protocol: TCP
port: 443
- protocol: TCP
port: 80

Apply network policies:

1
kubectl apply -f network-policy.yaml

Step 2: Configure Pod Security Standards

1
2
3
4
5
6
7
8
9
# pod-security.yaml
apiVersion: v1
kind: Namespace
metadata:
name: wordpress
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted

Step 3: Implement Security Context

Update WordPress deployment with security context:

1
2
3
4
5
6
7
8
9
securityContext:
runAsNonRoot: true
runAsUser: 33 # www-data user
fsGroup: 33
seccompProfile:
type: RuntimeDefault
capabilities:
drop:
- ALL

Monitoring and Observability

Setting Up Prometheus and Grafana

Install monitoring stack:

1
2
3
4
5
6
7
8
9
# Add Prometheus Helm repository
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# Install kube-prometheus-stack
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false

Create WordPress ServiceMonitor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# wordpress-servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: wordpress-monitor
namespace: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
endpoints:
- port: wordpress
path: /metrics
interval: 30s

Access Grafana Dashboard

1
2
3
4
5
6
7
8
9
10
# Get Grafana admin password
kubectl get secret -n monitoring monitoring-grafana \
-o jsonpath="{.data.admin-password}" | base64 --decode

# Port forward to access Grafana
kubectl port-forward -n monitoring svc/monitoring-grafana 3000:80

# Access at http://localhost:3000
# Username: admin
# Password: (from command above)

Import WordPress monitoring dashboard (ID: 13459)

Troubleshooting Common Issues

Issue 1: WordPress Pods Failing to Start

Symptoms:

1
2
kubectl get pods -n wordpress
# Shows pods in CrashLoopBackOff or Error state

Diagnosis:

1
2
3
4
5
# Check pod logs
kubectl logs -n wordpress <wordpress-pod-name>

# Check pod events
kubectl describe pod -n wordpress <wordpress-pod-name>

Common Causes and Solutions:

Issue Cause Solution
Permission denied Wrong file ownership Add initContainer to fix permissions
Cannot connect to MySQL MySQL not ready Ensure MySQL is running first
OOMKilled Memory limit too low Increase memory limits

Issue 2: File Upload Failures

Symptoms:
File uploads fail with “413 Request Entity Too Large”

Solution:

1
2
3
4
5
# Update ingress annotation
kubectl annotate ingress wordpress-ingress \
-n wordpress \
nginx.ingress.kubernetes.io/proxy-body-size=64m \
--overwrite

Issue 3: Slow Performance

Diagnosis:

1
2
3
4
5
# Check resource usage
kubectl top pods -n wordpress

# Check HPA status
kubectl get hpa -n wordpress

Solutions:

  1. Enable Redis caching
  2. Increase replica count
  3. Lower HPA CPU threshold
  4. Add CDN for static assets
  5. Optimize database queries

Issue 4: SSL Certificate Not Issued

Diagnosis:

1
2
3
4
5
# Check certificate status
kubectl describe certificate wordpress-tls -n wordpress

# Check cert-manager logs
kubectl logs -n cert-manager deploy/cert-manager

Common Solutions:

  • Verify DNS records point to correct IP
  • Check ClusterIssuer email address
  • Ensure port 80 is accessible for ACME challenge
  • Check rate limits (Let’s Encrypt has limits)

Production Best Practices

Resource Management

1
2
3
4
5
6
7
8
# Production-ready resource configuration
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"

Database Connection Pooling

Add to WordPress environment:

1
2
3
4
- name: WORDPRESS_DB_CHARSET
value: utf8mb4
- name: WORDPRESS_DB_COLLATE
value: utf8mb4_unicode_ci

Advanced Configuration

Multi-Site WordPress Setup

1
2
3
4
5
6
7
8
9
10
# Add to WordPress environment for multisite
- name: WORDPRESS_CONFIG_EXTRA
value: |
define('WP_ALLOW_MULTISITE', true);
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', false);
define('DOMAIN_CURRENT_SITE', 'your-domain.com');
define('PATH_CURRENT_SITE', '/');
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE', 1);

Blue-Green Deployment Strategy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Create two services: blue and green
apiVersion: v1
kind: Service
metadata:
name: wordpress-blue
namespace: wordpress
spec:
selector:
app: wordpress
version: blue
ports:
- port: 80
---
apiVersion: v1
kind: Service
metadata:
name: wordpress-green
namespace: wordpress
spec:
selector:
app: wordpress
version: green
ports:
- port: 80

Switch traffic by updating ingress backend:

1
2
3
4
# Switch to green
kubectl patch ingress wordpress-ingress -n wordpress \
--type='json' \
-p='[{"op": "replace", "path": "/spec/rules/0/http/paths/0/backend/service/name", "value":"wordpress-green"}]'

Cleanup and Teardown

Complete Cleanup Procedure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Delete the namespace (removes all resources)
kubectl delete namespace wordpress

# Remove PVs if not automatically cleaned
kubectl delete pv --selector=app=wordpress

# Uninstall monitoring (optional)
helm uninstall monitoring -n monitoring
kubectl delete namespace monitoring

# Uninstall cert-manager (optional)
kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

# Uninstall Velero (optional)
velero uninstall

Selective Cleanup

1
2
3
4
5
6
7
8
9
# Delete only WordPress application
kubectl delete deployment wordpress -n wordpress

# Delete only MySQL
kubectl delete deployment wordpress-mysql -n wordpress
kubectl delete pvc mysql-pvc -n wordpress

# Keep backups
velero backup get # Backups remain in object storage