Configurer le runner CI distant

Guide d'usage du script qui provisionne une machine distante pour exécuter les pipelines CI/CD de gitrust via SSH + rsync + Dagger.


1. Rôle du script

deployment/setup-remote-ci.sh (disponible dans le dépôt source gitrust) prépare un serveur de build distant utilisé par le worker CI de gitrust. Il automatise 6 étapes :

  1. Vérifie la connectivité SSH vers le runner
  2. Installe Docker (curl https://get.docker.com | sh) s'il est absent
  3. Installe Dagger CLI (curl https://dl.dagger.io/dagger/install.sh | sh) s'il est absent
  4. Crée le répertoire de travail distant (CI_REMOTE_PATH)
  5. Synchronise le module deployment/ci-engine/ (mode CI Easy) via rsync -az --delete
  6. Smoke test : affiche docker --version et dagger version

Le script est idempotent : rejoue sans dommage, skip ce qui existe déjà.


2. Quand l'utiliser

Scénario Besoin de setup-remote-ci.sh ?
Dev local, CI sur la même machine que gitrust (CI_REMOTE_HOST=localhost) Non — Docker et Dagger déjà installés localement, le ci-engine/ est lu depuis deployment/ci-engine/ directement
Prod on-premise, un seul serveur (gitrust + CI colocalisés) Non — idem, un simple curl get.docker.com \| sh suffit sur le serveur gitrust
Prod avec runner CI dédié (machine séparée) OUI — c'est le cas cible de ce script
Prod avec plusieurs instances gitrust partageant un runner OUI — le runner est provisionné une fois, chaque instance pointe dessus
CI dans Kubernetes / Nomad / runner managé cloud Non — ce script est pensé pour une VM Debian/Ubuntu classique

3. Architecture cible

+---------------------+        SSH + rsync        +-----------------------+
|  Gitrust (web+SSH)  |---------------------------|  CI Runner (distant)  |
|  <your-server-ip>   |  CI_REMOTE_HOST/USER/KEY  |  <ci-runner-ip>       |
|                     |                           |                       |
|  Worker CI Tokio    |   push .gitrust-ci.yml    |  /opt/gitrust-ci/     |
|  (dans gitrust.bin) |   + code source checkout  |   ├── ci-engine/      |
|                     |                           |   └── workspaces/     |
|                     |   dagger call ...         |                       |
|                     |                           |  Docker + Dagger CLI  |
+---------------------+                           +-----------------------+

Le worker CI de gitrust (tâche Tokio dans le binaire principal) ne fait pas tourner Docker localement — il délègue au runner via SSH. Cela permet d'isoler les workloads CPU/RAM gourmands (builds Rust, Node, Docker) du process web de gitrust.


4. Pré-requis

Sur la machine d'exécution (là où on lance le script)

Outil Rôle
bash ≥ 4 Interpréteur
ssh, rsync Transport et synchro
ssh-agent chargé ou CI_REMOTE_SSH_KEY défini Auth SSH sans mot de passe interactif (BatchMode=yes)
Fichier .env avec les variables CI_REMOTE_* Config (voir section 5)

Sur le runner distant

Pré-requis Pourquoi
OS Linux récent (Debian 12+, Ubuntu 22.04+) Docker install script compatible
User avec sudo passwordless ou droits docker get.docker.com fait sudo en interne
Clé SSH publique du user local dans ~/.ssh/authorized_keys Auth SSH non-interactive
Réseau sortant autorisé vers get.docker.com et dl.dagger.io Installation des binaires
Au minimum ~5 Go libres dans CI_REMOTE_PATH Images Docker + workspaces

5. Variables d'environnement attendues (le .env)

Le script source un fichier .env dont le chemin est passé en argument, ou par défaut ../.env (relatif au script, donc <racine_projet>/.env).

Tableau des variables

Variable Obligatoire Défaut Description
CI_REMOTE_HOST OUI Hostname ou IP du runner (ex: ci-runner.internal)
CI_REMOTE_USER non $(whoami) (user courant) Compte SSH sur le runner
CI_REMOTE_SSH_PORT non 22 Port SSH du runner
CI_REMOTE_PATH non /opt/gitrust-ci Répertoire de travail distant (créé par le script)
CI_REMOTE_SSH_KEY non — (ssh-agent) Chemin d'une clé privée SSH spécifique

Ces variables sont les mêmes que celles lues par gitrust au runtime. Centraliser dans .env évite les divergences entre le provisionnement et le runtime.

Exemple minimal de .env (runner dédié)

# --- CI runner distant ---
CI_REMOTE_HOST=<ci-runner-ip>
CI_REMOTE_USER=ci-runner
CI_REMOTE_SSH_PORT=22
CI_REMOTE_PATH=/opt/gitrust-ci
CI_REMOTE_SSH_KEY=/home/gitrust/.ssh/ci_runner_ed25519

Exemple .env complet coexistant avec config gitrust

DATABASE_URL=postgres://...
JWT_SECRET=...
# ... (voir .env.example pour le reste)

# --- CI/CD (lu par gitrust ET par setup-remote-ci.sh) ---
CI_ENABLED=true
CI_MAX_CONCURRENT=4
CI_REMOTE_HOST=ci-runner.internal
CI_REMOTE_USER=ci-runner
CI_REMOTE_PATH=/opt/gitrust-ci
CI_REMOTE_SSH_KEY=/opt/gitrust/data/ci_runner_key

Cas « runner local » (pas besoin du script)

CI_REMOTE_HOST=localhost
# Les autres CI_REMOTE_* sont ignorés

Dans ce cas, installer Docker et Dagger directement sur la machine gitrust, copier deployment/ci-engine/ vers CI_ENGINE_PATH (défaut /opt/gitrust/ci-engine) et passer à la suite. Ne pas exécuter setup-remote-ci.sh avec CI_REMOTE_HOST=localhost.


6. Usage

Depuis la racine du projet (par défaut)

cd /chemin/vers/gitrust

# .env a la racine (défaut) :
./deployment/setup-remote-ci.sh

Avec un .env explicite

./deployment/setup-remote-ci.sh /chemin/vers/mon.env
# Utile si vous avez .env.production, .env.staging, etc.
./deployment/setup-remote-ci.sh .env.production

Sortie attendue

==> Configuration :
    Serveur  : ci-runner@<ci-runner-ip>
    Port SSH : 22
    Chemin   : /opt/gitrust-ci

==> [1/6] Vérification de la connectivité SSH...
SSH OK
    OK
==> [2/6] Vérification de Docker...
    Docker déjà installé
==> [3/6] Vérification de Dagger CLI...
    Installation de Dagger CLI...
    Dagger installé
==> [4/6] Création du répertoire distant...
    /opt/gitrust-ci créé
==> [5/6] Synchronisation du ci-engine...
sending incremental file list
ci-engine/
ci-engine/profiles/
...
    ci-engine synchronisé vers /opt/gitrust-ci/ci-engine/
==> [6/6] Smoke test...
    Versions distantes :
Docker version 28.0.1, build abcd123
dagger v0.19.2 (linux/amd64)

==> Setup terminé. Le serveur ci-runner@<ci-runner-ip> est prêt pour l'exécution CI.
    Pensez à configurer CI_EXECUTION_MODE=remote dans votre .env

7. Ce qui se retrouve sur le runner

Après exécution réussie :

/opt/gitrust-ci/                    <- CI_REMOTE_PATH
└── ci-engine/                      <- synchronisé depuis deployment/ci-engine/
    ├── README.md
    └── profiles/                   <- templates par stack (Python, Node, Rust, ...)

Plus, installés globalement : - /usr/bin/docker (ou équivalent) + socket /var/run/docker.sock - /usr/local/bin/dagger

Les workspaces de pipelines (checkouts temporaires) sont créés par le worker CI de gitrust au moment de l'exécution sous CI_WORKSPACE_PATH (défaut /tmp/gitrust-ci) — pas par ce script.


8. Vérifications post-setup

Depuis la machine gitrust

# Source le .env
set -a; source .env.production; set +a

# 1. SSH direct (doit passer sans prompt)
ssh -p ${CI_REMOTE_SSH_PORT:-22} \
    ${CI_REMOTE_SSH_KEY:+-i $CI_REMOTE_SSH_KEY} \
    $CI_REMOTE_USER@$CI_REMOTE_HOST 'docker info && dagger version'

# 2. Rsync round-trip (lecture/écriture sur CI_REMOTE_PATH)
echo "test" | ssh $CI_REMOTE_USER@$CI_REMOTE_HOST \
    "cat > $CI_REMOTE_PATH/.gitrust-test && cat $CI_REMOTE_PATH/.gitrust-test && rm $CI_REMOTE_PATH/.gitrust-test"
# Attendu : "test"

Pipeline de test via gitrust

Pousser un dépôt avec un .gitrust-ci.yml minimal :

# .gitrust-ci.yml
version: 1
pipeline:
  - name: smoke
    image: alpine:3
    run: echo "CI runner OK"

Puis dans l'UI gitrust : onglet Pipelines → la pipeline doit passer au statut success.


9. Mise à jour après modification du ci-engine/

Le ci-engine/ synchronisé n'est pas « live-linké » : rejouer le script après modification côté source.

# Modifier deployment/ci-engine/profiles/*.py ou similaire
./deployment/setup-remote-ci.sh
# Les étapes 2-3 sont skip (déjà installés), seule l'étape 5 refait le rsync

rsync -az --delete supprime les fichiers côté runner qui n'existent plus localement — garantit la cohérence.


10. Dépannage

Symptôme Cause probable Fix
ERREUR: fichier .env introuvable .env absent ou chemin incorrect cp .env.example .env && $EDITOR .env ou passer le chemin : ./setup-remote-ci.sh /path/to/.env
ERREUR: CI_REMOTE_HOST non défini Variable commentée ou absente Décommenter CI_REMOTE_HOST=... dans le .env
ERREUR: impossible de se connecter SSH bloqué, mauvais user, clé non autorisée Tester manuellement : ssh -v -p X user@host ; vérifier ~/.ssh/authorized_keys sur le runner
Permission denied (publickey) BatchMode=yes interdit les prompts, clé non chargée ssh-add ~/.ssh/ci_runner_ed25519 ou définir CI_REMOTE_SSH_KEY=/path/to/key
sudo: a password is required pendant l'install Docker User sans NOPASSWD sudo Ajouter le user au sudoers : ci-runner ALL=(ALL) NOPASSWD:ALL (runner uniquement)
curl: (7) Failed to connect to get.docker.com Réseau sortant du runner bloqué Whitelist get.docker.com et dl.dagger.io, ou pré-installer Docker + Dagger manuellement
ATTENTION: ... ci-engine introuvable Lancé hors du repo gitrust cd dans la racine du projet avant de lancer
Pipeline reste queued indéfiniment Worker CI ne trouve pas le runner Vérifier CI_EXECUTION_MODE=remote dans .env gitrust + logs : journalctl -u gitrust \| grep -i 'ci\|dagger'
dagger: command not found au smoke test $PATH du user SSH ne contient pas /usr/local/bin echo 'export PATH=$PATH:/usr/local/bin' >> ~/.bashrc sur le runner, ou CI_DAGGER_BIN=/usr/local/bin/dagger côté gitrust

11. Sécurité

  • Le runner CI exécute du code arbitraire venant des dépôts hébergés. Ne jamais le colocaliser avec des secrets sensibles (PG prod, clés de prod).
  • Isoler réseau : bloquer l'accès sortant du runner vers le LAN privé (seul l'accès Internet pour docker pull est nécessaire).
  • Limiter sudo NOPASSWD au strict minimum sur le runner (idéalement : juste pour les commandes docker et apt).
  • Rotation régulière de la clé SSH CI_REMOTE_SSH_KEY. La révoquer dans ~/.ssh/authorized_keys côté runner en cas de suspicion.
  • Le runner ne doit pas pouvoir se connecter en SSH à la machine gitrust (unidirectionnel).