
🌐 Aussi en: English · Deutsch · Español
L’heure des aveux : le Nextcloud de production du journal de bataille de la migration tourne sur K3s depuis une semaine, le dépôt contient un playbook nextcloud-update.yml depuis des mois, et je ne l’avais encore jamais lancé pour de vrai. Les apps étaient mises à jour à l’ancienne, en cliquant dans l’interface d’administration, ou pas du tout. Aujourd’hui, ça a changé. L’exécution elle-même a pris 2 minutes 45 secondes. Le plus intéressant, c’était tout ce qu’il y avait autour.
Même méthode que d’habitude : je décide, mon co-admin IA (Claude) vérifie, construit et contrôle. Et la toute première chose qu’il a trouvée n’était pas un bug dans la logique de mise à jour, mais une arme chargée pointée sur mon propre pied, à la ligne trois.
🧭 Pourquoi un playbook de mise à jour séparé ?
D’abord, une question que j’ai réellement dû poser : si je lance le playbook principal, mes apps sont-elles mises à jour ? Réponse : non, et c’est voulu. Il y a deux raisons indépendantes, et le playbook principal n’en couvre délibérément aucune.
Raison 1 : même tag, image plus récente
Un tag d’image comme nextcloud:34.0.4-fpm n’est qu’un nom qui pointe vers une image. Les images officielles sont reconstruites sous le même nom dès qu’un composant sous-jacent est corrigé : un correctif de sécurité Debian, une version mineure de PHP, OpenSSL. La version de Nextcloud reste 34.0.4 ; le contenu, non.
Mes pods tournent avec imagePullPolicy: IfNotPresent : si une image portant ce nom se trouve déjà dans le store containerd local, K3s ne redemande jamais au registre. Tant que le tag ne change pas dans l’inventaire, le playbook principal applique donc des manifestes identiques, K3s n’a rien à faire, et l’ancien build continue de tourner indéfiniment. Le playbook de mise à jour force la comparaison avec crictl pull et redémarre ensuite. Idem pour Collabora.
Raison 2 : les apps ne sont pas dans l’image
C’est la raison la plus importante. Le répertoire de code de Nextcloud, /var/www/html, est un volume HostPath sur le serveur (/srv/nextcloud-www), et les apps de l’App Store s’installent justement là, à côté du cœur. Une nouvelle image apporte un nouveau cœur et les apps livrées avec. Elle ne touche jamais aux apps tierces comme audioplayer, drawio ou Deck. Celles-ci ne bougent qu’avec occ app:update (ou un clic dans l’interface d’administration). Le playbook principal n’impose que la disposition des apps : celles-ci activées, celles-là désactivées, installer ce qui manque. Il existe un interrupteur optionnel (nextcloud_apps_update), par défaut à false.
Trois couches, trois leviers
| Qu’est-ce qui change ? | Exemple | Levier |
|---|---|---|
| Version de Nextcloud | 34.0.4 → 34.0.5, ou → 35 | Changer le tag dans l’inventaire, lancer nextcloud-k3s.yml |
| Image reconstruite, même tag | Correctif de sécurité dans PHP ou Debian | nextcloud-update.yml (pull + redémarrage) |
| Apps de l’App Store | audioplayer 3 → 4 | nextcloud-update.yml (occ app:update --all) |
Pourquoi ne pas tout regrouper en une seule exécution ? Parce que le playbook principal doit être idempotent et prévisible : il converge vers un état déclaré, et le lancer deux fois ne change rien la seconde fois. Les mises à jour, c’est l’inverse : elles récupèrent ce qu’il y a de nouveau sur Internet et remplacent du code en cours d’exécution. Cela mérite son propre moment, sa propre vérification des sauvegardes et son propre coup d’œil aux logs ensuite. Sinon, chaque petite exécution de configuration mettrait discrètement des apps à jour au passage, et si quelque chose cassait ensuite, vous ne sauriez jamais si c’était votre changement de configuration ou la version publiée par quelqu’un d’autre.
🔫 L’arme pointée sur le pied : hosts: nextcloud
Le play cible le groupe d’inventaire nextcloud. Ce groupe contient actuellement l’instance de production, un hôte de test et une seconde instance en pleine migration : sa base de données est écrasée à chaque synchronisation jusqu’au jour de la bascule, et elle est figée sur la version exacte de l’ancien serveur. Oubliez --limit une seule fois et la mise à jour déferle sur les trois, en redémarrant des pods sur une machine censée rester parfaitement immobile.
Le correctif tient en quatre lignes et empêche le playbook de démarrer sans limite :
- name: Update | Refuse to run without --limit
ansible.builtin.assert:
that: ansible_limit is defined
fail_msg: "Run with --limit <host>, e.g. --limit cvjm - this playbook restarts Nextcloud."
run_once: trueansible_limit est une variable magique qui n’existe que si --limit a été passé. Peu coûteux, explicite, et ça transforme un « oups » en message d’erreur. Première tâche de l’exécution du jour : « All assertions passed ». 🎉
✅ Avant le décollage : quatre vérifications, deux minutes
- Sauvegarde récente ? Le pull quotidien depuis la machine de sauvegarde s’était terminé à 12 h 30 avec dump de la base et données. Une mise à jour sans point de restauration récent, c’est un pari, pas de la maintenance.
- Qu’est-ce qui va réellement changer ?
occ app:update --all --showonlyfait office de simulation. Résultat : une seule app, audioplayer, qui passe en 4.0.0. - Point de départ sain ?
occ status: pas de mode maintenance, pas de mise à niveau de la base en attente, tous les pods en marche, 190 Go libres. Des choses qu’on veut savoir avant, pour pouvoir dire après si on a cassé quelque chose ou si c’était déjà cassé. - Qui est en ligne ? Cinq utilisateurs actifs dans les 15 dernières minutes. Deux redémarrages de Nextcloud et un de Collabora signifient que les documents Office ouverts seront déconnectés. Noté, accepté : c’est un mardi midi tranquille.
⚙️ Anatomie de l’exécution
| Étape | Durée | Pourquoi elle est là |
|---|---|---|
crictl pull Nextcloud + Collabora | 51 s | Les pods utilisent imagePullPolicy: IfNotPresent, donc K3s ne retélécharge jamais un tag de lui-même. Ici, le tag est figé sur une version de correctif précise, donc cela a surtout confirmé que l’image figée est toujours l’image figée. |
| Redémarrer Nextcloud | 42 s | Prend en compte une nouvelle image s’il y en a une. Le déploiement utilise la stratégie Recreate : un seul pod peut toucher aux volumes HostPath, il y a donc une courte interruption au lieu d’une relève progressive. |
| Redémarrer Collabora | 20 s | Même idée pour le serveur Office. |
occ upgrade | 2 s | Le point d’entrée du conteneur le lance déjà au démarrage ; ceci est le filet de sécurité. |
occ app:update --all | 2 s | audioplayer → 4.0.0. L’App Store ne propose que des versions compatibles avec la version majeure en cours, donc cela ne peut rien embarquer qui casse Nextcloud 34. |
| Redémarrer Nextcloud encore une fois | 43 s | La plus intéressante, voir ci-dessous. |
🧠 Pourquoi redémarrer deux fois ? L’OPcache et un réglage qui ne pardonne pas
La configuration PHP tourne avec opcache.validate_timestamps=0. C’est un réglage de performance : PHP compile chaque fichier une fois et ne revérifie plus jamais le fichier sur le disque pendant toute la durée de vie du processus. Excellent pour la vitesse, mais avec une conséquence fâcheuse pour les mises à jour.
Le premier redémarrage a lieu avant que occ n’écrive quoi que ce soit ; il sert à prendre en compte les images. Ensuite, app:update écrase les fichiers PHP de l’app sur le volume persistant, mais le PHP-FPM en cours continue de servir l’ancien bytecode depuis son cache. La mise à jour semble terminée, app:list affiche le nouveau numéro de version, et l’ancien code continue de tourner jusqu’au prochain redémarrage sans aucun rapport. Pour un correctif de sécurité, c’est le pire des « terminé ». D’où le second redémarrage, et uniquement si quelque chose a réellement changé.
Détail amusant : cela ne concerne que les apps mises à jour. Une app fraîchement installée n’a jamais été dans le cache, elle est donc compilée à neuf. Ce sont précisément les mises à jour qui, en silence, ne prennent pas effet.
🐛 Bug nº 2 : une tâche qui disait toujours « changed »
La tâche occ upgrade signalait changed alors qu’il n’y avait rien à mettre à niveau. Son changed_when cherchait l’absence de la phrase « already at the latest version », et Nextcloud 34 n’affiche plus cette phrase. Quand il n’y a rien à faire, il affiche désormais juste une note renvoyant à la documentation de mise à niveau. L’absence d’une chaîne qui n’existe plus est toujours vraie, donc la tâche annonçait toujours un changement.
# before: true forever on NC 34
changed_when: "'already at the latest version' not in occ_upgrade.stdout"
# after: only a real upgrade prints this
changed_when: "'Update successful' in occ_upgrade.stdout"Sans conséquence aujourd’hui, puisque la mise à jour de l’app a de toute façon déclenché le second redémarrage. Mais un playbook qui ment sur ses changements vous apprend à ignorer sa sortie, et un jour, cette sortie comptera. Leçon : se fier au signal positif, pas à l’absence d’un ancien.
🔍 Après l’atterrissage : la confiance n’exclut pas le contrôle
- audioplayer 4.0.0 activé ; la liste des apps désactivées est inchangée, donc rien n’a été activé ou désactivé dans mon dos.
- nextcloud.log depuis l’exécution : zéro avertissement, zéro erreur. Aucune erreur PHP dans le conteneur.
- Collabora : le discovery répond, le côté Nextcloud de la connexion est intact.
- Autotest de notify_push : les trois vérifications au vert. Le serveur push s’est reconnecté tout seul après les redémarrages.
- 5xx sur l’ingress : cinq requêtes, toutes venant de téléphones et de clients de synchronisation pendant les secondes où le pod redémarrait. Attendu avec Recreate ; les clients réessaient automatiquement.
🎯 À retenir
La mise à jour elle-même a été la partie la moins palpitante : une app, moins de trois minutes, des logs propres. La valeur se trouvait dans les marges. Un garde-fou qui rend impossible le comportement par défaut dangereux, un redémarrage qui n’existe qu’à cause d’un seul réglage de cache, et une vérification d’état qui mentait discrètement depuis la dernière version majeure. L’Infrastructure as Code ne rend pas les mises à jour magiques. Elle les rend ennuyeuses, et l’ennui, c’est exactement ce qu’on attend de ce qui touche à la production. 🧰




