Semaphore UI : l'alternative légère à Ansible Tower, installée en un conteneur

Ansible DevOps Docker Semaphore Traefik
Semaphore UI : l'alternative légère à Ansible Tower, installée en un conteneur

Quand j'ai préparé le cours sur Ansible Tower, une question revenait sans cesse : « D'accord, mais pour mes quatre serveurs, je fais comment ? » Parce que la réalité, c'est qu'AWX (la version open source de Tower) demande aujourd'hui un cluster Kubernetes et un opérateur, avec plusieurs composants à maintenir. Pour une petite équipe ou une infra personnelle, c'est disproportionné.

La réponse que je donne maintenant, c'est Semaphore UI. Les mêmes idées que Tower (projets, clés, inventaires, modèles de tâches, historique, droits), dans un seul conteneur Docker. Voici comment l'installer proprement et l'utiliser de débutant à expert.

Ce que fait Semaphore (et ce qu'il ne fait pas)

Semaphore est une interface web pour lancer vos automatisations en équipe, avec un historique complet et des accès contrôlés. Contrairement à ce que son nom historique (« Ansible Semaphore ») laisse penser, il ne se limite plus à Ansible : il lance aussi Terraform, OpenTofu, Terragrunt, et des scripts Bash, PowerShell ou Python.

Ce qu'il n'a pas, par rapport à Tower : pas de workflows graphiques avec branches conditionnelles, pas de sources d'inventaire dynamiques aussi riches, pas de surveys aussi poussés. Pour la grande majorité des petites et moyennes équipes, ce n'est pas un problème.

Étape 1 : l'installation avec Docker Compose

J'utilise PostgreSQL plutôt que la base embarquée : c'est ce que recommande le projet pour la production, et ça simplifie les sauvegardes. Et comme tous mes services, Semaphore passe derrière Traefik en HTTPS.

services:
  semaphore-db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: semaphore
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: semaphore
    volumes:
      - semaphore-db:/var/lib/postgresql/data
    networks: [internal]

  semaphore:
    image: semaphoreui/semaphore:v2.13.0   # à adapter : dernière version stable
    restart: unless-stopped
    depends_on: [semaphore-db]
    environment:
      SEMAPHORE_DB_DIALECT: postgres
      SEMAPHORE_DB_HOST: semaphore-db
      SEMAPHORE_DB_PORT: 5432
      SEMAPHORE_DB_USER: semaphore
      SEMAPHORE_DB_PASS: ${DB_PASSWORD}
      SEMAPHORE_DB: semaphore
      SEMAPHORE_ADMIN: admin
      SEMAPHORE_ADMIN_NAME: Administrateur
      SEMAPHORE_ADMIN_EMAIL: admin@monsite.fr
      SEMAPHORE_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
      SEMAPHORE_ACCESS_KEY_ENCRYPTION: ${ENCRYPTION_KEY}
    volumes:
      - semaphore-data:/var/lib/semaphore
    networks: [internal, traefik_web]
    labels:
      - traefik.enable=true
      - traefik.http.routers.semaphore.rule=Host(`semaphore.monsite.fr`)
      - traefik.http.routers.semaphore.entrypoints=websecure
      - traefik.http.routers.semaphore.tls.certresolver=letsencrypt
      - traefik.http.services.semaphore.loadbalancer.server.port=3000

volumes:
  semaphore-db:
  semaphore-data:

networks:
  internal:
  traefik_web:
    external: true

Deux points importants :

  • SEMAPHORE_ACCESS_KEY_ENCRYPTION est la clé qui chiffre tous les secrets du Key Store. Générez-la avec head -c32 /dev/urandom | base64, et sauvegardez-la en dehors du serveur. Sans elle, une restauration de base ne vous rendra que des secrets illisibles.
  • Le port 3000 n'est pas publié sur l'hôte : seul Traefik y accède, via le réseau Docker.

Un docker compose up -d, on ouvre https://semaphore.monsite.fr, et on se connecte avec le compte administrateur.

Le projet : l'unité d'organisation

Tout commence par un projet. Il regroupe tout ce qu'il faut pour automatiser : les clés, les dépôts, les inventaires, les variables et les modèles de tâches. Je crée en général un projet par équipe ou par grand périmètre (« Infra perso », « Clients », « Lab »).

Étape 2 : le Key Store

C'est le coffre à secrets du projet. On y range :

  • les clés SSH pour se connecter aux serveurs et cloner les dépôts privés ;
  • les identifiants (login / mot de passe, mot de passe become) ;
  • les mots de passe Ansible Vault.

Une fois enregistrés, ils sont chiffrés et ne s'affichent plus jamais, même pour l'administrateur. On peut les remplacer, pas les relire.

Étape 3 : le dépôt

On renseigne l'URL du dépôt Git qui contient les playbooks, la branche, et la clé du Key Store pour y accéder. À chaque lancement, Semaphore récupère la dernière version : le dépôt reste la seule source de vérité, comme avec Tower.

Étape 4 : l'inventaire

Trois possibilités : l'écrire directement dans l'interface (format INI ou YAML), pointer vers un fichier du dépôt, ou un fichier sur le serveur Semaphore. On l'associe à la clé SSH qui permet de se connecter aux machines.

[web]
web1.monsite.fr
web2.monsite.fr

[monitoring]
10.8.0.3   # joignable via WireGuard

[all:vars]
ansible_user=deploy

Si vous avez cloisonné votre infra avec WireGuard (comme je le décris dans mon article dédié), placez Semaphore sur une machine du réseau VPN : il pourra joindre les adresses privées des serveurs, sans qu'aucun SSH ne soit exposé publiquement.

Étape 5 : les variables

Un groupe de variables (appelé environment dans l'interface) contient des variables Ansible au format JSON, des variables d'environnement, et des secrets. On le réutilise dans plusieurs modèles : un groupe « production », un groupe « recette ».

Étape 6 : le modèle de tâche

C'est l'équivalent du job template de Tower. Il assemble : quel playbook (chemin dans le dépôt), quel inventaire, quel dépôt, quel groupe de variables. On peut y ajouter des arguments CLI (--limit, --tags) et choisir le type : tâche classique, build (qui produit un artefact versionné) ou deploy (qui déploie un build précis).

Un clic sur « Run », et le journal s'affiche en direct, ligne par ligne, exactement comme dans votre terminal. Chaque exécution est conservée : qui l'a lancée, quand, avec quel commit, et le résultat complet.

Les questions au lancement

Pour les personnes qui ne connaissent pas Ansible, on ajoute des questions au modèle (l'équivalent des surveys de Tower) : la version à déployer, le nom d'un utilisateur à créer. Elles s'affichent dans un formulaire au lancement et deviennent des variables du playbook.

Niveau avancé

Les planifications

Un modèle peut se lancer selon une expression cron. Mon usage typique :

0 3 * * 0    # mises à jour de sécurité, chaque dimanche à 3 h
30 2 * * *   # vérification des sauvegardes, chaque nuit

Les droits

Les droits se gèrent par projet, avec quatre rôles : propriétaire, gestionnaire, lanceur de tâches (task runner) et invité en lecture seule. L'authentification peut passer par LDAP ou OpenID Connect (Authentik, Keycloak, Google…), et l'authentification à deux facteurs est disponible pour les comptes locaux.

Les notifications

En cas d'échec, Semaphore prévient par e-mail, Telegram, Slack, Microsoft Teams, Rocket.Chat, Gotify ou DingTalk. On sait tout de suite quelle tâche a échoué, et on clique directement sur son journal.

Niveau expert

Les intégrations (webhooks)

Une intégration expose une URL secrète qui déclenche un modèle de tâche. Votre dépôt GitLab ou GitHub l'appelle à chaque push sur la branche principale, et le déploiement part tout seul. On peut filtrer sur le contenu du webhook (la branche, l'auteur) et en extraire des valeurs pour les passer en variables.

Les runners

Par défaut, les tâches s'exécutent dans le conteneur Semaphore lui-même. Pour lancer des tâches sur plusieurs machines, ou au cœur d'un réseau isolé, on ajoute des runners : de petits agents qui se connectent au serveur, récupèrent les tâches en attente et les exécutent sur place.

L'API

Tout ce que fait l'interface est disponible par l'API REST, avec un jeton créé dans votre profil :

curl -s -X POST \
  -H "Authorization: Bearer $SEMAPHORE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"template_id": 3}' \
  https://semaphore.monsite.fr/api/project/1/tasks

Les bonnes pratiques

  • Une base de données sauvegardée (PostgreSQL ou MySQL en production), et la clé de chiffrement sauvegardée à part.
  • Semaphore derrière un reverse proxy en HTTPS, idéalement accessible seulement via VPN.
  • Tous les secrets dans le Key Store, jamais dans le dépôt.
  • Un projet par équipe, avec le minimum de droits : la plupart des utilisateurs n'ont besoin que du rôle « lanceur de tâches ».
  • Une version d'image fixée, et une lecture des notes de version avant chaque mise à jour.

Tower ou Semaphore ?

  • Semaphore si vous êtes une petite ou moyenne équipe, que vous voulez quelque chose qui tourne en dix minutes, et que vos besoins sont « lancer des playbooks en équipe avec un historique ».
  • AWX / Ansible Automation Platform si vous avez besoin de workflows complexes avec approbations, d'inventaires dynamiques poussés, d'un RBAC très fin, ou d'un support éditeur.

À retenir

Semaphore, c'est Tower en version légère. Un projet, des clés dans le Key Store, un dépôt, un inventaire, et un modèle de tâche pour tout lancer. Avec l'historique, les planifications, les notifications et les droits en bonus, dans un seul conteneur.

Retour aux articles DevOps