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 aSTUDIO_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 cifait. 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
- Notez la tête de la production et vérifiez que rien n’attend d’être expédié. En membre,
GET /api/revisiondonne la révision ;GET /readyzdonnerpoMs, qui doit valoir0. Avec les métriques,studio_journal_revisionetstudio_journal_rpo_secondsdisent la même chose.
-
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>
-
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 nombackups-latest.json. Écrivez la configuration de l’application studio (sonSTUDIO_CONFIG_JSON) dans un fichier, en changeantworkDirpour 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" } }
-
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.jsonLa 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, etstoppedsi 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.
- 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), etSELECT path, blob FROM studio_files ORDER BY pathdonne les mêmes lignes. Sans accès à la base de production, comparez en membre :GET /api/ops?after=0(page par page, avecnext) face auSELECT rev, op_id FROM studio_ops WHERE state = 'confirmed' ORDER BY revde l’exercice.
-
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ôme | Cause | Correction |
|---|---|---|
restore: the project is not empty (<table> holds rows): restore into a new one | STUDIO_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 13 | Le moteur de votre machine n’est pas la version qui a fait la sauvegarde | Passer à 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és | Vérifier blobs.bucket et les identifiants Cellar |
restore restores a hosted project: store.kind is postgres | La configuration est une configuration locale | Prendre celle de l’application studio (étape 3) |
"stopped":"gap" (ou not-the-head, blob-missing) dans la dernière ligne | Le journal du bucket a un trou après la sauvegarde | La 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 required | Aucune URI de base dans le shell | Exporter 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
workDirde 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
restorela migre d’abord. Relancezrestoredessus ;replayré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 --deletesur 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
STUDIO_DATABASE_URL,STUDIO_S3_KEY_IDet les autres variables du Studio Server : Variables d’environnement.- La sauvegarde et la restauration :
studio-server/src/ops/backup.ts; le rejeu :studio-server/src/ops/ship.ts; les commandes :studio-server/src/server/main.ts. - Le test derrière la garantie :
tests/studio-backup.test.ts. - La conception : ADR 0025.