Le deploiement WordPress sur K3s repose sur une architecture pod multi-containers avec separation stricte des responsabilites. Cet article detaille la structure du pod, la gestion des volumes, les ConfigMaps et le workflow de mise a jour.
Architecture du pod
Chaque pod WordPress contient quatre containers et un initContainer :
flowchart TD
subgraph pod ["Pod WordPress"]
direction TB
INIT["initContainer<br/>wordpress-files<br/>Telecharge WP core"] --> EMPTY["emptyDir<br/>wordpress-data"]
EMPTY --> NGX["nginx<br/>Serveur web"]
EMPTY --> PHP["php-fpm<br/>Runtime PHP"]
NGX --- NGXEXP["nginx-exporter<br/>Metriques Prometheus"]
PHP --- PHPEXP["phpfpm-exporter<br/>Metriques Prometheus"]
end
PVC["PVC Longhorn<br/>wp-content"] --> NGX
PVC --> PHP
CM["ConfigMaps<br/>wp-config, php.ini,<br/>www.conf, nginx.conf"] --> NGX
CM --> PHP
style INIT fill:#3498db,color:#fff
style EMPTY fill:#9b59b6,color:#fff
style PVC fill:#e67e22,color:#fff
style CM fill:#1abc9c,color:#fff
Pourquoi un initContainer ?
L'image php-fpm-hardened est construite FROM scratch : elle ne contient ni shell, ni cp, ni aucun utilitaire systeme. Il est donc impossible de copier les fichiers WordPress core au demarrage du container PHP.
L'initContainer wordpress-files tourne sous une image Alpine generique (pas une image dediee) : elle telecharge le core WordPress depuis wordpress.org/latest.tar.gz et l'extrait dans le volume partage emptyDir avant que les containers principaux ne demarrent -- il n'y a plus de version WordPress figee dans une image Docker.
Detail technique important : les pods de ce cluster n'ont pas d'acces internet direct (tout le trafic sortant HTTPS passe par le proxy Squid SSL-bump du homelab), donc l'initContainer doit faire confiance a la CA du proxy (montee via ConfigMap) et passer explicitement par le proxy avant tout appel reseau.
# Extrait du Deployment
initContainers:
- name: wordpress-files
image: alpine:3.23
command: ["sh", "-c"]
args:
- |
cat /etc/squid-ca/squid-bump-ca.crt >> /etc/ssl/certs/ca-certificates.crt
export http_proxy=http://vyos.home.arpa:3130 https_proxy=http://vyos.home.arpa:3130
apk add --no-cache curl
curl -fsSL --connect-timeout 10 --max-time 120 --retry 3 \
https://wordpress.org/latest.tar.gz -o /tmp/wp.tar.gz
tar xzf /tmp/wp.tar.gz -C /mnt/wordpress --strip-components=1
chown -R 1999:1999 /mnt/wordpress
volumeMounts:
- name: wordpress-data
mountPath: /mnt/wordpress
Strategie de volumes
Deux types de volumes coexistent avec des roles distincts :
emptyDir : wordpress-data
Volume ephemere cree a chaque demarrage du pod. L'initContainer y copie les fichiers core WordPress (wp-admin, wp-includes, index.php, etc.). Ce volume est partage entre les containers nginx et php-fpm. Son contenu est recree a chaque redemarrage et correspond systematiquement a la derniere version stable disponible sur wordpress.org au moment du demarrage du pod -- il n'y a plus de version figee : deux pods du meme Deployment demarres a des instants differents peuvent en theorie executer des versions WordPress legerement differentes.
PVC Longhorn : wp-content
Volume persistant gere par Longhorn pour le repertoire wp-content/ qui contient les donnees specifiques au site :
- themes/ : themes WordPress installes
- plugins/ : extensions installees et configurees
- uploads/ : medias uploades par les utilisateurs
- cache/ : fichiers de cache generes
Ce volume survit aux redemarrages et aux mises a jour de l'image WordPress.
ConfigMaps et subPath
Les fichiers de configuration sont injectes via ConfigMaps avec des montages subPath :
volumeMounts:
- name: wp-config
mountPath: /var/www/html/wp-config.php
subPath: wp-config.php
- name: php-config
mountPath: /usr/local/etc/php/php.ini
subPath: php.ini
- name: fpm-config
mountPath: /usr/local/etc/php-fpm.d/www.conf
subPath: www.conf
Gotcha subPath : contrairement aux montages de volume classiques, les fichiers montes avec subPath sont figes a la creation du pod. kubelet met bien a jour le contenu de la ConfigMap sur le node (~1 minute), mais le fichier monte dans le container garde sa valeur initiale. Un rollout restart du deployment est obligatoire apres chaque modification de ConfigMap.
Configuration WordPress specifique
FS_METHOD=direct
Sans cette constante dans wp-config.php, WordPress tente d'utiliser FTP pour installer les plugins et themes. Avec FS_METHOD a direct, WordPress ecrit directement sur le filesystem -- ce qui est possible grace au fsGroup: 1999 qui donne au processus PHP les droits d'ecriture sur le PVC.
AUTOMATIC_UPDATER_DISABLED
Les mises a jour automatiques de WordPress sont desactivees. Le core est deja retelecharge en version la plus recente a chaque demarrage de pod, donc a jour par construction -- inutile de laisser wp-admin le faire aussi. Et surtout, laisser wp-admin modifier le core creerait une incoherence : toute modification ecrite dans l'emptyDir serait perdue au prochain redemarrage du pod (l'emptyDir n'etant pas persistant).
Cache Varnish
Un cache Varnish est place devant le pod WordPress pour absorber le trafic de lecture. Le healthcheck Kubernetes pointe vers /healthcheck (endpoint dedie) et non vers / (page d'accueil) pour eviter de polluer le cache avec des requetes internes.
flowchart LR
A["Traefik"] --> B["Varnish<br/>Cache HTTP"]
B -- "Cache HIT" --> C["Reponse directe"]
B -- "Cache MISS" --> D["nginx<br/>Serveur web"]
D --> E["php-fpm<br/>Execution PHP"]
E --> F["MariaDB"]
style B fill:#9b59b6,color:#fff
style C fill:#27ae60,color:#fff
Securite du pod
Le pod applique des contraintes de securite strictes :
securityContext:
runAsUser: 1999
runAsGroup: 1999
fsGroup: 1999
runAsNonRoot: true
Tous les containers s'executent sous l'UID 1999 (non-root). Le fsGroup garantit que les fichiers du PVC Longhorn sont accessibles en lecture/ecriture par le processus PHP. L'initContainer wordpress-files s'execute egalement en non-root.
Workflow de mise a jour WordPress
flowchart TD
A["Demarrage/redemarrage du pod<br/>(rollout, crash, reschedule...)"] --> B["initContainer :<br/>confiance CA proxy Squid"]
B --> C["curl wordpress.org/latest.tar.gz<br/>via proxy vyos.home.arpa"]
C --> D["Extraction dans l'emptyDir<br/>wordpress-data"]
D --> E["nginx / php-fpm demarrent<br/>avec le code frais"]
style A fill:#3498db,color:#fff
style E fill:#27ae60,color:#fff
Il n'y a plus de mise a jour a proprement parler : chaque redemarrage de pod (deploiement volontaire, crash, reschedule Kubernetes...) retelecharge automatiquement la derniere version stable de WordPress. Aucune intervention manuelle, aucun rebuild d'image, aucun bump de tag.
Ce choix sacrifie deliberement la reproductibilite au profit de la simplicite : pas de pipeline de build a maintenir pour suivre les sorties WordPress. La contrepartie est une dependance reseau supplementaire au demarrage du pod (proxy Squid + confiance CA), et l'absence de garantie qu'un rollback restaure une version WordPress precise -- un nouveau pod tirera toujours la derniere version disponible, jamais une version anterieure. Le PVC wp-content n'est de toute facon jamais impacte par ce mecanisme, quelle que soit la version du core.
Articles lies
- Image PHP-FPM hardened et WordPress FROM scratch : construction des images Docker
- Cluster K3s Kubernetes homelab : infrastructure du cluster