Skip to content

CI/CD Runners (Workers)

Instance : gitea.mindlet.app — Hetzner VPS 89.167.14.242 Runner actif : main-runner (global, toute l’instance) Date de mise en place : 2 février 2026


  1. Qu’est-ce qu’un runner ?
  2. Architecture
  3. Configuration
  4. Fichiers et structure
  5. Guide des opérations
  6. Exemples de workflows
  7. Maintenance
  8. Troubleshooting

Un runner (worker) exécute les jobs CI/CD définis dans les fichiers .gitea/workflows/*.yml. Gitea crée les jobs et les met en file d’attente, le runner les récupère et les exécute.

sequenceDiagram
    participant Dev as Développeur
    participant Gitea as Gitea Server
    participant Runner as main-runner
    participant Docker as Docker Engine

    Dev->>Gitea: git push
    Gitea->>Gitea: Détecte .gitea/workflows/ci.yml
    Gitea->>Gitea: Crée job (status: Waiting)

    loop Toutes les 2 secondes
        Runner->>Gitea: Poll HTTP - jobs disponibles ?
    end

    Gitea->>Runner: Envoie le job
    Runner->>Docker: Crée conteneur ubuntu-latest
    Docker->>Docker: Exécute les steps
    Docker-->>Runner: Résultat
    Runner-->>Gitea: Logs + statut final
    Note over Docker: Conteneur détruit

    Gitea-->>Dev: Résultat visible dans Actions

flowchart TB
    subgraph VPS["Hetzner VPS — 89.167.14.242"]
        subgraph DockerEnv["Docker"]
            subgraph Network["Réseau: gitea"]
                Gitea["Gitea<br/>:3000 web<br/>:222 ssh<br/>Actions: ENABLED"]
                Runner["gitea-runner<br/>act_runner v0.2.x<br/>Nom: main-runner<br/>Portée: GLOBAL"]
            end

            Socket["/var/run/docker.sock"]

            subgraph Jobs["Conteneurs de job (éphémères)"]
                Job1["ubuntu-latest"]
                Job2["ubuntu-22.04"]
            end
        end
    end

    Runner -->|"poll HTTP"| Gitea
    Runner -->|"crée via socket"| Socket
    Socket -->|"spawn"| Jobs
    Jobs -->|"réseau gitea_gitea"| Gitea
RéseauConteneursUsage
giteagitea, gitea-runnerCommunication runner ↔ Gitea
gitea_giteaJobs éphémèresAccès à Gitea pour actions/checkout

Notre runner est global (owner_id = 0) : il traite les jobs de tous les repos de toutes les orgs.


3.1. Variables d’environnement (docker-compose.yml)

Section titled “3.1. Variables d’environnement (docker-compose.yml)”
runner:
image: docker.io/gitea/act_runner:latest
container_name: gitea-runner
restart: always
depends_on:
- gitea
networks:
- gitea
volumes:
- ./runner-config.yaml:/config.yaml
- ./runner-data:/data
- /var/run/docker.sock:/var/run/docker.sock
environment:
CONFIG_FILE: /config.yaml
GITEA_INSTANCE_URL: http://gitea:3000
GITEA_RUNNER_REGISTRATION_TOKEN: "${RUNNER_REGISTRATION_TOKEN}"
GITEA_RUNNER_NAME: "main-runner"

3.2. Configuration runner (runner-config.yaml)

Section titled “3.2. Configuration runner (runner-config.yaml)”
log:
level: info
runner:
file: .runner
capacity: 1 # Jobs en parallèle
timeout: 3h # Durée max par job
fetch_interval: 2s # Fréquence du polling
labels:
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
- "ubuntu-20.04:docker://docker.gitea.com/runner-images:ubuntu-20.04"
cache:
enabled: true
container:
network: "gitea_gitea" # CRITIQUE pour actions/checkout
privileged: false
force_pull: true
Label (runs-on)Image Docker
ubuntu-latestdocker.gitea.com/runner-images:ubuntu-latest
ubuntu-22.04docker.gitea.com/runner-images:ubuntu-22.04
ubuntu-20.04docker.gitea.com/runner-images:ubuntu-20.04

/root/gitea/
├── docker-compose.yml # Services gitea + runner
├── runner-config.yaml # Configuration runner
├── .env # RUNNER_REGISTRATION_TOKEN
└── runner-data/
└── .runner # Enregistrement (auto-généré, NE PAS MODIFIER)
{
"WARNING": "Do not edit manually.",
"id": 2,
"uuid": "db090e36-...",
"name": "main-runner",
"token": "30172ea7e0e5...",
"address": "http://gitea:3000",
"labels": ["ubuntu-latest:docker://...", ...],
"ephemeral": false
}

5.1. Générer un token d’enregistrement GLOBAL

Section titled “5.1. Générer un token d’enregistrement GLOBAL”
Terminal window
docker exec -u git gitea gitea actions generate-runner-token

Important : Ne jamais générer depuis User Settings → Actions → Runners (crée un runner user-level).

Terminal window
# 1. Générer token
docker exec -u git gitea gitea actions generate-runner-token
# 2. Créer répertoire et config
mkdir -p /root/gitea/runner-2-data
cp /root/gitea/runner-config.yaml /root/gitea/runner-2-config.yaml
# 3. Ajouter dans docker-compose.yml
runner-2:
image: docker.io/gitea/act_runner:latest
container_name: gitea-runner-2
restart: always
depends_on:
- gitea
networks:
- gitea
volumes:
- ./runner-2-config.yaml:/config.yaml
- ./runner-2-data:/data
- /var/run/docker.sock:/var/run/docker.sock
environment:
CONFIG_FILE: /config.yaml
GITEA_INSTANCE_URL: http://gitea:3000
GITEA_RUNNER_REGISTRATION_TOKEN: "<nouveau-token>"
GITEA_RUNNER_NAME: "runner-2"
Terminal window
# 4. Démarrer
docker compose up -d runner-2
# Dans runner-config.yaml
runner:
labels:
- "ubuntu-latest:docker://..."
- "node-20:docker://node:20" # Ajout custom
- "python-3.12:docker://python:3.12" # Ajout custom

Attention : Après modification des labels, il faut supprimer .runner et re-enregistrer :

Terminal window
rm /root/gitea/runner-data/.runner
docker exec -u git gitea gitea actions generate-runner-token
# Mettre à jour .env avec le nouveau token
docker compose restart runner
  1. Via l’interface : Site Administration → Runners → Delete
  2. Arrêter le conteneur :
Terminal window
docker compose stop runner
docker compose rm -f runner
rm -rf /root/gitea/runner-data

.gitea/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npm test
- run: npm run lint
name: CI/CD
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
deploy-staging:
runs-on: ubuntu-latest
needs: [test]
steps:
- uses: actions/checkout@v4
- run: echo "Deploying to staging..."
deploy-production:
runs-on: ubuntu-latest
needs: [deploy-staging]
steps:
- uses: actions/checkout@v4
- run: echo "Deploying to production..."
name: Docker Build
on:
push:
tags: ["v*"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: gitea.mindlet.app
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: gitea.mindlet.app/${{ gitea.repository }}:${{ gitea.ref_name }}

Terminal window
# Statut
docker ps | grep runner
docker logs -f gitea-runner
# Contrôle
docker compose restart runner
docker compose stop runner
docker compose start runner
# Diagnostic base de données
docker exec -u git gitea sqlite3 /data/gitea/gitea.db \
"SELECT name, owner_id FROM action_runner;"
# Jobs en attente
docker exec -u git gitea sqlite3 /data/gitea/gitea.db \
"SELECT id, name, status FROM action_run_job WHERE status IN (1, 2);"
CodeStatutDescription
1WaitingEn attente d’un runner
2RunningEn cours
3SuccessTerminé avec succès
4FailureTerminé en erreur
5CancelledAnnulé
Terminal window
cd /root/gitea
docker compose pull runner
docker compose up -d runner
Terminal window
docker system df
docker system prune -f

Voir Troubleshooting pour les problèmes courants :

  • Runner offline
  • Jobs bloqués en Waiting
  • Erreurs checkout
  • Problèmes de portée (owner_id)

RessourceLien
Gitea Actions — Overviewhttps://docs.gitea.com/usage/actions/overview
act_runner — Confighttps://docs.gitea.com/usage/actions/act-runner
Images runner officielleshttps://gitea.com/gitea/runner-images
Compatibilité GitHub Actionshttps://docs.gitea.com/usage/actions/comparison