Aller au contenu

WordPress complet

Cet exemple déploie un WordPress complet, prêt pour la production : une base MySQL sur volume persistant, des fichiers WordPress partagés entre 2 replicas, et l’exposition HTTPS avec certificat automatique.

Les manifests de cette page ont été déployés et testés tels quels sur la plateforme. Il ne vous reste qu’à changer le domaine et les mots de passe.

1. Les secrets

apiVersion: v1
kind: Secret
metadata:
name: wordpress-secrets
stringData:
MYSQL_ROOT_PASSWORD: "changez-moi-root"
MYSQL_PASSWORD: "changez-moi-wp"

2. MySQL

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-data
spec:
accessModes: [ReadWriteOnce]
storageClassName: ceph-block-rwo
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
strategy:
type: Recreate # volume RWO : jamais 2 pods MySQL simultanés
selector:
matchLabels: {app: mysql}
template:
metadata:
labels: {app: mysql}
spec:
containers:
- name: mysql
image: mysql:8.4
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef: {name: wordpress-secrets, key: MYSQL_ROOT_PASSWORD}
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef: {name: wordpress-secrets, key: MYSQL_PASSWORD}
- name: MYSQL_DATABASE
value: wordpress
- name: MYSQL_USER
value: wordpress
resources:
requests: {cpu: 250m, memory: 512Mi}
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumes:
- name: data
persistentVolumeClaim: {claimName: mysql-data}
---
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
selector: {app: mysql}
ports: [{port: 3306}]

3. WordPress

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-files
spec:
accessModes: [ReadWriteMany] # partagé entre les replicas
storageClassName: ceph-filesystem-rwx
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
replicas: 2
selector:
matchLabels: {app: wordpress}
template:
metadata:
labels: {app: wordpress}
spec:
containers:
- name: wordpress
image: wordpress:6-apache
env:
- name: WORDPRESS_DB_HOST
value: mysql
- name: WORDPRESS_DB_NAME
value: wordpress
- name: WORDPRESS_DB_USER
value: wordpress
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef: {name: wordpress-secrets, key: MYSQL_PASSWORD}
resources:
requests: {cpu: 200m, memory: 512Mi}
volumeMounts:
- name: files
mountPath: /var/www/html
readinessProbe:
httpGet: {path: /wp-login.php, port: 80}
initialDelaySeconds: 15
periodSeconds: 10
volumes:
- name: files
persistentVolumeClaim: {claimName: wordpress-files}
---
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
selector: {app: wordpress}
ports: [{port: 80}]

4. L’exposition HTTPS

Prérequis : votre domaine pointe vers la plateforme (Configurer votre DNS).

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wordpress
annotations:
cert-manager.io/issuer: letsencrypt
# Sticky sessions : chaque visiteur reste sur le même pod (cf. encadré)
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "wp-affinity"
spec:
rules:
- host: blog.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service: {name: wordpress, port: {number: 80}}
tls:
- hosts: [blog.example.com]
secretName: wordpress-tls

Déployer

Fenêtre de terminal
kubectl apply -f wordpress-stack.yaml -n <votre-namespace>
# Suivre le démarrage (~1 minute)
kubectl get pods -n <votre-namespace> -w

Une fois les pods Running et READY 1/1, ouvrez https://blog.example.com : l’assistant d’installation WordPress vous accueille.

Coût mensuel estimé

Avec la grille tarifaire (facturé à l’heure, ici ramené à un mois de 720 h) :

ComposantRequestsBundlesCoût / mois
MySQL250 m / 512 Mi38,64 €
WordPress × 2200 m / 512 Mi chacun3 × 217,28 €
Stockage5 Gi RWO + 5 Gi RWX7,20 €
Total≈ 33 € HT / mois

Sauvegardes quotidiennes, certificat TLS, trafic et monitoring inclus.

Pour aller plus loin

  • Réduire le coût d’un environnement de test : replicas: 1 et scale à zéro la nuit (~20 €/mois) ;
  • Les fichiers et la base sont sauvegardés chaque nuit — ajoutez un dump MySQL en CronJob pour un point de reprise plus fin ;
  • Suivez la consommation réelle dans le monitoring et ajustez les requests.