Aller au contenu

Services & déploiements

Un service est une application déployée : web ou worker. Il se crée depuis un dépôt Git (build automatique) ou une image Docker pré-construite (pull).

Un service dispose de deux espaces de stockage bien distincts. Les confondre est la première cause de perte de données, alors voici la différence en une phrase chacun.

Le disque applicatif est l’espace de travail du service, taillé dans la machine qui l’héberge. Il est éphémère : il repart vide à chaque déploiement, à chaque redimensionnement, et à chaque fois que la machine est recréée. Il est inclus dans le prix de la machine, sans ligne séparée sur votre facture. Tout ce que votre application y écrit — base SQLite, fichiers téléversés, cache généré — disparaît sans avertissement au déploiement suivant.

Le volume persistant est un disque commandé séparément et rattaché à votre service. Il survit aux déploiements, aux redémarrages et à la destruction de la machine : c’est le seul endroit où poser des données que vous ne voulez pas perdre. Il est facturé à part, tant qu’il existe, occupé ou non. Il est détruit avec la ressource à laquelle il est attaché — supprimer le service supprime son volume et son contenu.

Disque applicatifVolume persistant
Survit à un déploiementNonOui
Survit à la destruction de la machineNonOui
FacturationInclus dans la machineLigne séparée, tant qu’il existe

| Fin de vie | Avec la machine | Avec la ressource (service ou stack) |

Dans la fenêtre d’ajout d’un service, onglets Git, Docker et Modèle (pour un modèle d’application — une base managée se règle sur son add-on, voir Add-ons), cochez Stockage persistant et indiquez :

  • une taille en Go ;
  • un point de montage, le chemin absolu où le volume apparaît dans le conteneur. C’est le champ qui compte : il doit correspondre au répertoire où votre application écrit réellement. Monté à côté, le volume reste vide et vous perdrez quand même vos données. Les modèles du catalogue proposent le chemin correct pré-rempli ; ne le changez que si vous savez que l’application écrit ailleurs.

Quatre conséquences à connaître avant de valider :

  • Emplacement — le volume est créé dans la zone de votre service et n’en bouge plus. C’est lui qui fixe désormais l’emplacement : un service à volume est redéployé là où vit son volume, même si votre région préférée change.
  • Coût — la taille demandée est facturée tant que le volume existe, montée ou non, et quelle que soit la place réellement utilisée. Elle compte aussi dans le quota de stockage de votre plan, en plus du disque applicatif du service.
  • Suppression — supprimer le service détruit le volume qui lui est attaché, et les données qu’il contient. Détacher le volume d’abord est justement la façon de le conserver : c’est la suppression de la ressource qui emporte le volume, pas une impossibilité générale de le détacher (voir l’onglet Stockage ci-dessous).
  • Mise en veille — le volume est détaché avant la destruction de la machine, puis rattaché au réveil (voir l’encadré ci-dessus).

Pour une stack Docker Compose, les volumes sont ceux que déclare votre compose.yml (qui fixe aussi leur point de montage) : leur taille est celle que le compose déclare.

L’onglet Stockage : attacher, détacher, agrandir

Section intitulée « L’onglet Stockage : attacher, détacher, agrandir »

Chaque service et chaque stack a un onglet Stockage. Il montre les volumes que la ressource monte — taille, état, point de montage et coût mensuel — et, en dessous, vos volumes détachés : ceux qu’aucune ressource ne porte, et qui restent facturés tant qu’ils existent. C’est le seul endroit où ils apparaissent, parce qu’ils n’appartiennent plus à rien.

  • Attacher — deux façons d’y arriver, toujours proposées ensemble :

    • un volume existant : la liste ne propose que ceux de la zone de votre ressource (un volume bloc ne franchit pas les zones) et actuellement détachés. Si elle est vide, l’écran vous le dit plutôt que de vous présenter un choix impossible ;
    • un volume neuf : nom, taille et point de montage, créé et attaché en un seul geste — sans avoir à en créer un ailleurs (à la création d’un autre service, ou via une restauration) pour revenir ensuite l’attacher. C’est le choix le plus courant : la plupart du temps vous n’avez aucun volume détaché sous la main.

    Dans les deux cas, le volume est monté au prochain démarrage du conteneur — jamais à chaud.

  • Détacher — possible seulement lorsque la ressource est arrêtée (ou en veille). Détacher un volume monté pendant que l’application écrit dedans corrompt le système de fichiers : si la ressource tourne, l’écran refuse et vous indique de l’arrêter d’abord. Une fois détaché, le volume est conservé, reste facturé (le fournisseur le facture qu’il soit rattaché ou non) et pourra être rattaché plus tard à une ressource de la même zone. Supprimez-le si vous n’en avez plus besoin.

  • Agrandir — un volume ne peut que grandir, jamais rétrécir : ni le fournisseur ni le système de fichiers ne savent réduire un disque sans détruire les données qu’il contient. L’espace ajouté est facturé dès qu’il est provisionné, avant même que vous l’utilisiez.

Ces gestes sont asynchrones : l’écran affiche l’opération en cours (« attachement », « détachement », « redimensionnement ») et se met à jour seul dès qu’elle aboutit.

Un volume survit à la destruction de sa machine, mais il n’en existe qu’un exemplaire : une suppression accidentelle ou une donnée corrompue ne se rattrapent pas avec lui seul. La sauvegarde répond à ça — elle copie le contenu du volume dans le stockage objet de la plateforme, hors de la machine et du disque.

Ce stockage est aujourd’hui dans la même région que la plateforme : une sauvegarde vous protège d’une erreur, d’une perte de machine ou de disque, pas d’un sinistre de toute une région.

Ce qu’il faut savoir avant de cliquer :

  • Le volume doit être attaché. Une sauvegarde relit le système de fichiers, ce qui suppose une machine qui le monte. Un volume détaché ne peut pas être sauvegardé : rattachez-le d’abord.
  • La région est affichée pour chaque sauvegarde : c’est celle où l’archive est réellement déposée. Tant que l’archive est en cours d’écriture, l’écran le dit plutôt que de l’inventer.
  • La sauvegarde est facturée au stockage, comme les sauvegardes de bases. Demander sa suppression arrête la facturation immédiatement, avant même que l’archive ait disparu.
  • Elle expire au terme de la rétention de votre offre, et la date de suppression est affichée. Cette échéance est fixée à la création : changer d’offre ensuite ne raccourcit pas les sauvegardes déjà prises.
  • Cohérence : l’archive est prise pendant que le service tourne. Elle se relit comme après une coupure de courant — ce qui convient à des fichiers, mais pas à une base de données en écriture. Pour une base, utilisez un add-on, qui est sauvegardé à chaud et proprement.

Une archive d’un disque en cours d’écriture est « cohérente après coupure de courant » : suffisant pour des fichiers, risqué pour une base de données. Avant l’archive, Cassiope demande donc au conteneur qui monte le volume d’écrire un dump logique dans le volume (retiré après l’archive) :

  • Détection par image : postgres, mysql/mariadb, mongo, redis. Rien à configurer.
  • Autre image : dans la carte du volume, Options avancées — hook de sauvegarde, saisissez la commande de dump. Elle s’exécute dans votre conteneur et son sortie standard est le dump.
  • Désactiver : décochez le hook. Si le dump échoue, la sauvegarde échoue (visible, jamais silencieuse) ; corrigez la commande ou désactivez le hook.

Chaque sauvegarde indique si un dump applicatif est inclus ou si elle est seulement cohérente après coupure. Fonctionne pour les volumes de services comme de stacks.

Précisions :

  • Seuls les conteneurs qui montent ce volume sont considérés ; le premier dont l’image est reconnue est dumpé (un seul dump par volume). Une application qui ne monte pas le volume de la base est ignorée. Avec une commande saisie, elle s’exécute dans le premier conteneur qui monte le volume.
  • Le dump est écrit dans le dossier .cassiope-backup/ du volume (dump.sql, dump.archive, dump.rdb, ou dump pour une commande saisie). Il est inclus dans l’archive, puis retiré du volume en service.
  • Il n’est pas rechargé automatiquement à la restauration. Le volume restauré contient les fichiers bruts de la base et le dossier .cassiope-backup/ ; rechargez le dump vous-même si besoin (psql -f dump.sql, mysql < dump.sql, mongorestore --archive=dump.archive, ou copie de dump.rdb dans le répertoire de données de Redis).

Une sauvegarde est une archive : elle ne se « monte » pas telle quelle. La restauration la déverse dans un volume neuf, la contrôle, puis seulement la substitue à l’ancien volume. Seule une sauvegarde terminée peut être restaurée (bouton Restaurer de la carte « Sauvegardes » ; une sauvegarde en échec ou en cours de suppression ne l’est pas).

Remplacer un volume, au même point de montage

  1. Arrêtez la ressource (service ou stack) qui monte le volume.
  2. Restaurer, choisissez le volume à remplacer puis confirmez.
  3. Cassiope crée un volume neuf (<nom>-restauration) et y déverse l’archive. Le volume actuel n’est pas touché pendant ce temps.
  4. Contrôle de fiabilité : la taille et l’empreinte SHA-256 de l’archive lue sont comparées à celles enregistrées à la sauvegarde. Au moindre écart, la restauration échoue, le volume neuf est marqué en erreur et votre volume actuel reste en place.
  5. Contrôle réussi : l’ancien volume est détaché et renommé <nom>-avant-restauration ; le volume restauré prend son nom et son même point de montage.
  6. Au prochain démarrage de la ressource, le volume restauré est utilisé.

L’ancien volume est conservé (détaché, donc toujours facturé) : c’est votre filet de retour arrière. Quand vous avez vérifié, supprimez-le depuis la carte Volumes détachés (voir ci-dessous). Cassiope n’écrase jamais un volume en place : un échec à mi-chemin vous laisserait des données ni anciennes ni nouvelles.

Si la bascule échoue après le détachement de l’ancien volume, vos données restent intactes (l’ancien volume est détaché, le restauré existe) mais le point de montage doit être rétabli à la main ; l’erreur est affichée sur le volume.

Supprimer un volume détaché

Le bouton Supprimer de la carte « Volumes détachés » détruit le disque chez le fournisseur : c’est irréversible, et la facturation du disque s’arrête. Par défaut, le contenu est d’abord archivé au stockage objet (case « Sauvegarder le contenu avant de supprimer »). Cassiope prête pour cela une machine de la même zone, y monte le volume le temps de l’archive, puis le détache. Si l’archive échoue, le volume n’est pas supprimé. L’archive est facturée au stockage objet jusqu’à ce que vous la supprimiez (carte « Sauvegardes ») ; elle peut servir à restaurer plus tard. Décochée, la suppression est définitive et le contenu est perdu.

Restaurer vers un nouveau volume (sans remplacer) reste possible par l’API (POST /v1/volumes/backups/{id}/restore) : vous choisissez la ressource d’accueil et le point de montage, qui n’a pas à être celui de l’original.

Tant qu’un volume est en cours d’attachement, de détachement, d’agrandissement, de suppression ou de restauration, la ressource (service ou stack) est verrouillée : démarrer, arrêter, mettre en veille, déployer, revenir en arrière, supprimer et les gestes sur ses autres volumes sont refusés (boutons grisés, bandeau d’explication). Ce verrou se lève tout seul à la fin de l’opération. Une restauration interrompue ou en erreur ne verrouille rien : vous pouvez détacher puis supprimer le volume provisoire. La suppression d’un add-on est de même refusée pendant son provisionnement, son redimensionnement ou une restauration.

  • Git — fournissez le fournisseur et le dépôt. Pour GitHub, la branche par défaut (main, master…) se résout automatiquement (que vous passiez par le picker de dépôts ou que vous tapiez/collez le dépôt à la main) et pré-remplit le champ ; la même résolution est refaite à la création côté serveur si vous n’avez pas choisi de branche vous-même, y compris pour un service créé hors formulaire (API, agent MCP) — une branche fausse ne fait pas qu’échouer le clone, elle fait aussi conclure à tort que le dépôt n’a pas de Dockerfile. Dès le dépôt connu, un menu déroulant liste ses autres branches (cliquer le champ Branche les affiche) sans jamais bloquer la saisie libre d’une branche non listée. La méthode de build se détecte aussi automatiquement : un Dockerfile à la racine du dépôt bascule sur dockerfile, sinon railpack (avec sa propre auto-détection de langage) — réglage disponible dans « Options avancées », modifiable à tout moment vers railpack, nixpacks ou dockerfile. Cette détection est refaite au moment de la création, y compris quand le service est créé hors du formulaire (API, agent MCP) : le Dockerfile du dépôt est la recette écrite et testée par ses auteurs, et il est plus fiable qu’une reconstruction devinée — les monorepos, en particulier, mettent souvent les build packs en échec. Si vous choisissez vous-même la méthode, votre choix est conservé tel quel et la détection ne s’y substitue jamais. Le port exposé se pré-remplit lui aussi depuis la dernière instruction EXPOSE <port> du Dockerfile quand elle déclare un port numérique fixe (sinon, ex. avec railpack/nixpacks ou un port injecté au runtime via $PORT, le champ reste vide) — modifiable à tout moment ; vide à la création, 3000 est utilisé par défaut. Enfin, « Options avancées » permet de décrire la forme du build quand la détection ne peut pas la deviner : répertoire de base, commande d’installation, commande de build, répertoire publié. Le cas typique est le monorepo, où la commande de build de la racine délègue à un sous-paquet — une délégation qui peut repartir de la racine et faire tourner le build en rond jusqu’à l’échec. Chaque champ laissé vide reste détecté automatiquement ; les quatre sont indépendants. Ils restent modifiables après coup depuis Configuration avancée, sur la page du service — c’est là qu’on corrige un build cassé sans recréer le service. Une réserve : vider un champ déjà enregistré cesse de l’imposer, mais la dernière valeur envoyée reste appliquée au build existant ; revenir vraiment à la détection automatique demande de recréer le service. Branche et méthode de build y sont aussi modifiables : un service parti sur la mauvaise branche ou le mauvais moteur de build se corrige sans être recréé. La méthode de build, elle, n’est détectée qu’une fois, à la création — changer de branche ensuite ne la recalcule pas.
  • Image — fournissez la référence d’image et les ports exposés ; identifiants de registre pour une image privée. Les images hébergées par le registry interne de Cassiope (celles de vos propres builds et du catalogue) ne se saisissent pas ici : une référence vers une image de la plateforme hors catalogue est refusée, pour qu’aucun compte ne puisse tirer l’image d’un autre.

Le nom du service se pré-remplit automatiquement depuis le dépôt (ou l’image), avec un suffixe numérique en cas de collision avec un service existant dans l’environnement — modifiable à tout moment avant de créer.

Si le dépôt renseigné contient un docker-compose.yaml/.yml (ou compose.yaml/.yml) à sa racine, le fichier est validé immédiatement. S’il n’est pas déployable en l’état — cas fréquent d’un compose destiné au développement local, qui publie des ports sur l’hôte ou monte des chemins absolus — les raisons sont affichées et aucune stack n’est proposée : continuez en service unique. Sinon, le compose trouvé vous est signalé, avec son chemin : ce dépôt peut devenir une stack multi-conteneurs plutôt qu’un service unique. Le choix se fait dans ce même formulaire, sur le sélecteur « Déployer : Un service / Une stack » — sans changer d’écran ni ressaisir quoi que ce soit. Ce sélecteur est toujours présent, même si aucun compose n’a été détecté (forge auto-hébergée, dépôt privé) : le chemin du compose se saisit alors à la main.

Le type vaut web par défaut ; worker (service sans adresse publique) et cron se choisissent sous « Options avancées ».

Healthcheck et port : ce que la plateforme peut garantir

Section intitulée « Healthcheck et port : ce que la plateforme peut garantir »

Cassiope pose une sonde de santé permissive sur les services qu’elle construit avec un build pack (railpack, nixpacks) : elle compose ces images et sait donc ce qu’il y a dedans.

Sur une image qu’elle ne compose pas — build depuis votre Dockerfile, ou source image — aucune sonde n’est posée par défaut : rien ne garantit qu’un client HTTP (curl) existe dans l’image, et une sonde impossible ferait échouer un déploiement parfaitement sain. Si votre image déclare son propre HEALTHCHECK, Docker l’applique. Sinon, renseignez une commande dans Configuration avancée (les images Alpine embarquent wget, pas curl).

Même logique pour le port : il est lu dans l’instruction EXPOSE de votre Dockerfile. S’il n’y en a pas, 3000 est utilisé — un défaut, pas un constat. Un Dockerfile qui se termine par un serveur nginx écoute en général sur 80 : vérifiez le port, sinon le routage et la sonde viseront un port où personne n’écoute.

github, gitlab et bitbucket acceptent un raccourci owner/repo. Pour tout autre hébergeur compatible Git (Codeberg, Forgejo, GitLab/Bitbucket self-hosted…), choisissez generic : le dépôt doit alors être une URL complète (https://forge.example.com/org/repo ou git@forge.example.com:org/repo.git) — il n’y a pas d’hôte connu à déduire d’un simple owner/repo.

Si vous choisissez generic mais que l’URL pointe vers github.com, gitlab.com ou bitbucket.org, la plateforme le reconnaît et garde toutes ses détections actives (branche par défaut, Dockerfile, port). Sur une forge réellement auto-hébergée, en revanche, rien n’est détecté : la branche vaut main et le build passe par un build pack, sauf si vous renseignez ces champs vous-même.

C’est l’URL qui décide du mode de clonage, il n’y a pas de case « dépôt privé » à cocher :

  • HTTPS (https://gitlab.com/org/repo.git) → clonage anonyme, aucune clé. Pour les dépôts publics.
  • SSH (git@gitlab.com:org/repo.git) → clonage authentifié par une clé de déploiement. Pour les dépôts privés.

Une URL de dépôt en SSH (git@… ou ssh://…), quel que soit le fournisseur, déclenche automatiquement une deploy key dédiée à ce service : une paire de clés est générée à la création, et sa clé publique apparaît dans les paramètres du service (page Aperçu). Ajoutez cette clé comme deploy key en lecture seule sur votre hébergeur Git avant de déployer — sans cela, le clonage échouera au build. La clé privée n’est jamais affichée ni exposée par l’API.

Sur la page Paramètres du tenant, connectez votre compte GitHub (OAuth, une connexion par tenant). Une fois connecté, le champ « Dépôt » du formulaire de création devient un picker : recherchez et sélectionnez un de vos dépôts (publics ou privés) au lieu de saisir une URL à la main. Pour un dépôt privé choisi via le picker, la deploy key est auto-posée sur GitHub (API, scope repo) — aucune étape manuelle. Le clone lui-même passe toujours par la deploy key SSH ci-dessus ; la connexion GitHub ne sert qu’à parcourir + automatiser sa pose. Déconnectable à tout moment depuis Paramètres.

Un modèle déploie une brique connue sans rien avoir à configurer : vous choisissez n8n, Excalidraw ou une autre entrée du catalogue, et le service est créé avec sa source, sa méthode de build, son port d’écoute, sa sonde de santé et ses variables d’environnement déjà réglés. Ces valeurs sont maintenues par Cassiope et résolues au moment de la création : quand une entrée du catalogue est corrigée, la correction vaut pour toutes les créations suivantes, sans que vous ayez quoi que ce soit à refaire.

Vous restez libre des ressources (vCPU, RAM, disque). Chaque modèle annonce toutefois un minimum en dessous duquel la brique ne démarre pas — n8n, par exemple, exige 512 Mo pour charger son éditeur de workflows. Une demande en dessous de ce seuil est refusée avec la valeur exigée, plutôt que corrigée en silence : c’est votre quota, la décision de le consommer vous appartient.

Certains modèles posent des variables d’environnement, dont des secrets tirés au hasard pour votre service seul (n8n reçoit ainsi sa clé de chiffrement N8N_ENCRYPTION_KEY). Elles sont visibles — et modifiables — dans l’onglet Variables du service, les secrets restant masqués.

La plupart des modèles produisent un service autonome : rien n’est branché automatiquement. Pour rattacher une base managée à un service quelconque, utilisez « + Add-on », qui relève d’une autre mécanique (voir Add-ons) — un add-on est une brique à laquelle on se connecte, avec ses identifiants, ses sauvegardes et sa consultation ; un modèle est une application qui tourne.

Quelques briques ne sont pas utilisables sans base de données. n8n, par exemple, range sinon ses workflows et ses identifiants dans un fichier local : le disque d’un service étant remis à neuf à chaque déploiement, tout disparaîtrait au premier redéploiement — sans erreur, l’application redémarrant simplement vide. Ces modèles annoncent la base sur leur carte (« + PostgreSQL managé »), et la jauge de capacité la compte avant que vous ne validiez : ce qui sera facturé est visible au moment du choix.

La création enchaîne alors trois étapes : le service, la base, puis la liaison entre les deux. Si une étape échoue après la création du service, Cassiope vous dit laquelle et pourquoi — un quota d’add-ons atteint, par exemple, s’affiche comme tel. Le service, lui, existe déjà : vous terminez depuis l’onglet Connexions du service. La base est liée sous la clé que le modèle déclare ; certaines applications ne savent pas lire une URL de connexion complète et reçoivent alors les cinq composantes séparées (..._HOST, _PORT, _DATABASE, _USER, _PASSWORD). Comme pour toute liaison, les variables sont injectées au déploiement suivant : déployez le service une fois la base liée.

Le modèle Matrix crée une messagerie privée en deux services : le serveur Matrix (Tuwunel) et le client web Element, déjà pointé sur ce serveur. Sa carte l’annonce (« + Element créé avec »), et la jauge de capacité compte les deux. Element est créé juste après le serveur, sous le nom <votre nom> · Element, puis connecté au serveur (onglet Connexions) : c’est cette connexion qui lui donne l’adresse du serveur à chaque déploiement. Si une étape échoue, le message dit laquelle ; le serveur existe déjà et vous terminez depuis le catalogue ou l’onglet Connexions.

Il n’y a rien à saisir : le formulaire est celui de tout modèle. Bon à savoir :

  • Code d’invitation — tiré au hasard à la création, et demandé par Element à chaque création de compte (« Jeton d’enregistrement »). Il est affiché sur la page du serveur, avec un bouton pour le copier et le transmettre aux personnes que vous invitez. Le premier compte créé devient administrateur.
  • Stockage persistant — coché d’office sur /var/lib/tuwunel : comptes, salons et messages y vivent. Sans lui, tout disparaît au premier redéploiement.
  • Nom du serveur — il entre dans chaque identifiant (@alice:<nom>) et il est figé au premier déploiement : Matrix refuse ensuite d’en changer. Par défaut, c’est l’adresse attribuée par la plateforme (…apps.cassiope.eu). Pour des identifiants à votre nom (@alice:matrix.acme.fr), ajoutez votre domaine dans l’onglet Domaines du serveur et faites-le vérifier avant de le déployer — l’onglet vous le rappelle. Ajouté après, le domaine sert d’adresse d’accès, mais les identifiants gardent l’ancien nom.
  • Fédération coupée — le serveur n’échange pas avec les autres serveurs Matrix (matrix.org…). Pour l’ouvrir, passez TUWUNEL_ALLOW_FEDERATION à true puis redéployez.

Déployez les deux services. Element ouvre alors son écran de connexion sur votre serveur : « Créer un compte », saisissez le code d’invitation, et vous êtes connecté.

Element Web est fait pour un ordinateur ; sur téléphone, il propose les applications Element (iOS, Android), à connecter à l’adresse de votre serveur. Si, à la fin de l’inscription, Element affiche « Impossible de configurer les clés », le compte est bien créé : relancez la configuration depuis Paramètres › Sécurité et vie privée, qui redemande votre mot de passe.

Créé seul, le modèle Element ne demande rien non plus : il se connecte à matrix.org. Pour le pointer sur votre propre serveur, connectez-le au service Matrix depuis l’onglet Connexions avec le préfixe MATRIX, puis redéployez-le.

Chaque déploiement de la liste se déplie sur ses logs de build. Un bouton Copier y place l’intégralité des logs dans le presse-papiers, suivis du diagnostic après déploiement quand il y en a un — c’est le couple à joindre à un ticket ou à un message de support.

Le bouton confirme ce qui s’est réellement passé : « Copié » seulement si la copie a abouti, « Échec » sinon (il reste alors à sélectionner le texte à la main). Sur mobile, la copie fonctionne aussi bien en HTTP local qu’en HTTPS.

Le nom par défaut ne vous convient plus ? Cliquez sur le crayon à côté du nom, en haut de la page du service, modifiez-le puis validez avec Entrée (Échap annule). Seul le nom affiché change : l’adresse du service, ses domaines et ses déploiements restent identiques. Cela fonctionne à tout moment, y compris après le premier déploiement.

  • Déployer — déclenche un build + déploiement (asynchrone). Suivez le statut jusqu’à running.
  • Arrêter / Démarrer — met en pause ou relance le service. Le service garde sa place sur le serveur qui l’héberge.
  • Mettre en veille — voir ci-dessous. À ne pas confondre avec « Arrêter ».
  • Redimensionner — ajuste CPU, RAM et disque depuis le panneau « Redimensionner » (curseurs vCPU / RAM / Disque). Recrée le conteneur. Réduire le disque n’efface aucune donnée persistée — il est éphémère — mais un build volumineux peut manquer de place, et l’écran vous le signale.
  • Rollback — revient à un déploiement réussi antérieur.
  • Purger les images de rollback — libère de l’espace de stockage (voir ci-dessous). Bouton sur la carte Ressources du service, également disponible par l’API et l’agent MCP.

La veille détruit ce qui coûte et conserve ce qui compte : les conteneurs sont supprimés, la capacité est rendue au pool, et si votre service tourne sur un serveur dédié, la machine elle-même est détruite — c’est la seule façon d’arrêter d’en payer la réservation. Vos add-ons et toute votre configuration sont conservés.

C’est ce qui la distingue d’un arrêt : un service arrêté garde sa place (et, sur un serveur dédié, son coût) ; un service en veille la rend. Le statut affiché est « en veille », et non « arrêtée ».

Le réveil (Démarrer) est un redéploiement : le service repasse par le placement, puis redémarre l’image qui tournait au moment de la mise en veille, sans rien reconstruire. C’est plus long qu’un simple démarrage, et c’est la contrepartie assumée d’avoir tout libéré.

Réveiller un service, c’est reprendre la version qui tournait, pas livrer les commits poussés sur la branche pendant la veille : pour ceux-là, lancez un déploiement. Si cette image n’existe plus (purgée), le réveil reconstruit le service depuis sa source, comme un déploiement ordinaire.

Refus possible : un service qui consomme un add-on ne peut pas être mis en veille. Sa connexion dépend d’être hébergé au même endroit que l’add-on ; un réveil ailleurs la casserait. Retirez le lien avant, ou mettez le groupe entier en veille.

Chaque service dispose d’un disque applicatif (10 Go par défaut, réglable de 1 à 100 Go au curseur, à la création comme au redimensionnement). Il est éphémère, au pied de la lettre : rien n’y survit à un redéploiement. Les données qui doivent durer vivent sur un volume persistant, dans un add-on ou dans un stockage objet.

Ce disque est inclus dans le prix de la machine — il n’ajoute pas de ligne à votre facture, contrairement à un volume persistant. Il compte en revanche dans le quota de stockage de votre plan, au même titre que le disque de vos add-ons, vos volumes persistants et les volumes déclarés de vos stacks.

Chaque déploiement réussi publie une image immuable, conservée pour permettre le rollback. Ces images occupent de l’espace et entrent dans votre quota de stockage. Les couches partagées entre deux versions d’une même application ne sont comptées qu’une fois.

Quand le plafond est atteint, un nouveau déploiement est refusé — jamais une image supprimée automatiquement, car cela vous retirerait sans prévenir la possibilité de revenir en arrière. Deux issues :

  • purger les images de rollback du service — aujourd’hui via l’API (POST /v1/services/:id/prune-images) ou l’outil prune_service_images de votre agent MCP. L’image du dernier déploiement réussi n’est jamais supprimée : votre service reste redéployable et redémarrable. Vous perdez en revanche la possibilité de revenir aux versions antérieures ;
  • passer à un plan supérieur, dont le plafond de stockage est plus élevé.

Votre application ne choisit pas son port d’écoute, elle le reçoit. Cassiope injecte une variable d’environnement PORT qui vaut le port exposé du service, et route le trafic vers ce port — même convention que Heroku, Railway ou Render.

Votre code doit donc lire cette variable :

const port = process.env.PORT || 3000;
app.listen(port);
port = int(os.environ.get("PORT", 3000))

C’est la cause n°1 d’un service qui se construit correctement mais reste injoignable : une application qui écoute sur un port fixe pendant que la plateforme route vers un autre. Rien n’écoute là où l’on frappe, et vous obtenez une erreur de passerelle.

Vous pouvez définir PORT vous-même dans les variables d’environnement du service : votre valeur l’emporte. Pensez alors à aligner le port exposé du service sur cette même valeur.

Chaque service construit depuis un dépôt Git reçoit automatiquement une sonde de santé exécutée à l’intérieur du conteneur, toutes les 5 secondes. Elle vérifie qu’un serveur accepte bien les connexions sur le port exposé — sans juger le code HTTP retourné : une API qui répond 404 sur / parce qu’elle n’a pas de route racine reste parfaitement valide.

Cette sonde change ce que vous voyez pendant un déploiement. Le déploiement attend son verdict avant de se déclarer terminé : si l’application ne répond jamais, vous obtenez un échec explicite en moins d’une minute, au lieu d’un service annoncé « démarré » dont la page ne s’ouvre pas.

Si le nouveau conteneur ne devient jamais sain, le déploiement échoue et la version précédente continue de servir. Votre application en ligne n’est donc pas remplacée par une version qui ne démarre pas.

Onglet Déploiements d’un service → Configuration avancée → Commande de healthcheck.

Laissez le champ vide pour conserver la commande par défaut de la plateforme. Un champ vide ne veut pas dire « aucune sonde » : c’est celle que Cassiope choisit pour vous.

Renseignez une commande quand le défaut ne convient pas :

  • votre image ne contient pas curl (image tierce minimale, distroless, scratch) ;
  • votre application écoute sur un port interne différent du port exposé ;
  • vous préférez une route de santé dédiée, par exemple /healthz.
curl -s -o /dev/null --max-time 3 http://127.0.0.1:8080/healthz

La commande est exécutée dans le conteneur ; un code de sortie non nul répété dix fois de suite marque le service en échec. Un délai de grâce de 5 secondes au démarrage laisse l’application booter avant que les échecs comptent.

Les services créés depuis une image Docker n’ont pas de sonde par défaut — rien ne garantit qu’un client HTTP soit présent dans une image que vous fournissez. Renseignez une commande ici pour en activer une.

Les statuts transitoires (building, deploying, stopping, resizing…) indiquent une opération en cours ; le service converge vers un statut terminal. Les build logs aident à diagnostiquer un échec de build.

Un service dont le conteneur s’arrête, ou dont la sonde de santé échoue durablement, repasse en crashed même si le déploiement s’était bien terminé — une vérification périodique compare l’état affiché à l’état réel des conteneurs. Un service ne peut donc plus rester affiché « running » avec une page morte.

Captures d’écran à insérer.