- Python 81.9%
- Shell 18.1%
|
|
||
|---|---|---|
| modeles | ||
| outils | ||
| .gitattributes | ||
| action.yml | ||
| README.md | ||
deploiement-vps : gabarits de déploiement sur le VPS Linux
Ce dépôt contient tout ce qu'il faut pour qu'un projet se déploie seul sur le VPS Linux à chaque arrivée sur main. Un projet n'a besoin que de :
- un
Dockerfilepar application (ou par site statique) ; - un manifeste
deploiement-vps.ymlà la racine, qui décrit ses applications ; - le workflow modeles/deployer.yml, copié tel quel dans
.forgejo/workflows/deployer.yml.
Rien d'autre à préparer sur le serveur. Au premier déploiement, l'action fait tout le nécessaire :
- elle construit les images ;
- elle crée le site dans la console du VPS : domaines, relais ou site statique, puis certificat ;
- elle crée la base PostgreSQL et son compte si le manifeste en demande une, et injecte la chaîne de connexion ;
- elle crée les dossiers de données, avec le bon propriétaire ;
- elle écrit les secrets déclarés et génère la composition Docker ;
- elle met en service, contrôle la santé et revient automatiquement à la version précédente en cas d'échec.
Les déploiements suivants refont la même chose : le manifeste du dépôt fait foi.
Démarrer un nouveau projet
-
Écrire le ou les
Dockerfile.- Conteneur : l'application écoute un port HTTP en clair. Caddy fait le HTTPS devant, depuis l'adresse fixe
172.18.0.250. - Site statique : l'image finale contient le site compilé dans
/site,index.htmlà la racine. Une étape finaleFROM busybox:1.37suffit.
- Conteneur : l'application écoute un port HTTP en clair. Caddy fait le HTTPS devant, depuis l'adresse fixe
-
Copier modeles/deploiement-vps.yml à la racine du projet et l'adapter.
-
Copier modeles/deployer.yml dans
.forgejo/workflows/deployer.yml. -
Pour une clé ou un mot de passe propre à l'application (clé JWT, clé de chiffrement…), préférer
secrets_generes: rien à créer. Pour un secret venu d'ailleurs (clé d'API d'un fournisseur), le déclarer danssecretset le créer dans Forgejo : Paramètres du dépôt > Actions > Secrets, noms en majuscules. -
Fusionner dans
main. L'onglet Actions du dépôt montre le déploiement. -
Le DNS se fait seul pour les noms des zones OVH du compte (
orbiteigroup.com,sates-doc.com,sates-doc.fr,sates-doc.net) : un enregistrement A vers le VPS (169.58.249.205) est créé pour chaque nom qui n'en a aucun. Un nom qui pointe déjà ailleurs (ancien serveur) n'est jamais modifié : on le bascule depuis la console (« Faire pointer ici ») ou chez le registraire. Pour un nom hors de ces zones, faire pointer le DNS à la main.Tant que tous les noms ne pointent pas sur le VPS, le site est en mode essai (certificat local). La console vérifie toutes les 5 minutes et passe seule en certificat Let's Encrypt dès que c'est le cas.
Plusieurs adresses et changements d'adresses. Un site sert tous les noms de sa liste domaines (avec ou sans www., sous-domaines, autres zones). Ajouter un nom au manifeste puis déployer : il est servi, son DNS créé s'il manque, son certificat obtenu. Retirer un nom : il n'est plus servi, et son enregistrement DNS est retiré seulement si c'est la console qui l'a créé et qu'aucun autre site ne s'en sert.
Le manifeste
version: 1
applications: # déployées DANS L'ORDRE ; un échec arrête la suite
- nom: ... # nom du conteneur, de l'image et du site (minuscules, chiffres, tirets)
type: conteneur # ou statique
...
Champs communs
| Champ | Rôle |
|---|---|
nom |
identifiant unique sur le VPS (dossier /srv/apps/<nom>, conteneur, image <nom>:<commit>, site de la console) |
type |
conteneur (relais Caddy vers le conteneur) ou statique (fichiers servis par Caddy) |
libelle |
nom affiché sur la page « service indisponible » |
dockerfile, contexte |
Dockerfile et contexte de construction, relatifs au dépôt (défaut : Dockerfile, .) |
arguments_construction |
--build-arg (dictionnaire) |
domaines |
noms servis ; le premier sert au contrôle de santé |
www_vers_nu |
www.x redirigé vers x (301), pour chaque paire présente dans domaines |
sante.chemin, sante.motif |
adresse vérifiée après mise en service (statut 200 à 399) et texte exigé dans la réponse |
sante.tous_statuts |
accepter tout statut HTTP : seul le motif compte |
Conteneur seulement
| Champ | Rôle |
|---|---|
port |
port écouté dans le conteneur (obligatoire) |
utilisateur |
uid de l'image. Les volumes et fichiers du serveur lui sont attribués avant chaque mise en service, après l'arrêt de l'ancien conteneur |
volumes |
sous-dossier: /chemin/dans/le/conteneur. Données persistantes dans /srv/apps/<nom>/<sous-dossier>, sauvegardées chaque nuit. Tout VOLUME déclaré par l'image doit y figurer, sinon Docker y place un volume anonyme vide qui masque les données |
fichiers_serveur |
chemin-sur-le-serveur: /chemin/dans/le/conteneur, monté en lecture seule (ou {cible: ..., ecriture: true}). Pour une configuration avec secrets déposée une fois à la main dans /srv/apps/<nom>/ et jamais écrasée. Absent, le déploiement s'arrête en le signalant |
environnement |
variables non secrètes |
secrets |
[NOM] ou {NOM_DU_SECRET: VARIABLE} : secrets Forgejo du dépôt, réécrits dans /srv/apps/<nom>/.env à chaque déploiement |
secrets_generes |
[VARIABLE] ou {VARIABLE: {format, octets, copie_en_preproduction}} : valeur tirée au sort sur le VPS au premier déploiement, écrite dans .env, puis jamais régénérée ni affichée. Rien à créer dans Forgejo. format : texte (lettres et chiffres, défaut), hex ou base64 ; octets : 16 à 128 (défaut 32). En préproduction, chaque secret généré a sa propre valeur (un jeton signé en préproduction n'ouvre pas la production), sauf copie_en_preproduction: true, à mettre sur une clé qui chiffre des données copiées depuis la production. Une même variable ne peut pas être à la fois dans secrets et secrets_generes |
postgres |
{base, utilisateur, variable, format} : base et compte créés sur le PostgreSQL commun s'ils n'existent pas, mot de passe généré et chaîne écrite dans .env (format Npgsql par défaut, format: url pour postgresql://…). Une variable déjà présente dans .env n'est jamais remplacée |
reseaux |
réseaux Docker en plus de web (bases est ajouté seul avec postgres) |
memoire, memoire_partagee |
mem_limit et shm_size. Sans memoire, la limite acceptée dans la console du VPS (proposée depuis le pic des 7 derniers jours) est reprise à chaque déploiement |
Statique seulement
| Champ | Rôle |
|---|---|
chemin |
dossier du site dans l'image (défaut /site) |
spa |
application monopage : une adresse inconnue sert index.html, sauf /api/* et les fichiers du service worker ; en-têtes de cache comme sous IIS |
proteger |
fichiers repris de la version en ligne (configuration propre au serveur, par exemple assets/app-config.json) |
Tests avant déploiement (facultatif, à la racine du manifeste) :
tests: # lancés AVANT toute construction ; un échec arrête tout
- nom: unitaires
image: mcr.microsoft.com/dotnet/sdk:10.0 # image où tourne la commande
commande: dotnet test MaSolution.sln -c Release
docker: false # true : Docker du VPS + réseau de l'hôte (Testcontainers)
delai: 1800 # secondes (défaut 1800)
environnement: {} # variables en plus
Chaque test tourne dans un conteneur jetable, sur une copie du code du commit (répertoire /src). Les caches NuGet et npm sont gardés dans des volumes Docker (deploiement-cache-*). Ne pas terminer la commande par un tube (| tail…) : le code de sortie serait celui du dernier programme, et un test en échec passerait. En urgence, la variable SANS_TESTS=1 de l'exécuteur les saute, mais c'est déconseillé.
Documentation seule : le workflow modèle ignore les commits qui ne touchent que la documentation (*.md, docs/, Documentation/, .claude/, _bmad-output/, LICENSE*) : rien n'est redéployé pour eux. Adapter la liste paths-ignore du workflow si un projet range sa documentation ailleurs.
Variante : l'entrée seulement de l'action (noms séparés par des virgules) ne déploie que les applications indiquées.
Ce que l'action écrit sur le serveur
/srv/apps/<nom>/compose.yamletdeploiement.conf: générés à chaque déploiement depuis le manifeste ;/srv/apps/<nom>/.env:IMAGE, les secrets Forgejo, les secrets générés et la connexion PostgreSQL. Les autres lignes, posées à la main, sont gardées ;- le site dans la console (
/srv/console-vps/etat/sites.json, puis Caddy). Ce que le manifeste ne précise pas est conservé, par exemple un en-tête secret vers l'application ajouté dans la console ; - une ligne au journal de la console par mise en service.
Les fichiers_serveur ne sont jamais écrits : seulement montés.
Fonctionnement
- action.yml : action composite. Elle clone le commit avec le jeton de la tâche, puis lance
outils/deployer.py. - outils/deployer.py : lit le manifeste et enchaîne construction, préparation du serveur, site de la console (
docker exec console-vps python3 /app/server.py site-assurer) et mise en service. - outils/vps-deployer.sh : la mise en service elle-même. Arrêt de l'ancien conteneur et
chown(crochetAVANT),docker compose up, stabilité pendant 20 s, santé, et retour à l'image (ou à la version statique) précédente en cas d'échec. Il garde 3 images et 5 versions statiques.
Tout s'exécute sur l'exécuteur Forgejo du VPS (étiquette vps-linux), qui a la main sur le serveur. Il est réservé au compte yannicktebi : ne jamais l'ouvrir à d'autres comptes ni à toute l'instance. Une modification de ce dépôt s'applique dès le déploiement suivant de chaque projet, puisque tous référencent @main.
Projets qui l'utilisent
OrbiteGroupe (orbite-api, orbite-desk, orbite-public), MyCVBuilder (mycvbuilder), PiloteEquipe (piloteequipe), sates-gestiondocumentconfidentiel (sates). Leurs manifestes sont de bons exemples.
Image de base suivie
Pour une application conteneur, l'image du dernier FROM du Dockerfile (celle qui tourne en production, étapes nommées suivies, ARG résolus) est récupérée juste avant la construction. Elle est inscrite sur l'image construite : vps.base=<image>@<empreinte>, avec vps.depot=<adresse du dépôt>. La console du VPS compare chaque jour cette empreinte à celle du registre. Si l'éditeur a publié une nouvelle version de la même étiquette (correctifs de sécurité de .NET, Node, Debian…), elle signale qu'il faut redéployer l'application, avec un lien vers le dépôt. Rien n'est à écrire dans le manifeste.
Redéploiement automatique : si le manifeste a des tests, la console relance elle-même le pipeline la nuit (04:30 GMT), une seule fois par nouvelle version de la base. Tests, contrôle de santé et retour automatique s'appliquent comme pour un envoi sur main. Si la base est toujours périmée 20 minutes après, l'alerte le signale. Sans tests, ou avec mise_a_jour_auto: false à la racine du manifeste, rien n'est relancé : l'alerte demande un redéploiement à la main.
Préproduction (demandes de fusion vers main)
Une section preproduction: dans le manifeste suffit. La demande reçoit un commentaire avec l'adresse de chaque application en préproduction (ou l'échec, avec le lien du journal), mis à jour à chaque envoi. Les sites de préproduction sont hors des moteurs de recherche (en-tête X-Robots-Tag: noindex et robots.txt qui interdit tout). Une demande de fusion vers main se déploie alors en préproduction, se met à jour à chaque envoi sur sa branche, et tout est retiré à sa fermeture (fusion ou abandon). Sans cette section, une demande de fusion ne déploie rien.
preproduction:
environnement: # variables ajoutées ou remplacées en préproduction (toutes les applications)
Email__Envoi: "false" # exemple : couper l'envoi de courriels
applications: # réglages propres à une application
mon-api:
environnement: {Url__Front: https://dev-exemple.com}
domaines: # facultatif : nom de production -> nom de préproduction
exemple.com: essai.exemple.com
remplacer: # sites statiques : textes remplacés dans les fichiers (js, json, html, css...)
api.exemple.com: dev-api.exemple.com
copier_donnees: true # copie des volumes de production au premier déploiement (défaut : oui)
copier_env: true # copie du .env de production, sans la chaîne de la base ni l'image (défaut : oui)
memoire: 384m # facultatif
Ce qui se passe :
- chaque application devient
<nom>-dev, surdev-<nom de domaine>(oudev.<domaine>pour un domaine nu). Les nomswww.sont ignorés ; - au premier déploiement, la base PostgreSQL est copiée depuis la production (
<base>_dev, compte<compte>_dev, sans couper la production). Les fichiers de configuration du serveur sont copiés, ainsi que les volumes et le.envsi les options le permettent ; - la console du VPS crée l'enregistrement DNS chez OVH si le nom n'en a aucun, puis sort le site du mode essai dès que le nom pointe sur le VPS ;
- les applications de préproduction n'ont pas de sonde Uptime Kuma ;
- à la fermeture de la demande, sont supprimés : le conteneur, le site, l'enregistrement DNS créé par la console, la base et le compte
_dev, les images, et les dossiers/srv/apps/<nom>-dev.
Attention : la préproduction utilise une copie des données réelles. Coupe tout effet externe (courriels, paiements, webhooks) par environnement, et vérifie les fichiers de configuration statiques (proteger) qui pointeraient vers la production.
Le workflow modèle (modeles/deployer.yml) contient le déclencheur pull_request ; les projets qui veulent la préproduction doivent reprendre cette version.