Aller au contenu principal

Projet personnel

BackReel : restaurer un cluster Kubernetes à la seconde près

Le problème

Les outils de sauvegarde ne restaurent qu’aux instants de leurs sauvegardes planifiées. Les outils d’historique voient chaque changement, mais ne restaurent rien. Et les fournisseurs cloud limitent la fréquence des instantanés de disque : leurs API ne peuvent pas atteindre la seconde.

BackReel restaure un cluster Kubernetes, ses objets comme ses volumes, tel qu’il était à n’importe quelle seconde, sans sauvegarde planifiée.

Deux règles

  • Aucun accès à etcd. Tout passe par l’API Kubernetes, pour que les clusters managés restent à portée.
  • Chaque restauration annonce sa précision réelle. Un volume sans données est signalé avant la restauration, et un trou dans l’historique n’est jamais présenté comme une période calme.
API Kubernetessans etcdEnregistreurbackreel recordS3Object LockRestaurationà la secondePilote CSIchaque volumeAgentjournal ublkVolume restaurérestore-volumeAPI Kubernetessans etcdEnregistreurbackreel recordS3Object LockRestaurationà la secondePilote CSIchaque volumeAgentjournal ublkVolume restaurérestore-volume

Survolez ou sélectionnez une brique pour en lire le détail.

Les objets

Un enregistreur suit chaque ressource par l’API : des images complètes, les événements entre elles, et les trous de l’historique, signalés comme tels. history, at et diff relisent cet historique sans cluster. Un namespace est restauré tel qu’il était, après un essai à blanc et un diff.

Les Secrets sont chiffrés avec age avant d’être écrits, et ne sont pas enregistrés du tout sans clé publique. L’historique part dans un bucket compatible S3 ; avec Object Lock et une rétention par défaut, ni la suppression du cluster ni celle de l’historique ne peuvent l’effacer, et l’enregistreur prévient s’il n’en a pas.

Les volumes

Un agent écrit en Rust sert un disque ublk, en espace utilisateur, et journalise chaque écriture, avec un point cohérent à chaque flush. Une écriture n’est confirmée qu’une fois son enregistrement, et tous ceux qui le précèdent, dans le journal : ce qu’un arrêt brutal laisse hors du journal n’avait donc jamais été confirmé.

Dans Kubernetes, un pilote CSI écrit en Go enveloppe le pilote réel et place l’agent sur chaque volume. Le journal, découpé en segments, part dans le bucket, avec un VolumeSnapshot comme image de référence. restore-volume choisit la dernière image qui couvre l’instant demandé et en crée un nouveau volume ; un instant qu’aucune image ne couvre est refusé.

Ce qui est prouvé

  • PostgreSQL sous charge, reconstruit à des instants tirés au hasard : aucune ligne écrite après l’instant, aucune corruption.
  • L’agent tué avec -9 sous charge : un nouvel agent reprend le disque en moins d’une seconde, sans perdre une écriture confirmée.
  • 510 restaurations à des instants tirés au hasard, à travers 5 arrêts brutaux : aucune écriture confirmée perdue.
  • Dans Kubernetes, sous pgbench, l’agent tué deux fois et le plugin du nœud redémarré ne produisent que des pauses de moins d’une seconde : aucune transaction échouée.
  • Un disque reconstruit à partir d’un instantané pris sous charge et des segments du bucket est identique, octet pour octet, au disque lui-même.
  • Douze instants tirés au hasard sous pgbench, restaurés en nouveaux volumes : chaque ligne confirmée présente, aucune écrite après, chaque base saine.
  • Le nœud perdu avec des écritures jamais vidées : le volume restauré est le disque, octet pour octet, et non ce que le journal en avait expédié.

Ce que ça coûte

Mesuré et publié dans le dépôt, avec sa méthode. Sous PostgreSQL, le disque ublk sans journal coûte 32 % du débit ; le journal en prend 46 % de plus : 1 992 transactions par seconde au lieu de 3 708, et une latence p99 de 5,0 ms au lieu de 2,1 ms. Deux changements, une synchronisation unique à chaque flush et des écritures du journal par io_uring, ont fait passer la part du débit conservée de 36 % à 54 %. Ces mesures viennent d’une machine virtuelle locale, pas d’un cluster cloud.

Où en est le projet

L’enregistreur d’objets, le journal de blocs hors de Kubernetes, puis dans Kubernetes avec son pilote CSI : ces trois phases sont faites. Reste la démonstration sur un vrai cluster cloud.

← Retour aux projets