Aller au contenu
quest'n'click

Clever CloudGuidePour adminsS'applique de 4.2.2

Exercice de restauration sur une installation vierge

This page in EnglishCette page sur le wiki GitHub

Cet exercice restaure la dernière sauvegarde d’un Studio hébergé dans une base PostgreSQL neuve et vide, rejoue ce qui a été écrit depuis, puis compare le résultat à la production. La production n’est jamais touchée. Faites-le avant d’en avoir besoin : le jour où la base est vraiment perdue, vous connaîtrez déjà les commandes et leur durée.

Ce que vous obtenez

Une seconde base, créée pour l’exercice, qui contient le jeu à la même révision que la production : les lignes de la sauvegarde, puis chaque opération écrite après elle, relue dans le journal que le serveur expédie vers le bucket. Vous obtenez aussi une durée, à noter dans vos propres relevés, et la preuve que vos sauvegardes se restaurent.

Contexte et versions

  • Un Studio hébergé (le Studio Server) sur Clever Cloud : une application studio, son add-on PostgreSQL, son bucket Cellar.
  • À partir de la 4.2.2, version qui apporte restore --replay. La sauvegarde quotidienne vers le bucket (backup --to-bucket) existe depuis la 4.2.3 ; avant, prenez la sauvegarde à la main.
  • Vérifié sur : non vérifié sur une installation réelle pour cette page. La procédure est celle que le déploiement de référence de la 4.2.3 a suivie le 19 octobre 2026 (la mesure plus bas), mais personne n’a encore rejoué le texte de cette page sur une installation Clever Cloud réelle. Lisez chaque commande avant de la lancer.

Prérequis

  • Un Studio hébergé en marche, avec au moins une sauvegarde dans son bucket (backups/<date>-r<révision>.json). La sauvegarde quotidienne en écrit une quand l’application studio a STUDIO_BACKUP_CRON=1 (STUDIO_BACKUP_CRON).
  • clever-tools, connecté à l’organisation qui porte les applications.
  • Sur votre machine : le moteur dans la même version que l’application studio, npm ci fait. Une sauvegarde ne se restaure que dans le schéma de base de la version qui l’a faite.
  • Un outil S3 (la console Cellar, s3cmd, aws s3) et les identifiants Cellar du bucket, pour télécharger la sauvegarde.
  • psql, pour comparer les deux bases. Sans accès à la base de production, un compte de membre du Studio suffit (l’étape 5 dit comment).

Où lancer les commandes

  • clever … : sur votre machine, dans le dossier où l’application studio est liée (clever link).
  • npm run studio-server -- … : sur votre machine, dans le dépôt du moteur, à la version de l’application studio.
  • Jamais sur l’instance de production, et jamais avec l’URI de la base de production dans votre shell.

Étapes

  1. Notez la tête de la production et vérifiez que rien n’attend d’être expédié. En membre, GET /api/revision donne la révision ; GET /readyz donne rpoMs, qui doit valoir 0. Avec les métriques, studio_journal_revision et studio_journal_rpo_seconds disent la même chose.
  1. Créez un add-on PostgreSQL vide pour l’exercice, lié à aucune application, et lisez son URI :

    # sur votre machine, là où l'application studio est liée
    clever addon create postgresql-addon my-game-pg-drill --plan dev
    clever addon env <drill-addon-id>
  1. Téléchargez sur votre machine le dernier objet backups/ du bucket (n’importe quel outil S3, avec les identifiants Cellar), par exemple sous le nom backups-latest.json. Écrivez la configuration de l’application studio (son STUDIO_CONFIG_JSON) dans un fichier, en changeant workDir pour un dossier de votre machine. Le chargeur la vérifie comme le ferait le serveur :

    {
      "publicUrl": "https://studio.example.fr",
      "playUrl": "https://play.example.fr",
      "game": "my-game",
      "workDir": "/tmp/my-game-drill",
      "host": "0.0.0.0",
      "trustProxy": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
      "store": { "kind": "postgres" },
      "blobs": { "kind": "s3", "host": "cellar-c2.services.clever-cloud.com", "bucket": "my-game-studio" },
      "oidc": { "issuer": "https://keycloak.example.fr/realms/web-scumm", "clientId": "studio", "audience": "studio-api", "cliClientId": "web-scumm-cli" },
      "worker": { "url": "https://worker.example.fr", "instance": "my-game-studio" }
    }
  1. Faites pointer le serveur vers la base de l’exercice et vers le bucket, puis restaurez en chronométrant :

    # sur votre machine, dans le dépôt du moteur, même version que l'application studio
    export STUDIO_DATABASE_URL='<the drill add-on URI from step 2>'
    export STUDIO_S3_KEY_ID='<Cellar key id>' STUDIO_S3_KEY_SECRET='<Cellar secret>'
    time npm run -s studio-server -- restore backups-latest.json --replay --config drill.config.json

    La commande vérifie l’empreinte de la sauvegarde, ses tables et ses colonnes, et la présence dans le bucket de chaque blob que nomment la sauvegarde et le journal ; elle écrit les lignes, puis rejoue les opérations expédiées depuis la sauvegarde. Sa dernière ligne donne les lignes écrites, les lignes dropped, la révision de la sauvegarde, la révision atteinte, et stopped si le rejeu s’est arrêté avant la fin.

La vérification a lieu dans la transaction de la restauration, avant l’écriture de la première ligne (studio-server/src/ops/backup.ts) : viser la production par erreur à l’étape 4 est refusé, et la laisse telle qu’elle était. N’ayez quand même jamais l’URI de la production dans ce shell.

  1. Comparez, en lecture seule, sur les deux bases (psql <URI>) : SELECT value FROM studio_meta WHERE key = 'revision' donne la tête notée à l’étape 1 (ou une plus récente si des membres ont écrit entre-temps), et SELECT path, blob FROM studio_files ORDER BY path donne les mêmes lignes. Sans accès à la base de production, comparez en membre : GET /api/ops?after=0 (page par page, avec next) face au SELECT rev, op_id FROM studio_ops WHERE state = 'confirmed' ORDER BY rev de l’exercice.
  1. Notez la durée et les révisions dans vos relevés, puis supprimez l’add-on de l’exercice :

    # sur votre machine, là où l'application studio est liée
    clever addon delete my-game-pg-drill

Résultat attendu, et comment le vérifier

npm run -s studio-server -- restore … sort avec le code 0 et affiche une ligne JSON (-s écarte les lignes de npm), par exemple {"event":"restored","rows":593,"dropped":0,"backup":63,"revision":65}, sans stopped. La révision atteinte est la tête notée à l’étape 1, ou une plus récente. L’étape 5 montre les mêmes fichiers à la même révision dans les deux bases.

Erreurs courantes

SymptômeCauseCorrection
restore: the project is not empty (<table> holds rows): restore into a new oneSTUDIO_DATABASE_URL vise une base qui contient déjà un projet (la production, ou un exercice déjà fait)La faire pointer vers un add-on neuf et vide
restore: the backup is of schema 12, this server's is 13Le moteur de votre machine n’est pas la version qui a fait la sauvegardePasser à la version de l’application studio, npm ci, relancer
restore: 3 blob(s) the backup names are missing (first: …)Un autre bucket, ou une collecte les a supprimésVérifier blobs.bucket et les identifiants Cellar
restore restores a hosted project: store.kind is postgresLa configuration est une configuration localePrendre celle de l’application studio (étape 3)
"stopped":"gap" (ou not-the-head, blob-missing) dans la dernière ligneLe journal du bucket a un trou après la sauvegardeLa base contient la sauvegarde et ce qui a été rejoué ; notez-le, et tenez-en compte pour la sauvegarde suivante
STUDIO_DATABASE_URL (or POSTGRESQL_ADDON_URI) is requiredAucune URI de base dans le shellExporter l’URI de l’add-on de l’exercice (étape 4)

Fichiers ou données modifiés

  • L’add-on PostgreSQL de l’exercice : toutes ses tables, écrites par la restauration.
  • Le dossier workDir de votre configuration, sur votre machine.
  • Rien en production : ni sa base, ni son bucket (une restauration lit le bucket, elle n’y écrit jamais). Une nouvelle instance démarrée sur la base restaurée expédierait ses opérations suivantes sur une nouvelle ligne de journal, jamais par-dessus l’ancienne.

Reprise ou retour arrière

  • Les lignes sont écrites en une seule transaction. Si la restauration échoue à ce moment (une connexion perdue, un blob manquant, un autre schéma), rien de la sauvegarde n’est écrit : la base de l’exercice reste vide mais migrée, puisque restore la migre d’abord. Relancez restore dessus ; replay répondrait seulement « no restore is under way ».
  • Si le rejeu échoue après l’écriture des lignes, la base est marquée « restauration en cours » et le serveur refuse d’y démarrer. Reprenez avec npm run -s studio-server -- replay --config drill.config.json, ou supprimez l’add-on et recommencez.
  • Ne lancez jamais gc --delete sur la base de l’exercice : elle supprimerait des blobs que la production nomme encore.
  • Une restauration déconnecte tout le monde : les sessions et les baux ne sont pas dans une sauvegarde. Cela compte pour une vraie restauration, pas pour un exercice.

Références