Migration PrestaShop vers Kubernetes : checklist GitOps et pièges courants

Guide checklist pour migrer PrestaShop vers Kubernetes : préparation, GitOps, image immuable, persistance, manifests, sécurité et rollback rapide.

Ordinateurs et écrans avec des graphiques et le logo Kubernetes pour la migration PrestaShop.

Table des matières :

  1. Prérequis : rendre PrestaShop “Kubernetes‑friendly” sans se mentir
  2. GitOps appliqué à PrestaShop : structure de repo, environnements et promotion
  3. Image immuable : builder PrestaShop (core + modules + thème) sans volumes “magiques”
  4. État et persistance : médias, sessions, cache, et impact sur le scaling horizontal
  5. Manifests Kubernetes : Deployments, probes, HPA, CronJobs et jobs de maintenance
  6. Secrets, TLS et surface d’attaque : durcissement compatible GitOps
  7. Bascule de prod : tests, SEO, canary et rollback en moins de 5 minutes

Prérequis : rendre PrestaShop “Kubernetes‑friendly” sans se mentir

Migrer PrestaShop vers Kubernetes n’est pas une simple transposition “Apache → Pod”. PrestaShop (8.x et 9.x) reste une application PHP historiquement stateful : uploads stockés sur disque, cache applicatif local, génération d’assets, et une partie de la configuration encore ancrée dans app/config/parameters.php. Sur PrestaShop 9 (Symfony 6.4, PHP 8.3), l’outillage CLI progresse, mais le cœur ne devient pas “12‑factor” par magie.

Avant même de parler manifests, prenez 30 minutes pour répondre à une question très concrète : qu’est‑ce qui doit survivre à la mort d’un pod, et qu’est‑ce qui doit être recréé automatiquement ? C’est ce tri qui conditionne la réussite de la migration (et non le choix Helm vs Kustomize).

Côté versions, partez sur une base cohérente et supportée : PrestaShop 8.1/8.2 ou 9.x, PHP 8.2/8.3, et un cluster Kubernetes 1.29+ (le sujet est surtout la discipline de déploiement, pas une feature d’une release précise). Prérequis non négociables : un registry privé, une chaîne de build reproductible, un stockage persistant (ou objet), une base MariaDB/Percona gérée correctement, et une stratégie de secrets qui ne se résume pas à un kubectl create secret lancé à la main.

Quelques points “Kubernetes‑friendly” qui évitent les mauvaises surprises en prod :

  • Configuration externalisée : tout ce qui varie par environnement (DB, Redis, mail, domaines, clés) doit être injecté via variables d’environnement / fichiers montés (ConfigMap/Secret), pas recopié à la main dans l’image.
  • Écriture contrôlée : identifiez précisément les chemins en écriture. Un pod qui écrit “un peu partout” fonctionnera en single replica… puis cassera dès que vous scalez.
  • Runtime observable : logs sur stdout/stderr, pas dans des fichiers perdus dans le container. Les erreurs PHP “silencieuses” deviennent un cauchemar en environnement éphémère.
  • Dépendances externes explicites : DB, cache, queue, SMTP, stockage médias… Kubernetes n’est pas un serveur dédié : tout doit être déclaré, monitoré et testé.
  • Discipline des droits : l’ère du “chown -R à la main après un FTP” se termine. Les permissions doivent être déterministes au build ou via initContainer.

Le point de départ utile, c’est d’accepter la contrainte : Kubernetes orchestrationne, il ne corrige pas les défauts d’architecture applicative. Le manifeste GitOps doit rendre explicite ce que vous faisiez implicitement sur un serveur dédié (cron, jobs d’index, permissions, warmup cache). Pour cadrer les fondations “serveur”, vous pouvez recouper avec des approches bare‑metal/VM (Nginx, PHP‑FPM, MariaDB, Redis) décrites ici : Serveur dédié PrestaShop : config Nginx PHP-FPM MariaDB Redis. L’objectif Kubernetes est ensuite de déclarer ces briques, pas de les improviser.

Enfin, gardez un élément “terrain” en tête : en France/UE, beaucoup de boutiques ont des contraintes RGPD, parfois des exigences de localisation des données (contrats, DPA, hébergeur). Kubernetes facilite le multi‑environnement, mais ne “règle” ni la gouvernance, ni la traçabilité. Votre repo GitOps devient de facto une pièce de conformité : il doit expliquer quoi tourne, où, avec quels accès.

GitOps appliqué à PrestaShop : structure de repo, environnements et promotion

GitOps, au sens strict, c’est traiter Git comme source de vérité et laisser un contrôleur réconcilier l’état réel. L’intérêt n’est pas seulement “déployer automatiquement”, c’est réduire l’entropie : éviter que la prod devienne un système unique, impossible à reproduire ailleurs. Une définition largement reprise dans l’écosystème est disponible sur le site OpenGitOps (CNCF).

Sur PrestaShop, la discipline GitOps se heurte souvent à un anti‑pattern : le code applicatif et les artefacts runtime se mélangent (modules ajoutés en FTP, thème patché à la main, overrides modifiés sur la prod). Le repo GitOps doit donc séparer (1) l’image applicative immuable et (2) la configuration runtime (Ingress, ressources, secrets, endpoints). Un squelette efficace :

  • apps/prestashop/base/ (Deployment, Service, Ingress, HPA, CronJobs)
  • apps/prestashop/overlays/dev|staging|prod/ (Kustomize) ou un chart Helm + values par environnement
  • clusters/<cluster>/ (bootstrap, namespaces, RBAC, operators)

Deux pratiques qui font gagner du temps (et évitent les “drifts” invisibles) :

  • Convention de naming et labels : imposez app.kubernetes.io/name, app.kubernetes.io/part-of, app.kubernetes.io/version (digest ou tag immuable). Cela simplifie les sélecteurs, les dashboards et les règles d’alerting.
  • Même workflow partout : dev/staging/prod suivent la même mécanique (PR, review, reconcile). La différence doit être dans les valeurs (ressources, endpoints), pas dans le procédé.

Une checklist GitOps pragmatique (avant la première mise en prod) :

  1. Environnements reproductibles : une pré‑prod qui ressemble à la prod (ressources, versions, mêmes CRDs). Le sujet est détaillé côté Docker ici : Staging PrestaShop : créer un environnement Docker fidèle à la production. Kubernetes ne doit pas devenir votre premier environnement “réel”.
  2. Promotion par digest : déployer image: repo@sha256:... (ou tag immuable), pas latest. Bonus : notez le digest dans la PR, c’est un “audit trail” lisible.
  3. Politiques de sécurité : au minimum admission control (Kyverno/Gatekeeper) pour empêcher privileged, root, hostPath, etc.
  4. Drift control : l’outil GitOps (Argo CD ou Flux) doit être propriétaire des resources (prune/GC activé), sinon vous perdez la traçabilité.
  5. Diff lisible par les humains : si chaque PR touche 40 fichiers YAML, personne ne review vraiment. Préférez des overlays ciblés et des conventions stables.

Enfin, évitez le faux GitOps “CI/CD push”. Le modèle robuste est “pull” (Argo CD/Flux tirent l’état depuis Git), particulièrement utile quand vous devez auditer : qui a changé un Ingress, pourquoi, et avec quel diff.

Mini‑scénario fréquent (à anticiper) : une équipe “patch” un module en prod pour corriger un bug de paiement, oublie de backporter le correctif, puis la prochaine sync GitOps “corrige” la prod… en réintroduisant le bug. La solution n’est pas Kubernetes : c’est une règle non négociable “pas de modification runtime du code” et un pipeline qui reconstruit l’image dès qu’un module/thème évolue.

Pour une mise en place CI/CD orientée environnements éphémères et validation rapide, la mécanique de démos à la demande est un bon complément : PrestaShop CI/CD : générer des démos à la demande en minutes.

Image immuable : builder PrestaShop (core + modules + thème) sans volumes “magiques”

La majorité des migrations Kubernetes PrestaShop échouent sur un détail trivial : on monte un volume sur /var/www/html “pour être comme avant”, puis on perd toute notion d’immuabilité. Résultat : des pods identiques sur le papier, mais divergents en runtime (modules différents, overrides non versionnés, permissions aléatoires). La règle GitOps : le code (core + modules + thème + overrides) est dans l’image, pas dans un PVC.

Un Dockerfile multi‑stage typique (Debian slim recommandé pour compatibilité extensions PHP) : build Composer + assets (si thème), puis runtime minimal. Points à figer :

  • dépendances PHP : intl, gd, zip, pdo_mysql, opcache (et éventuellement redis)
  • composer install --no-dev --classmap-authoritative
  • permissions www-data + umask stable
  • suppression de /install et renommage du répertoire /admin au build, pas en prod

Exemple (extrait) :

FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --prefer-dist --no-progress --classmap-authoritative

FROM php:8.3-fpm-bookworm AS runtime
# ... install extensions
WORKDIR /var/www/html
COPY --from=vendor /app/vendor ./vendor
COPY . .
RUN rm -rf install && chown -R www-data:www-data /var/www/html
USER www-data

Pour rendre cette immuabilité réellement tenable, prévoyez où PrestaShop a le droit d’écrire. Typiquement, vous voulez :

  • un volume en écriture pour var/ (cache, logs) — souvent un emptyDir suffit (recréé à chaque rollout) ;
  • un volume persistant uniquement pour les médias (selon votre stratégie) ;
  • zéro écriture dans modules/, themes/, override/ en prod (ou vous retombez dans le “serveur FTP déguisé”).

Deux pièges récurrents : (1) laisser PrestaShop générer des fichiers en écriture dans le code (ex : certains modules écrivent dans leur propre dossier), (2) déclencher des “auto‑updates” depuis le back‑office en prod. Sur Kubernetes, ce genre d’écriture aboutit à un état non reproductible, voire à une corruption si vous scalez à >1 replica.

Checklist “image immuable” (rapide, mais efficace) :

  • [ ] .dockerignore en place (évite d’embarquer var/cache, exports, dumps…)
  • [ ] modules/thème versionnés (Git) et intégrés au build
  • [ ] install/ absent, admin/ renommé au build
  • [ ] sortie des credentials de l’image (aucun secret baked)
  • [ ] tests de build reproductible (même commit → même digest)

Pour cadrer l’approche “secure by default” (SBOM, WAF, pipeline), recoupez : PrestaShop : sécuriser APIs et modules avec SBOM, WAF et CI/CD.

État et persistance : médias, sessions, cache, et impact sur le scaling horizontal

PrestaShop n’est pas stateless : img/, download/, upload/, parfois modules/ si vous avez de mauvaises habitudes, et des caches (Smarty, Symfony, images). Avant même d’écrire des manifests, listez précisément ce qui doit survivre à un reschedule de pod. Faites la chasse aux écritures via inotifywait sur un staging, ou en auditant les paths modifiés lors d’un parcours (upload d’image produit, génération de facture, thème, paiement).

Un tableau de décision simple (à adapter) aide à éviter les montages “au hasard” :

Zone Exemples Doit être persistant ? Recommandation K8s
Médias catalogue img/, miniatures Oui PV RWX ou objet+CDN
Fichiers clients upload/, download/ Oui PV RWX + politiques d’accès
Cache applicatif var/cache/ Non emptyDir + warmup éventuel
Logs applicatifs var/log/ Non (si centralisés) stdout/stderr + collecte
Exports temporaires CSV, PDFs “ça dépend” idéalement objet ou volume dédié

Trois stratégies existent pour les médias :

  1. PV RWX (NFS, CephFS, EFS…) monté sur img/ et download/. Simple, mais attention aux perfs (latence) et aux verrous (génération thumbnails). En pratique, surveillez surtout la latence I/O et les pics lors de régénérations d’images.
  2. Stockage objet S3 + CDN : plus scalable, mais nécessite soit un module/adaptation, soit une synchronisation et une discipline forte (invalidations CDN, cohérence). C’est souvent pertinent si vous servez une audience large (Europe / international) et que vous voulez rapprocher le contenu via CDN.
  3. Single replica writer : vous restez à 1 pod web (donc pas de HA applicatif), ce qui annule une partie de l’intérêt Kubernetes.

Le scaling horizontal est aussi bloqué par les sessions (au sens PHP) et certains verrous applicatifs. Même si PrestaShop base beaucoup sur les cookies, des modules (checkout, paiement, anti‑fraude) utilisent $_SESSION. En K8s, bannissez le stockage session sur disque local : configurez session.save_handler=redis et un Redis dédié. Idem pour le cache : emptyDir pour var/cache est OK (reconstruit à chaque déploiement), mais pour la performance, Redis/Memcached restent préférables.

Deux points opérationnels souvent sous‑estimés :

  • Sticky sessions : c’est tentant (“on colle un client à un pod”), mais c’est fragile en cas de reschedule, et ça cache le problème au lieu de le résoudre. Mieux vaut rendre la session réellement partagée.
  • Régénération d’images : ne lancez pas une régénération depuis un pod web scalé (effet “tous les pods travaillent”). Traitez‑la comme un job contrôlé (CronJob/Job) et, si possible, en dehors des heures de pointe.

Le piège classique : activer HPA, scaler de 2 à 6 pods, et découvrir que le panier “saute” car les sessions ne suivent pas (ou que l’indexation d’images explose). Dans un contexte e‑commerce, le coût est immédiat (perte de conversion). D’où l’intérêt de valider le mode “multi‑replica” en staging, avec un test simple : un parcours panier/checkout effectué en parallèle via plusieurs clients, pendant un rollout.

Manifests Kubernetes : Deployments, probes, HPA, CronJobs et jobs de maintenance

Le pattern le moins mauvais pour PrestaShop en K8s est souvent Nginx + PHP‑FPM dans le même Pod (2 containers), partageant un socket Unix via emptyDir. Vous limitez la latence interne et gardez une séparation de responsabilité. Une alternative (Ingress → Service Nginx → Service PHP‑FPM) fonctionne aussi, mais multiplie les hops et complexifie l’observabilité. Dans tous les cas, évitez les images “tout‑en‑un” (supervisord + 3 daemons) : vous perdez la lisibilité et la gestion propre du lifecycle.

Au-delà du “ça tourne”, pensez stabilité de rollout :

  • Requests/Limits réalistes : PHP‑FPM sans limites mémoire finira par être OOMKilled de manière non intuitive. Fixez une limite et dimensionnez pm.max_children en conséquence.
  • PDB (PodDisruptionBudget) : évite que des maintenances de nœuds vident tous les pods en même temps.
  • Anti-affinity / topology spread : utile pour éviter que toutes les replicas finissent sur le même nœud (notamment sur petits clusters).
  • Séparation web / worker : si vous avez des traitements asynchrones, isolez-les (scaling indépendant, limites différentes).

Les probes sont un point de casse fréquent. Une liveness probe HTTP sur / peut déclencher des redémarrages en chaîne si la page d’accueil dépend de la DB/Redis. Préférez :

  • liveness : ping PHP‑FPM (pm.status_path / ping.path) ou endpoint minimal
  • readiness : un check HTTP qui valide que Nginx sert et que PHP répond (sans requête lourde)
  • terminationGracePeriodSeconds + hook preStop pour laisser finir les requêtes

Exemple (extrait) :

livenessProbe:
  tcpSocket:
    port: 9000
  initialDelaySeconds: 20
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /healthz.php
    port: 8080
  periodSeconds: 5

Pour que /healthz.php soit utile, l’objectif n’est pas de tester “tout le site”, mais de réduire les faux positifs. Un bon compromis côté PrestaShop : vérifier que PHP répond, que l’autoloader est OK, et éventuellement qu’une connexion DB est possible avec un timeout très court (sinon, vous transformez l’incident DB en tempête de redémarrages).

Les tâches batch doivent être traitées explicitement. PrestaShop a du cron (emails, nettoyage, exports, flux modules). Sur un serveur, vous aviez un crontab. En Kubernetes, utilisez des CronJobs dédiés, et surtout empêchez le multi‑run concurrent (locking en DB/Redis). Un pattern simple et robuste : un lock Redis (SET NX + TTL) avant d’exécuter la tâche, sinon exit.

Si vous basculez vers Symfony Messenger (selon modules / PrestaShop 9), séparez un Deployment “worker” et dimensionnez le throughput (files, retries). Et n’oubliez pas les dépendances : un worker “sain” qui ne fait rien parce que Redis/DB est saturé ne remonte pas forcément une alerte sans métriques.

Pour l’alerte et le pilotage capacité, raccordez des métriques : Prometheus : configuration des alertes, métriques et requêtes PromQL. En e‑commerce, deux signaux simples donnent déjà beaucoup : taux de 5xx et p95 sur panier/checkout (corrélés à la saturation PHP‑FPM et aux erreurs DB).

Secrets, TLS et surface d’attaque : durcissement compatible GitOps

Kubernetes fournit des primitives, pas une politique. Les Secrets servent à stocker des données sensibles, mais en GitOps ça ne veut pas dire “committer un Secret en base64”. Vous devez choisir entre chiffrement Git (SOPS) ou références externes (Vault, KMS, Secrets Manager) synchronisées à l’exécution.

Pour une approche “pull” propre, External Secrets Operator est un standard de fait : les manifests référencent un secret distant, l’opérateur le matérialise en Secret K8s. C’est précisément l’objectif détaillé ici : External Secrets Operator : synchroniser les secrets Kubernetes avec OVHcloud OKMS. L’erreur courante est de conserver des secrets dans l’image (ex : parameters.php baked avec credentials) : vous perdez la rotation, et vous répliquez les secrets dans le registry.

Checklist de durcissement (sans tomber dans l’usine à gaz) :

  • Sécurité pod : runAsNonRoot, readOnlyRootFilesystem si possible, capabilities minimales, seccompProfile par défaut.
  • Réseau : NetworkPolicies (au moins “deny all” + allow DB/Redis/SMTP nécessaires).
  • Ingress : limiter les méthodes, taille max de body si pertinent, timeouts cohérents (paiement/checkout), headers X‑Forwarded-* corrects.
  • Surface admin : back‑office non exposé “grand public” si possible (IP allowlist/VPN/WAF), et au minimum authentification forte côté comptes.

Pour TLS/DNS/multiboutique, ne “bricolez” pas : la configuration PrestaShop (domaines, SSL, redirections) doit être alignée avec Ingress, certificats, et headers. Une migration K8s casse souvent le SEO via un mauvais canonical / host, des mixed content, ou une redirection 301 inversée. Les détails d’implémentation (SNI, wildcard, SAN, multi‑host) sont à traiter comme un chantier à part entière : Migration PrestaShop Kubernetes : TLS, DNS et configuration multiboutique et, côté SEO TLS, HTTPS SEO : bonnes pratiques, certificats SSL et audit technique.

Point “GEO” concret : si vous opérez plusieurs zones (ex. cluster en France + cluster de secours ailleurs), documentez clairement où vivent les secrets et sauvegardes, et qui a le droit d’y accéder. C’est souvent plus sensible (contractuellement) que le simple fait d’avoir un cluster Kubernetes.

Bascule de prod : tests, SEO, canary et rollback en moins de 5 minutes

Une bascule Kubernetes réussie tient plus du plan de rollback que de l’“exploit technique”. Le minimum est un runbook : snapshot DB, freeze contenu, fenêtre de maintenance (ou réplication), validation, puis bascule DNS/Ingress. Si vous migrez aussi MySQL→MariaDB, validez collation/charset, InnoDB, et queries : Prérequis système : migration MySQL vers MariaDB, InnoDB et collation UTF-8.

Une séquence de bascule réaliste (et audit-able) :

  1. Avant J‑0 : baissez le TTL DNS (si votre stratégie passe par DNS), préparez la supervision, validez sauvegardes/restores (test restauré, pas juste “un dump existe”).
  2. J‑0 (freeze) : stop des écritures non essentielles (imports/exports), blocage éventuel de back‑office, synchronisation finale des médias si nécessaire.
  3. Déploiement : apply GitOps (version/digest connu), warmup si applicable, validation fonctionnelle rapide.
  4. Canary contrôlé : trafic interne (header/cookie), puis montée progressive.
  5. Ouverture : monitoring renforcé + procédure rollback prête.

Côté stratégie de déploiement, le “RollingUpdate” standard est rarement suffisant quand vous avez des risques de divergence de schéma ou de cache : privilégiez blue/green ou canary (Argo Rollouts, Flagger), avec une route contrôlée par header/cookie pour les tests internes. Mesurez des SLIs simples : taux de 5xx, temps de réponse p95 sur panier/checkout, erreurs DB, et saturation PHP‑FPM (busy workers).

Un symptôme classique post‑bascule est la “page blanche” (fatal PHP masquée par une conf prod) : ayez un plan de diagnostic rapide et centralisé, pas une chasse aux logs sur des pods éphémères : PrestaShop page blanche : diagnostiquer l’erreur fatale PHP rapidement.

Enfin, validez explicitement les invariants SEO avant ouverture complète : codes HTTP, canonicals, robots, sitemap, redirections, et absence d’URLs parasites (facettes). Utilisez un crawl de pré‑prod et comparez (diff) avec la prod.

Checklist “SEO & perf” (spécifique migration) :

  • [ ] 200/301 attendus sur les top URLs (catégories, produits, CMS)
  • [ ] canonical cohérent (http→https, non-www→www ou inverse)
  • [ ] robots.txt et meta robots identiques à l’attendu (pas de noindex accidentel)
  • [ ] sitemap accessible et à jour
  • [ ] pas de mixed content (assets en http)
  • [ ] temps de réponse stable sur pages panier/checkout (p95)

La checklist côté indexation/perf est un filet de sécurité utile : SEO PrestaShop : checklist technique 2025 pour indexation et performance.

Sur l’observabilité, centralisez logs applicatifs et access logs (stdout) vers un backend (OpenSearch/ELK) pour corréler immédiatement les erreurs lors d’un canary : OVHcloud Managed OpenSearch : moteur NoSQL managé pour logs et recherche.

Si vous visez un rollback “< 5 minutes”, soyez concret : quel levier déclenche le retour arrière (switch Ingress, rollback Argo Rollouts, restauration snapshot, retour DNS) et quel est le point de non‑retour (écritures en DB après bascule). Un rollback rapide n’est possible que si vous avez testé le scénario au moins une fois en conditions proches, et si les artefacts (image digest, manifests, secrets) sont prêts et cohérents.


À lire aussi