Aller au contenu
Culture DevOps medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Installer GARM avec LXD sur Ubuntu 24.04

11 min de lecture

Ce guide installe GARM v0.2.0 (nightly) sur une VM Ubuntu 24.04 qui fait déjà tourner Gitea. À la fin, GARM sera actif en tant que service systemd, le provider LXD sera enregistré, et l’API répondra sur le port 9997.

GARM (GitHub/Gitea Actions Runner Manager) peut être installé :

  • De la même façon que Gitea : un seul binaire, un service systemd
  • Sans Docker en production (Docker sert uniquement à extraire le binaire depuis l’image nightly)
  • VM Ubuntu 24.04 avec 4 Go de RAM, 30 Go de disque
  • Gitea installé et accessible (voir Installer Gitea)
  • Docker installé sur votre machine locale (pas sur la VM)
  • Accès SSH avec sudo sur la VM

Étape 1 — Extraire les binaires GARM depuis Docker (machine locale)

Section intitulée « Étape 1 — Extraire les binaires GARM depuis Docker (machine locale) »

GARM ne publie pas encore de releases binaires pour la branche nightly. La méthode la plus simple est d’extraire les binaires depuis l’image Docker officielle.

Sur votre machine locale :

Fenêtre de terminal
# 1. Télécharger l'image nightly
docker pull ghcr.io/cloudbase/garm:nightly
# 2. Créer un conteneur sans le démarrer
CONTAINER_ID=$(docker create ghcr.io/cloudbase/garm:nightly)
# 3. Extraire les 3 binaires
docker cp "${CONTAINER_ID}:/usr/bin/garm" /tmp/garm
docker cp "${CONTAINER_ID}:/usr/bin/garm-cli" /tmp/garm-cli
docker cp "${CONTAINER_ID}:/usr/bin/garm-provider-lxd" /tmp/garm-provider-lxd
# 4. Supprimer le conteneur temporaire
docker rm "${CONTAINER_ID}"
# 5. Vérifier la version extraite
/tmp/garm --version
# → v0.2.0-alpha-274-g8ff29e19 (ou version plus récente)
Fenêtre de terminal
VM_IP="192.168.122.52" # Adapter à votre VM
# Copier les 3 binaires
scp /tmp/garm /tmp/garm-cli /tmp/garm-provider-lxd lab@${VM_IP}:/tmp/
# Se connecter à la VM
ssh lab@${VM_IP}
# Installer les binaires
sudo install -o root -g root -m 755 /tmp/garm /usr/local/bin/garm
sudo install -o root -g root -m 755 /tmp/garm-cli /usr/local/bin/garm-cli
# Installer le provider LXD dans un répertoire dédié
sudo mkdir -p /opt/garm/providers.d
sudo install -o root -g root -m 755 /tmp/garm-provider-lxd /opt/garm/providers.d/garm-provider-lxd
# Vérifier
garm --version
# → v0.2.0-alpha-274-g8ff29e19

LXD est le provider local qui va créer les conteneurs runners. Sur Ubuntu 24.04, il s’installe via snap.

Fenêtre de terminal
# Installer LXD via snap (version LTS 5.x)
sudo snap install lxd
# Initialiser LXD avec les paramètres par défaut
sudo lxd init --auto
# Vérifier que le socket Unix est présent
test -S /var/snap/lxd/common/lxd/unix.socket && echo "LXD OK"
# Ajouter votre utilisateur au groupe lxd (pour utiliser lxc sans sudo)
sudo usermod -aG lxd ${USER}
newgrp lxd
# Vérifier la version
lxd --version
# → 5.21.4 LTS

GARM tourne en tant qu’utilisateur dédié, sans shell, membre du groupe lxd pour accéder au socket LXD.

Fenêtre de terminal
sudo useradd \
--system \
--no-create-home \
--shell /usr/sbin/nologin \
--groups lxd \
garm
# Vérifier
id garm
# → uid=997(garm) gid=997(garm) groups=997(garm),988(lxd)

Étape 5 — Créer les répertoires et la configuration

Section intitulée « Étape 5 — Créer les répertoires et la configuration »
  1. Créer les répertoires :

    Fenêtre de terminal
    sudo mkdir -p /etc/garm /var/lib/garm
    sudo chown garm:garm /var/lib/garm && sudo chmod 750 /var/lib/garm
    sudo chown root:garm /etc/garm && sudo chmod 750 /etc/garm
  2. Créer /etc/garm/config.toml :

    Fenêtre de terminal
    sudo tee /etc/garm/config.toml << 'EOF'
    [default]
    listen_address = "0.0.0.0"
    listen_port = 9997
    # Clé AES-256 — doit faire exactement 32 caractères
    passphrase = "Rk7mPvXhQdNwYeWpKsLuJ3TbFcGnAz12"
    [jwt_auth]
    secret = "garm-lab-jwt-secret-change-in-prod"
    time_to_live = "24h"
    [apiserver]
    bind = "0.0.0.0"
    port = 9997
    [apiserver.cors]
    allow_origins = ["*"]
    [logging]
    log_level = "info"
    log_format = "text"
    [database]
    backend = "sqlite3"
    passphrase = "Rk7mPvXhQdNwYeWpKsLuJ3TbFcGnAz12"
    [database.sqlite3]
    db_file = "/var/lib/garm/garm.db"
    [[provider]]
    name = "lxd_local"
    description = "LXD local"
    provider_type = "external"
    [provider.external]
    provider_executable = "/opt/garm/providers.d/garm-provider-lxd"
    config_file = "/etc/garm/garm-provider-lxd.toml"
    EOF
  3. Créer /etc/garm/garm-provider-lxd.toml :

    Fenêtre de terminal
    sudo tee /etc/garm/garm-provider-lxd.toml << 'EOF'
    [lxd]
    # Socket Unix local — pas de TLS nécessaire
    unix_socket = "/var/snap/lxd/common/lxd/unix.socket"
    instance_type = "container"
    profile_name = "default"
    image_timeout = 300
    EOF
  4. Fixer les permissions :

    Fenêtre de terminal
    sudo chown garm:garm /etc/garm/config.toml /etc/garm/garm-provider-lxd.toml
    sudo chmod 640 /etc/garm/config.toml /etc/garm/garm-provider-lxd.toml
Fenêtre de terminal
sudo tee /etc/systemd/system/garm.service << 'EOF'
[Unit]
Description=GARM — GitHub/Gitea Actions Runner Manager
After=network.target
[Service]
Type=simple
User=garm
Group=garm
WorkingDirectory=/var/lib/garm
ExecStart=/usr/local/bin/garm -config /etc/garm/config.toml
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/lib/garm /etc/garm
ReadOnlyPaths=/opt/garm
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable garm
sudo systemctl start garm
Fenêtre de terminal
# Vérifier que le service tourne
sudo systemctl status garm --no-pager
# Vérifier que le socket est en écoute
ss -tlnp | grep 9997
# → LISTEN 0 0.0.0.0:9997
# Tester l'API (401 = normal, GARM répond mais requiert une auth)
curl -s -o /dev/null -w "%{http_code}" http://localhost:9997/api/v1/
# → 401

GARM ne crée pas de compte admin automatiquement. La première commande garm-cli init crée l’administrateur et configure le profil local de garm-cli. Cette opération est à faire une seule fois sur chaque installation.

Fenêtre de terminal
garm-cli init \
--name "mon-garm" \
--url "http://localhost:9997" \
--username "garmadmin" \
--password "MotDePasseForte2026!" \
--email "admin@garm.lab"

Vérification :

Fenêtre de terminal
# Afficher les infos du contrôleur
garm-cli controller show
# → Controller ID, version, URLs...
# Lister les providers
garm-cli provider list
# → lxd_local
SymptômeCauseSolution
passphrase must be…32 charactersPassphrase trop courteCompter exactement 32 chars dans config.toml
permission denied sur le socket LXDL’user garm n’est pas dans le groupe lxdsudo usermod -aG lxd garm + restart
Port 9997 déjà utiliséAutre processus`ss -tlnp
garm-cli: token expiredLe token JWT a expirégarm-cli profile login -u admin -p pass
Service en failed au démarrageErreur configjournalctl -u garm -n 20 pour voir l’erreur
  • Les binaires GARM nightly s’extraient depuis l’image Docker ghcr.io/cloudbase/garm:nightly.
  • La passphrase dans config.toml doit faire exactement 32 caractères (AES-256).
  • L’user garm doit être dans le groupe lxd pour accéder au socket Unix de LXD.
  • garm-cli init est une opération unique : elle crée l’admin et configure le profil local.
  • Une réponse HTTP 401 de l’API confirme que GARM tourne correctement.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn