---
title: "WordPress complet"
description: "Déployer un WordPress de production sur Kontainers : MySQL avec volume persistant, fichiers partagés en RWX, HTTPS automatique — manifests testés et coût estimé."
source_url:
  html: https://docs.blackswift.cloud/exemples/wordpress/
  md: https://docs.blackswift.cloud/exemples/wordpress.md
---

# WordPress complet

> Déployer un WordPress de production sur Kontainers : MySQL avec volume persistant, fichiers partagés en RWX, HTTPS automatique — manifests testés et coût estimé.

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.

<Aside type="note">
L'architecture illustre les deux [classes de stockage](https://docs.blackswift.cloud/deployer/stockage-persistant.md) :
MySQL écrit seul → volume **RWO** ; les 2 replicas WordPress partagent les
uploads → volume **RWX**.
</Aside>

## 1. Les secrets

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

## 2. MySQL

```yaml
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

```yaml
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](https://docs.blackswift.cloud/deployer/configurer-votre-dns.md)).

```yaml
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

```bash
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.

<Aside type="note" title="Deux replicas et les sessions PHP ?">
WordPress lui-même n'utilise **pas** les sessions PHP : l'authentification repose
sur des cookies signés, validés contre la base — et les clés de signature vivent
dans `wp-config.php`, généré **sur le volume partagé**, donc identiques sur les
deux pods (vérifié sur la plateforme). Le cœur de WordPress est ainsi
indifférent au pod qui répond.

Certains **plugins**, en revanche, ouvrent des sessions PHP — stockées
localement dans chaque pod. C'est le rôle des deux annotations `affinity` de
l'Ingress ci-dessus : chaque visiteur reste collé à « son » pod (sticky
sessions), et ces plugins fonctionnent sans rien remarquer. Alternative plus
robuste pour un site à fort trafic : stocker les sessions en base ou dans un
Redis via un plugin dédié.
</Aside>

## Coût mensuel estimé

Avec la [grille tarifaire](https://docs.blackswift.cloud/reference/facturation.md) (facturé à l'heure, ici
ramené à un mois de 720 h) :

| Composant | Requests | Bundles | Coût / mois |
| --- | --- | --- | --- |
| MySQL | 250 m / 512 Mi | 3 | 8,64 € |
| WordPress × 2 | 200 m / 512 Mi chacun | 3 × 2 | 17,28 € |
| Stockage | 5 Gi RWO + 5 Gi RWX | — | 7,20 € |
| **Total** | | | **≈ 33 € HT / mois** |

Sauvegardes quotidiennes, certificat TLS, trafic et monitoring
[inclus](https://docs.blackswift.cloud/reference/facturation.md#inclus-sans-supplément).

## Pour aller plus loin

- Réduire le coût d'un environnement de test : `replicas: 1` et
  [scale à zéro la nuit](https://docs.blackswift.cloud/operer/consommation-et-facturation.md) (~20 €/mois) ;
- Les fichiers et la base sont [sauvegardés chaque nuit](https://docs.blackswift.cloud/operer/sauvegardes-et-restauration.md) —
  ajoutez un dump MySQL en CronJob pour un point de reprise plus fin ;
- Suivez la consommation réelle dans le
  [monitoring](https://docs.blackswift.cloud/operer/acceder-au-monitoring.md) et ajustez les requests.
