Skip to content

Un opérateur figé est indiscernable d'un opérateur au repos #241

Description

@BryanFRD

Le 2026-08-25, l'opérateur a cessé de réconcilier tous les FerrVaultSecret du cluster FerrLabs pendant plus de quatre heures. Aucun indicateur n'a bougé. La panne a été trouvée par hasard, en cherchant pourquoi une clé ajoutée dans un coffre n'arrivait pas.

La cause immédiate est corrigée par #240. Cette issue porte sur ce qui a rendu la panne invisible, et qui reste vrai après ce correctif.

Ce qu'on voyait pendant la panne

Signal Valeur Vérité
Pod Running, Ready figé
CPU 4m rien ne tourne
Sonde de vivacité verte le processus vit, mais ne travaille plus
Conditions des FerrVaultSecret Ready=True dernier état connu, jamais réévalué
status.lastSyncedAt 11:12:57 dernière fois où le CONTENU a changé
Journaux erreurs de watch toutes les 30 s seul signal réel, noyé

Aucun de ces signaux ne distingue « l'opérateur va bien et rien n'a changé » de « l'opérateur ne réconcilie plus rien ».

Les deux défauts, séparés

1. lastSyncedAt répond à la mauvaise question. Il n'est mis à jour qu'au changement de contenu. Un secret stable et un secret dont la synchro est morte présentent donc le même champ, figé au même endroit. Pendant le diagnostic, ce champ m'a fait conclure deux fois de suite, à tort, que la propagation fonctionnait.

Il manque un lastAttemptedAt (ou équivalent), écrit à chaque réconciliation aboutie, qu'elle ait changé quelque chose ou non. C'est ce champ, comparé à spec.refreshInterval, qui permet de dire « cette ressource aurait dû être revue il y a dix minutes ».

2. La sonde de vivacité ne teste que le processus. healthz répond tant que le binaire tourne. Or le mode de défaillance observé est précisément un binaire vivant dont la file de reconcile est bloquée. Une sonde qui échouerait quand aucune réconciliation n'a abouti depuis N fois l'intervalle le plus court aurait fait redémarrer le pod en quelques minutes, au lieu de quatre heures d'arrêt silencieux.

Pistes, à arbitrer

  • lastAttemptedAt dans le status, et une condition qui passe à False quand l'écart avec now dépasse un multiple de refreshInterval. C'est le minimum, et ça rend la panne visible dans un simple kubectl get.
  • Une métrique ferrvault_last_successful_reconcile_timestamp_seconds, par ressource ou globale. Le ServiceMonitor existe déjà dans le chart, donc l'alerte Prometheus suit naturellement.
  • Une sonde de vivacité qui a un avis, adossée à cette même horloge, pour que le cas « bloqué » se répare tout seul.
  • Un délai d'expiration sur le reconcile, pour qu'aucun appel ne puisse bloquer la file indéfiniment. C'est la protection générique : elle aurait couvert ce bug sans rien savoir des informers, et couvrira le prochain.

Ma préférence va au premier et au dernier : l'un rend la panne lisible, l'autre l'empêche de durer. Les deux autres sont utiles mais viennent après.

Critère d'acceptation

Reproduire le scénario — retirer list/watch sur apps et provoquer un changement de contenu sur un FerrVaultSecret déclarant un rolloutRestart — et vérifier que la panne devient visible sans lire les journaux, en moins de dix minutes.

Contexte

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High priorityenhancementImprovement to existing feature

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions