Aller au contenu

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 :

POST /api/v1/repos/<owner>/<repo>/actions/runners/registration-token

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

::error::The version '3.12' with architecture 'x64' was not found
for this operating system.

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 :

- name: Installer Python et les dépendances
  run: |
    apt-get update -qq
    apt-get install -y --no-install-recommends python3-venv python3-pip
    python3 -m venv /tmp/venv
    /tmp/venv/bin/pip install --no-cache-dir -r requirements.txt

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