CyberTrainDéployer

Déployer en production

Une application CyberTrain se livre sous la forme d’un seul binaire natif et d’un dossier à côté. Elle ne parle que le HTTP simple : c’est donc ce qui se trouve devant elle qui assure le HTTPS, kamal-proxy si vous déployez avec Kamal, ou Caddy sur un serveur que vous gérez vous-même. Cette page explique comment les pièces s’assemblent et en quoi les deux méthodes diffèrent ; les guides liés à chaque étape donnent toutes les commandes.

Il vous faut
Un serveur Linux accessible en SSH, et un nom de domaine
Ce qui tourne
Un binaire derrière un proxy inverse, avec SQLite à côté
Deux méthodes
Kamal et Docker, ou systemd et Caddy

Vous êtes ici:Exécution dist/

Ce qui tourne en production

PourquoiSavoir ce que fait le binaire, et ce qu’il laisse à d’autres, décide du reste de l’installation.

cybertrain build compile le framework, vos contrôleurs et modèles et l’interpréteur de gabarits dans dist/blog, avec toutes les vues intégrées, et copie public/ à côté. Rien d’autre n’est installé là où il tourne : ni Ruby, ni gems.

productiontext
browser ──HTTPS──▶ reverse proxy (kamal-proxy or Caddy)
                     └─ HTTP/1.1 ──▶ dist/blog (port 3000)
                                       ├─ public/  static files, 404.html, 500.html
                                       └─ storage/production.sqlite3
  • Il est lié à la SQLite et à la libc du système : construisez-le donc sur le même OS et le même CPU que la machine qui l’exécute. Le construire dans une image Docker, comme le fait la configuration Kamal, règle la question.
  • Il ne parle que le HTTP/1.1 simple. TLS et HTTP/2 sont l’affaire du proxy inverse. En production, le cookie de session est Secure : le site doit être servi en HTTPS, sinon les formulaires échouent avec Invalid authenticity token.
  • La base de données est un seul fichier SQLite. Faites tourner un seul processus sur un seul serveur, et gardez le fichier sur un stockage qui survit à un déploiement.
  • Il est en production par défaut et refuse de démarrer sans CYBERTRAIN_SECRET_KEY_BASE. ./blog migrate applique les migrations compilées dedans.

Deux façons de déployer

PourquoiLes deux mettent du HTTPS devant le même binaire ; elles diffèrent par l’endroit où il est construit et la façon dont un déploiement le remplace.

Kamalsystemd et Caddy
ConstructionDans une image Docker, sur votre machine ou un builder distantSur le serveur, depuis un clone git
En façadekamal-proxy, avec un certificat Let’s EncryptCaddy, avec un certificat Let’s Encrypt
Fichiers statiquesL’application sert public/Caddy sert lui-même dist/public/
Un déploiementLe nouveau conteneur reçoit le trafic une fois son contrôle de santé réussi : aucune connexion n’est refuséeUn redémarrage : quelques secondes de 500.html servi par Caddy
Revenir en arrièrekamal rollback VERSIONPointer current vers une version antérieure et redémarrer
Le serveur a besoin deSSH et Docker (installé par kamal setup), plus un registre d’imagesRuby, une chaîne de compilation C, les en-têtes SQLite, la CLI cybertrain et Spinel

Dans les deux cas, l’application est un processus et son fichier SQLite sur un seul serveur.

Déployer avec Kamal

Pourquoicybertrain new a déjà écrit les fichiers ; il vous reste à indiquer un serveur, un domaine et un registre.

  • Dockerfileune étape de build Ubuntu exécute cybertrain setup et cybertrain build ; une étape allégée de la même version ne reçoit que dist/ et les bibliothèques auxquelles il est lié
  • config/deploy.ymlle serveur, le domaine, kamal-proxy avec TLS vers le port 3000, le contrôle de santé et le volume de la base
  • .kamal/secretslit KAMAL_REGISTRY_PASSWORD et CYBERTRAIN_SECRET_KEY_BASE dans votre environnement, jamais les valeurs elles-mêmes
  • public/up.htmlla page que kamal-proxy interroge avant d’envoyer du trafic à un nouveau conteneur

Renseignez les valeurs marquées CHANGE ME dans config/deploy.yml, committez, puis :

terminal — blog/shell
export KAMAL_REGISTRY_PASSWORD=...
export CYBERTRAIN_SECRET_KEY_BASE="$(openssl rand -hex 32)"  # une seule fois ; conservez-la
kamal setup    # la première fois : Docker et kamal-proxy sur le serveur, build, push, démarrage
kamal deploy   # chaque déploiement suivant
  • Chaque déploiement construit l’image (Spinel reste dans le cache de couches de Docker après la première fois), la pousse et démarre un conteneur qui exécute ./blog migrate puis exec ./blog sur 0.0.0.0:3000.
  • kamal-proxy attend que /up.html réponde 200, bascule le trafic vers le nouveau conteneur, puis arrête l’ancien, qui termine ses requêtes en cours sur SIGTERM.
  • La base de données se trouve sur le volume blog_storage, monté en /app/storage : elle survit à chaque déploiement.
  • Réglez builder.arch sur le CPU du serveur. Spinel se compile dans l’image, donc construire pour une autre architecture sous émulation est lent ; construisez plutôt sur le serveur avec builder.remote.

Le guide pas à pas, sauvegardes du volume comprises, est docs/deploy-kamal.md. examples/blog embarque la même configuration, et la CI construit et teste son image.

Derrière Caddy, sous systemd

PourquoiSans Docker : le serveur construit l’application depuis git, systemd la maintient en marche, Caddy fait face à Internet.

  • L’application n’écoute que sur 127.0.0.1:3000 : rien ne l’atteint sans passer par Caddy. public/ et storage/ se résolvent depuis le répertoire de travail, donc systemd la démarre avec dist/ comme répertoire de travail et lit son secret dans un fichier d’environnement hors du dépôt.
  • Un script de déploiement clone chaque version dans son propre répertoire, vérifie que gen/ est à jour, exécute cybertrain build et dist/blog migrate, puis fait pointer le lien current dessus, redémarre le service et attend que up.html réponde ; sinon, le script revient à la version précédente. Une erreur avant la bascule laisse la version en service intacte. Revenir en arrière n’annule pas les migrations : elles doivent rester compatibles avec la version précédente ; un premier déploiement raté n’a rien vers quoi revenir et se termine simplement en erreur.
  • Caddy obtient le certificat, redirige HTTP vers HTTPS, sert lui-même les fichiers de dist/public/ et relaie tout le reste vers l’application. Pendant que l’application redémarre, il répond avec 500.html.
/etc/caddy/Caddyfilecaddyfile
blog.example.com {
	encode zstd gzip
	root * /srv/blog/current/dist/public

	@static file
	handle @static {
		file_server
	}

	handle {
		reverse_proxy 127.0.0.1:3000
	}

	handle_errors {
		rewrite * /500.html
		file_server
	}
}

L’application ajoute X-Content-Type-Options et X-Frame-Options à ce qu’elle sert ; les fichiers que Caddy sert depuis dist/public/ ne passent pas par elle, ajoutez-les donc dans le bloc du site si vous les voulez là aussi. nginx fonctionne de la même façon : terminer TLS, servir dist/public/, relayer le reste.

La procédure complète, d’un serveur Ubuntu neuf aux sauvegardes et retours en arrière, est docs/deploy.en.md (l’original japonais est docs/deploy.md).

Configurer

PourquoiLes réglages de production viennent de l’environnement : le même binaire tourne partout.

VariableEn production
CYBERTRAIN_SECRET_KEY_BASEObligatoire. Signe le cookie de session ; la changer déconnecte tout le monde. Générez-la une fois avec openssl rand -hex 32
CYBERTRAIN_DATABASELe fichier SQLite ; par défaut storage/production.sqlite3 sous le répertoire de travail. Gardez-le hors de la version déployée
CYBERTRAIN_HOST127.0.0.1 par défaut, ce qui convient derrière un proxy sur la même machine ; 0.0.0.0 dans un conteneur
PORT3000 par défaut ; là où le proxy transmet
CYBERTRAIN_ENVDéjà production dans un binaire construit ; development lancerait la surveillance des fichiers et les reconstructions

L’étape Compiler pour le déploiement du tutoriel liste toutes les variables et l’attribut config/app.rb correspondant.

L’exploitation au quotidien

  • Chaque modification est un déploiement. Les vues sont intégrées à la compilation, donc même une modification de vue seule demande une reconstruction et un redémarrage. Committez gen/ avec la modification : le script de déploiement s’arrête sur un gen/ périmé.
  • Les migrations passent avant que le nouveau code ne serve : dans le script de déploiement, ou au démarrage du conteneur. Supprimez une colonne lors d’un déploiement ultérieur, quand plus aucun code en service ne la lit.
  • Sauvegardez avec .backup de SQLite, pas en copiant le fichier : la copie est cohérente même pendant que l’application écrit.
  • Revenir en arrière par-delà une migration implique de ramener aussi la base, avec db rollback depuis la version la plus récente, avant de basculer.
  • L’arrêt est en douceur : sur SIGTERM, le serveur cesse d’accepter, termine les requêtes en cours et quitte, au bout de 10 secondes au plus.

Pour aller plus loin