Intégration continue — Gitea Actions¶
Le parc exécute ses workflows avec act_runner, sur vm-compute-01, en mode dind :
les jobs tournent dans le démon Docker du runner, pas dans celui de l'hôte.
Le trajet d'un push¶
flowchart LR
dev["Poste<br/>git push"]
gitea["Gitea<br/>vm-docker:3303"]
runner["act_runner<br/>vm-compute-01"]
job["Job dans<br/>node:20-bookworm"]
hote["vm-docker<br/>deploy-hook.sh"]
dev --> gitea
gitea -.->|"le runner interroge,<br/>Gitea ne pousse pas"| runner
runner --> job
job -->|"ssh, clé verrouillée<br/>par command="| hote
hote --> ok["git pull + build<br/>+ vérification"]
Le runner tire le travail par interrogation longue : Gitea ne le contacte jamais. D'où l'URL en IP directe dans sa configuration — à travers Caddy, cette interrogation permanente ressemble à du balayage et finirait bannie par CrowdSec.
Le piège qui coûte le plus cher : la portée d'un runner¶
Un act_runner porte une portée unique, fixée à l'enregistrement — instance,
organisation, utilisateur, ou un seul dépôt. Elle ne se change pas après coup.
flowchart TB
subgraph hote["vm-compute-01"]
r1["rtx-runner<br/>portée : dépôt homelab-vault"]
r2["docs-runner<br/>portée : dépôt homelab-docs"]
end
v["Dépôt homelab-vault"]
d["Dépôt homelab-docs"]
t["Un troisième dépôt"]
r1 --> v
r2 --> d
t -.->|"aucun runner éligible"| queued["runs « queued »<br/>indéfiniment"]
classDef bad stroke-width:3px,stroke-dasharray: 5 5
class queued bad
Des runs queued pour toujours ne ressemblent pas à une erreur
Quand aucun runner n'est éligible, les exécutions apparaissent normalement
dans l'interface et restent queued. Aucun message, aucune alerte, rien qui
dise que personne ne viendra les prendre. Ça se lit comme « la CI n'est pas
encore branchée ».
Le contrôle qui tranche en une requête :
curl -s -H "Authorization: token $TOKEN" \
https://gitea.savethemall.eu/api/v1/repos/<owner>/<repo>/actions/runners \
| jq '.runners[].name'
# tableau vide → ces jobs ne partiront jamais
Ajouter un dépôt à la CI, c'est donc soit ajouter un runner, soit migrer un runner existant vers une portée plus large — cette seconde option arrête la CI qu'il servait pendant l'opération, à faire à froid.
Le jeton d'enregistrement se demande en POST, pas en GET :
Ce que l'image des jobs contient — et ne contient pas¶
Les jobs runs-on: ubuntu-latest s'exécutent dans node:20-bookworm.
| Présent | Absent |
|---|---|
git 2.39 |
pip |
| Python 3.11 | venv |
| accès à github.com et pypi.org | client SSH |
Debian livre pip, venv et openssh-client séparément. Un workflow qui les
suppose échoue tard, après le checkout, sur un message qui ne dit pas qu'il
manque un paquet.
actions/setup-python ne fonctionne pas sur ce runner
L'action télécharge des binaires publiés pour les images ubuntu-XX de GitHub.
Aucun n'existe pour Debian bookworm. Ce n'est pas un problème de réseau : le
runner atteint github.com et pypi.org sans difficulté.
Installer depuis Debian à la place :
Déployer sans donner un shell¶
Une clé de déploiement qui ouvre un shell complet sur l'hôte de production vaut le mot de passe de cet hôte. La forme utilisée ici la réduit à un seul geste :
command="/opt/docker/<stack>/deploy-hook.sh",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty,restrict ssh-ed25519 AAAA…
Quoi que le client envoie, le serveur exécute ce script et rien d'autre. Le contrôle qui le prouve, plutôt que de le supposer :
ssh -i <clé> -p <port-ssh> <user>@vm-docker "cat /etc/shadow"
# doit afficher la sortie du déploiement, jamais le contenu du fichier
Corollaire de conception : le script doit faire lui-même sa vérification, puisque le client ne peut pas envoyer une seconde commande pour contrôler le résultat.
Dernière vérification de cette page : 2026-09-08