← Tous les guides
Développement et déploiement

Exécuter les builds CI sur des Droplets jetables

Utilisez des Droplets jetables pour vos builds GitHub Actions. Conservez les artefacts, limitez les accès et vérifiez la suppression avec un projet compagnon.

Aller aux étapesVoir sur GitHub

Compiler une fois, garder le résultat, supprimer la machine

Une machine de build CI éphémère fournit un système neuf pour chaque compilation, puis disparaît après le travail. Ce guide utilise un Droplet DigitalOcean comme runner GitHub Actions limité à un seul job. Vous exécuterez des tests Python, publierez un artefact téléchargeable et vérifierez la suppression de la machine.

La distinction compte. GitHub retire un runner éphémère après un job, mais ne détruit pas la machine virtuelle. Un workflow vert peut laisser un serveur facturable. La suppression fait donc partie de la procédure de build.

Le premier essai crée le Droplet manuellement pour permettre de vérifier chaque étape. Le compagnon automatise le build, la suppression normale et le nettoyage des machines de démonstration abandonnées. Il vise du code approuvé dans un dépôt GitHub.com privé. Ce n’est ni un autoscaler de production ni un exemple pour GitHub Enterprise Server.

Quand exploiter des machines de build CI éphémères

Je garderais les runners hébergés par GitHub pour les tests ordinaires, sauf besoin précis de gérer les machines. Les Droplets deviennent utiles pour un environnement Linux particulier, des paquets spécifiques ou des builds occasionnels qui demandent plus de mémoire. Gérer l’image implique aussi de gérer ses mises à jour et son nettoyage.

Pour cet exercice, choisissez un dépôt privé dont vous approuvez les collaborateurs et les modifications des workflows. Une VM jetable limite la persistance entre jobs, mais ne rend pas un programme malveillant inoffensif pendant son exécution. N’ajoutez ni base de production, ni clé de déploiement, ni socket Docker partagé. N’utilisez pas pull_request_target pour exécuter une branche proposée avec des identifiants privilégiés.

Faites défiler horizontalement pour voir toutes les colonnes.

Choisir selon le travail à effectuer
ApprocheUsage adaptéCompromis
Runner hébergé par GitHubCI courante sans administrer les machinesEnvironnements proposés et quotas du forfait
Droplet neuf par jobLinux personnalisé et disque de build séparéDémarrage, entretien de l’image, suppression et facturation
Runner autohébergé permanentOutils et caches prêts pour des jobs fréquents et approuvésÉtat et identifiants peuvent persister entre les builds

Budgéter de la création à la suppression

DigitalOcean facture actuellement les Droplets CPU à la seconde, avec un minimum de 60 secondes ou de 0,01 USD, selon le montant le plus élevé. La facturation commence à la création et s’arrête à la destruction. Éteindre un Droplet ne suffit pas. Vérifiez la région, la configuration et le tarif horaire avant de le créer.

Pour une machine hypothétique à 0,06 USD par heure qui existe pendant 12 minutes, le calcul donne 0,012 USD par exécution. Cent exécutions séparées coûteraient 1,20 USD avant les autres frais. Ce calcul n’est ni un tarif de Droplet proposé ni une durée mesurée. Appliquez le minimum à chaque machine et comptez l’installation, l’attente et l’envoi des artefacts.

Le stockage des artefacts, les minutes de nettoyage hébergées par GitHub, les snapshots et les transferts peuvent ajouter des frais. Une machine temporaire n’accumule pas un mois complet de quota sortant. Évitez les snapshots, sauvegardes, volumes supplémentaires et IP réservées pour cet exercice. Une alerte de facturation vous avertit, mais ne plafonne pas les dépenses.

Préparer le dépôt privé et le contrôleur de nettoyage

Téléchargez le compagnon et copiez ses fichiers dans un nouveau dépôt privé dont la branche par défaut est main. Déplacez workflows/build.yml et workflows/cleanup.yml dans .github/workflows/. Gardez cleanup.py et tests/ à la racine. Enregistrez ces fichiers sur main. Le compagnon public garde volontairement les workflows cloud inactifs.

Sur votre ordinateur, utilisez Python 3.10 ou une version plus récente et lancez la commande ci-dessous depuis le dossier du compagnon. Elle ne contacte pas le cloud. Le build exemple exécute ces mêmes tests sur Ubuntu et archive le script avec un identifiant de commit. Vous pourrez examiner un véritable artefact avant de remplacer cet exemple par votre application.

Dans DigitalOcean, créez un jeton API de nettoyage avec les droits droplet:read et droplet:delete. Dans le dépôt GitHub privé, ouvrez Settings, Secrets and variables, Actions. Ajoutez le secret de dépôt DO_CLEANUP_TOKEN avec ce jeton. Ajoutez la variable DO_CI_OWNER_TAG avec une valeur unique, par exemple ci-owner-my-private-repo. Réservez cette valeur à cet exercice.

Ne définissez pas encore DO_CI_CLEANUP_ENABLED. Le nettoyage planifié inspectera sans supprimer. Lancez manuellement ce workflow sans cocher apply et vérifiez qu’il peut lister les ressources. Le nettoyage après build supprime déjà l’identifiant de démonstration fourni. Les droits du jeton DigitalOcean ne sont pas limités par les tags, que seul le script contrôle. Une équipe DigitalOcean séparée offre une séparation plus forte.

Sur votre ordinateur, dans le compagnonTerminal local
python3 -m unittest discover -s tests -v

Créer et identifier un Droplet jetable

Dans le panneau DigitalOcean, créez un Droplet CPU Ubuntu 24.04 x64. Prévoyez assez de mémoire pour l’exemple Python, par exemple 2 Gio. Ce point de départ ne dimensionne pas une grosse application. Choisissez un forfait disponible, vérifiez son prix et utilisez une clé SSH que vous contrôlez déjà.

Nommez-le ci-demo-first et ajoutez les deux tags ci-ephemeral-demo et la valeur exacte de DO_CI_OWNER_TAG. Notez son identifiant numérique, son IP publique et son heure de création hors de la VM. L’identifiant figure dans l’URL du panneau lorsque vous ouvrez le Droplet. Vérifiez sa correspondance avec le nom avant de l’utiliser dans un workflow.

Appliquez un Cloud Firewall autorisant SSH entrant sur TCP 22 uniquement depuis votre IP publique actuelle. Gardez les connexions sortantes disponibles pour cette démonstration approuvée, afin de permettre les téléchargements, DNS et HTTPS vers GitHub. N’exposez pas de serveur entrant sur 80 ou 443, ni de démon Docker. Le runner contacte GitHub, qui n’a pas besoin d’une connexion entrante pour lui attribuer un job.

Utilisez un VPC séparé, sans service de production ni connexion vers ces services. Le pare-feu et l’absence d’identifiants de déploiement limitent les accès accidentels. Ils ne rendent pas la machine adaptée à du code hostile.

Installer le runner avec un utilisateur sans privilèges

Connectez-vous en SSH comme root avec l’IP publique. Au premier accès, vérifiez l’empreinte du serveur par un canal de confiance, comme la console DigitalOcean. La commande ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub y affiche l’empreinte ED25519. Ne désactivez pas le contrôle de clé d’hôte pour éviter cette étape.

Exécutez les commandes suivantes sur le Droplet. Root installe les paquets et crée runner, un compte sans droits sudo. La dernière commande ouvre un shell avec ce compte. Gardez ce terminal ouvert pendant l’exercice.

Dans le dépôt GitHub privé, ouvrez Settings, Actions, Runners, New self-hosted runner. Choisissez Linux et x64. Comme utilisateur runner, exécutez les commandes actuelles de téléchargement, de vérification de somme et d’extraction affichées par GitHub. Ne lancez pas encore sa configuration par défaut ni l’installation du service. Utilisez le paquet actuel plutôt qu’une ancienne version copiée dans un tutoriel.

Si la vérification des prérequis signale des bibliothèques manquantes, revenez au shell root avec exit, exécutez /home/runner/actions-runner/bin/installdependencies.sh, puis revenez avec su - runner. Seule l’installation des dépendances nécessite root. Ne corrigez pas une erreur de démarrage en autorisant l’exécution du runner comme root ou en lui donnant tous les droits sudo.

Avant de continuer : Exécutez comme root uniquement sur le nouveau Droplet de démonstration. La dernière commande passe à runner.

Sur le Droplet, comme rootDroplet connecté
apt-get update
apt-get install -y ca-certificates curl git python3
adduser --disabled-password --gecos "" runner
su - runner

Enregistrer un runner pour un seul job

Ouvrez le dossier actions-runner extrait. Le jeton d’enregistrement affiché par GitHub a une durée limitée. Saisissez-le à l’invite masquée ci-dessous plutôt que de le conserver dans un script ou l’historique. Remplacez OWNER/PRIVATE_REPO par le chemin de votre dépôt privé. Le jeton peut apparaître brièvement dans les arguments du processus pendant la configuration. Limitez donc les accès à cette machine.

Le label ci-demo-first dirige cette démonstration vers son runner. Choisissez un nouveau label pour chaque machine et utilisez-le au lancement du workflow. Les labels sélectionnent les machines, mais ne contrôlent pas les autorisations. Enregistrez ce runner uniquement dans le dépôt privé dédié.

L’option --ephemeral est indispensable. Le runner se désenregistre après un job. N’installez pas de service permanent et ne relancez pas run.sh en boucle. Exécutez-le au premier plan et cherchez le message indiquant l’attente de jobs. Le processus ou la connexion SSH peut s’interrompre lorsque le nettoyage hébergé détruit le Droplet.

Avant de continuer : Exécutez comme utilisateur runner sans privilèges dans Bash. Ne conservez pas le jeton dans un fichier.

Sur le Droplet, comme runner, dans BashDroplet connecté
Modifier d’abordRemplacez chaque valeur surlignée avant d’exécuter la commande.
cd ~/actions-runner
read -r -s -p "Runner registration token: " RUNNER_TOKEN
printf "\n"
./config.sh --unattended --url https://github.com/OWNER/PRIVATE_REPO \
  --token "$RUNNER_TOKEN" --ephemeral \
  --name ci-demo-first --labels ci-demo-first
unset RUNNER_TOKEN
./run.sh

Remplacez avant l’utilisation : OWNER/PRIVATE_REPO

Lancer le build et examiner son artefact

Ouvrez Actions dans le dépôt privé, sélectionnez Disposable build, puis Run workflow sur main. Saisissez ci-demo-first dans runner_label et l’identifiant numérique noté dans droplet_id. Ils doivent désigner la même machine. Le workflow accepte uniquement un dépôt privé sur main, limite l’accès au contenu en lecture et arrête le build après 20 minutes d’exécution.

L’exemple lance les tests puis crée dist/commit.txt, dist/python-version.txt et une archive du script. Il envoie ensuite dist comme artefact conservé trois jours. Téléchargez-le dans le résumé du workflow et comparez commit.txt au commit de l’exécution. Une étape de test verte sans artefact téléchargeable ne suffit pas.

Le job de nettoyage utilise ubuntu-24.04 sur l’infrastructure GitHub et suit le build avec always(). Lui seul reçoit le jeton DigitalOcean. Il revérifie l’identifiant, le préfixe du nom et les deux tags, supprime la machine correspondante et interroge l’API jusqu’à son absence. Une demande de suppression seule n’est pas une confirmation.

Une annulation, l’indisponibilité d’un runner hébergé ou une panne GitHub peut encore empêcher ce job d’aboutir. Si le build attend, vérifiez que le runner écoute et que son label correspond. Le délai du build ne limite pas l’attente d’un runner disponible.

Récupérer un nettoyage échoué

Ouvrez la liste des Droplets après le workflow et vérifiez que ci-demo-first a disparu. Vérifiez aussi la liste des runners GitHub. Si la VM reste présente, consultez les erreurs puis détruisez uniquement cette démonstration dans le panneau, ou utilisez le compagnon localement avec son identifiant exact.

Pour le nettoyage local, lisez le jeton DigitalOcean dans votre session Bash locale avec l’invite masquée ci-dessous. Remplacez le tag propriétaire et l’identifiant numérique d’exemple par vos valeurs. Le premier appel affiche la suppression prévue. Ajoutez --apply seulement après vérification de l’identifiant et du nom affichés, puis effacez la variable. Ces commandes ne s’exécutent jamais sur la machine de build.

Une réponse 401 ou 403 signale une erreur d’authentification ou de droits, pas la disparition de la VM. Le script s’arrête sur ces réponses. Si la suppression reste non confirmée, vérifiez le panneau et résolvez cette ressource avant de créer une autre démonstration.

Sur votre ordinateur, dans Bash et le compagnonTerminal local
Modifier d’abordRemplacez chaque valeur surlignée avant d’exécuter la commande.
read -r -s -p "DigitalOcean cleanup token: " DIGITALOCEAN_TOKEN
printf "\n"
export DIGITALOCEAN_TOKEN
python3 cleanup.py --owner-tag ci-owner-my-private-repo --id 123456789

Remplacez avant l’utilisation : ci-owner-my-private-repo, 123456789

Avant de continuer : La commande --apply supprime définitivement le Droplet correspondant et son disque local. Exécutez d’abord la simulation et vérifiez l’identifiant et le nom.

Après vérification du résultat de la simulationTerminal local
Modifier d’abordRemplacez chaque valeur surlignée avant d’exécuter la commande.
python3 cleanup.py --owner-tag ci-owner-my-private-repo --id 123456789 --apply
unset DIGITALOCEAN_TOKEN

Remplacez avant l’utilisation : ci-owner-my-private-repo, 123456789

Activer le nettoyage indépendant selon l’âge

Le second workflow inspecte les machines toutes les demi-heures, aux minutes 17 et 47. Il retient uniquement les noms commençant par ci-demo-, portant le tag géré et votre tag propriétaire, et âgés d’au moins deux heures. Il ne vérifie pas si un build est actif. Ce seuil est une durée maximale de démonstration et peut interrompre un job bloqué ou encore actif.

Laissez d’abord une machine jetable correctement étiquetée dépasser le seuil et lancez le workflow sans cocher apply. Vérifiez qu’il affiche la bonne machine et ignore les autres ressources. Relancez avec apply coché, confirmez l’absence, puis définissez la variable de dépôt DO_CI_CLEANUP_ENABLED à true pour autoriser la suppression planifiée.

La planification reste un recours, pas une garantie de dépenses limitées à deux heures. GitHub documente des retards et des jobs planifiés abandonnés sous forte charge. Vérifiez que le workflow figure sur la branche par défaut et reste actif, puis surveillez les erreurs. En production, un contrôleur extérieur à la VM doit rapprocher les ressources et signaler toute machine qui dépasse sa durée prévue.

Remplacer l’exemple en séparant build et déploiement

Une fois la démonstration réussie, remplacez ses commandes de test et d’archivage par l’installation verrouillée des dépendances, les tests et le build de votre application. Installez le compilateur ou runtime nécessaire dans l’image. Commencez sans cache, puis mesurez son intérêt avant de l’ajouter. Séparez les auteurs de caches approuvés du code non fiable.

Pour la livraison continue, un job séparé doit télécharger l’artefact réussi et déployer le commit enregistré selon votre procédure d’approbation. Placez ses identifiants dans un environnement protégé. Donner les accès de production au Droplet de build supprime une séparation utile sans faciliter la compilation.

Avant de créer les machines automatiquement, ajoutez un contrôleur qui crée une VM par job, enregistre son identifiant avant l’inscription, fournit un jeton temporaire et attend que le runner soit prêt. Utilisez des labels uniques, un nombre maximal de machines et un nettoyage répétable. Gardez le jeton d’administration GitHub et le jeton DigitalOcean hors de la VM. Ne créez jamais d’image contenant un runner déjà enregistré ou ses identifiants.

En production, exportez les journaux de diagnostic avant la destruction, comme GitHub le recommande pour les runners éphémères. La démonstration conserve les journaux du workflow et l’artefact envoyé, mais ne collecte pas le dossier _diag à l’extérieur. Testez le succès, l’échec, l’annulation et un runner qui ne s’enregistre jamais avant de laisser le système sans surveillance.

Garder cette approche si elle justifie son entretien

Cette approche fournit un disque neuf et le contrôle de l’environnement Linux. Son coût comprend aussi l’entretien des paquets, la sortie des artefacts et la suppression des machines lors des échecs. Pour des jobs courts et ordinaires, un runner hébergé peut être préférable, même si le calcul de la VM paraît moins cher.

Adoptez ce modèle quand ce contrôle résout une contrainte réelle de build. Conservez le commit testé, l’artefact téléchargé, le retrait du runner, l’absence confirmée du Droplet et le résultat d’un nettoyage de machine abandonnée. Ces vérifications prouvent le fonctionnement du cycle complet. Une compilation réussie seule ne suffit pas.

L’option --ephemeral supprime-t-elle le Droplet ?

Non. GitHub attribue un seul job puis retire le runner. La VM reste présente jusqu’à sa suppression par un contrôleur ou un opérateur via DigitalOcean. Ce guide utilise un job hébergé et un nettoyage selon l’âge, puis vérifie l’absence de la machine.

Puis-je exécuter des PR issues de forks publics ?

N’utilisez pas cette démonstration pour des PR non fiables. Une machine jetable exécute le code avec les identifiants et les accès réseau disponibles pendant le job. Commencez par un dépôt privé et des workflows approuvés. Gardez les contributions publiques sur un service hébergé correctement isolé.

Éteindre la machine arrête-t-il la facturation ?

Non. Détruisez le Droplet pour arrêter sa facturation de calcul. Les Droplets CPU sont actuellement facturés à la seconde, avec un minimum de 60 secondes ou 0,01 USD. Comptez l’installation et l’attente, puis vérifiez les frais distincts de stockage et de transfert.

Un nouveau Droplet est-il créé automatiquement ?

Non. Le premier essai crée et enregistre une machine manuellement. Le compagnon automatise les tests, l’envoi des artefacts, la suppression après build et le nettoyage des machines anciennes. La création automatique exige un contrôleur avec identifiants d’inscription, vérifications de disponibilité, limites et suivi durable des VM.

Que se passe-t-il si le nettoyage planifié ne démarre pas ?

Le Droplet peut rester facturable. Les workflows planifiés peuvent subir des retards ou être abandonnés. Le seuil de deux heures ne plafonne donc pas les dépenses. Vérifiez le panneau, supprimez la démonstration exacte si nécessaire et surveillez les échecs avant une utilisation sans surveillance.

Vérifier le résultat

Résultat attendu
L’artefact identifie le commit testé, le runner se retire et l’API confirme l’absence du Droplet.
Arrêter si
Un build vert avec une VM restante est incomplet. Examiner le nettoyage puis supprimer la démonstration exacte.
Étape suivante
Tester le nettoyage selon l’âge avant d’adapter le build ou d’automatiser la création.