Aller au contenu
medium

dkron : l'ordonnanceur cron distribué et tolérant aux pannes

11 min de lecture

logo dkron

dkron est un ordonnanceur cron distribué et tolérant aux pannes, écrit en Go. Là où un crontab vit sur une seule machine, dkron répartit vos tâches planifiées sur un cluster sans point de défaillance unique, avec une interface web, une API REST et un historique des exécutions. Ce guide monte un cluster haute disponibilité en Docker Compose, crée des jobs, et prouve la tolérance aux pannes en tuant le leader pour observer la ré-élection. Testé avec dkron 4.1.1. Pour intermédiaires à l'aise avec Docker et les API.

  • Ce qu'apporte un cron distribué par rapport à cron.
  • L'architecture de dkron (Serf, Raft, executors).
  • Monter un cluster HA de trois serveurs en Docker Compose.
  • Créer un job planifié via l'API et l'interface.
  • Vérifier la tolérance aux pannes par un failover réel.

dkron est un service de planification qui exécute des commandes à intervalle régulier, comme cron, mais à l'échelle d'un parc de machines. Sa promesse tient en trois mots : distribué, tolérant aux pannes, sans SPOF (Single Point Of Failure). Concrètement, plusieurs nœuds forment un cluster ; si celui qui pilote tombe, un autre prend le relais automatiquement, sans intervention humaine.

On le pilote de trois façons : une interface web pour créer et suivre les jobs, une API REST pour l'automatisation, et des executors qui réalisent le travail (shell, HTTP, et d'autres via plugins). Le projet est open source, maintenu par la communauté sous dkron-io/dkron.

Le cron classique rend d'énormes services, mais il montre vite ses limites en production. Il vit sur une seule machine : si elle tombe, les tâches ne partent plus. Il ne garde aucun historique exploitable, n'offre aucune interface, et ne sait pas cibler plusieurs serveurs ni gérer des dépendances entre tâches.

dkron répond à chacun de ces manques. La planification survit à la panne d'un nœud, chaque exécution est tracée avec sa sortie, l'interface montre l'état du cluster, et on cible les machines par tags. C'est le passage d'un crontab isolé à un ordonnanceur de cluster gouverné.

dkron s'appuie sur deux briques éprouvées de l'écosystème HashiCorp. Serf gère l'appartenance au cluster et la détection de panne via un protocole gossip : chaque nœud sait en permanence qui est vivant. Raft assure la cohérence et l'élection du leader : à tout instant, un seul nœud planifie, et s'il disparaît, les autres en réélisent un.

Un cluster mélange deux rôles. Les serveurs participent au consensus Raft et peuvent planifier ; les agents se contentent d'exécuter les tâches qu'on leur confie. On sélectionne les cibles d'un job par tags, exactement comme un inventaire.

On déploie trois serveurs (pour un quorum Raft qui survit à une panne) et un agent d'exécution. L'image officielle est dkron/dkron, épinglée ici en 4.1.1.

  1. Écrire la stack dans un fichier docker-compose.yml :

    services:
    dkron1:
    image: dkron/dkron:4.1.1
    command: agent --server --bootstrap-expect=3 --node-name=dkron1
    hostname: dkron1
    ports:
    - "8899:8080" # interface web et API
    environment:
    - GODEBUG=netdns=go
    dkron2:
    image: dkron/dkron:4.1.1
    command: agent --server --bootstrap-expect=3 --retry-join=dkron1:8946 --node-name=dkron2
    hostname: dkron2
    environment:
    - GODEBUG=netdns=go
    depends_on: [dkron1]
    dkron3:
    image: dkron/dkron:4.1.1
    command: agent --server --bootstrap-expect=3 --retry-join=dkron1:8946 --node-name=dkron3
    hostname: dkron3
    environment:
    - GODEBUG=netdns=go
    depends_on: [dkron1]
    dkron-agent:
    image: dkron/dkron:4.1.1
    command: agent --retry-join=dkron1:8946 --tag worker=true --node-name=agent1
    hostname: agent1
    environment:
    - GODEBUG=netdns=go
    depends_on: [dkron1]
  2. Démarrer le cluster :

    Fenêtre de terminal
    docker compose up -d

    Le drapeau --bootstrap-expect=3 fait patienter dkron jusqu'à ce que les trois serveurs soient présents avant d'élire un leader. Les nœuds se rejoignent par --retry-join sur le port Serf (8946).

Après quelques secondes, on vérifie l'état du cluster par l'API :

Fenêtre de terminal
curl -s http://localhost:8899/v1/leader | grep -o '"Name":"[^"]*"'
curl -s http://localhost:8899/v1/members | grep -o '"Name":"[^"]*"'
"Name":"dkron2" # le leader élu
"Name":"dkron1" "Name":"dkron2" "Name":"dkron3" "Name":"agent1"

L'interface web répond sur http://localhost:8899. Son tableau de bord affiche le leader, les compteurs de jobs, les statistiques d'exécution et, tout en bas, la liste des membres du cluster avec leur statut.

Tableau de bord dkron : leader, statistiques et membres du cluster

Un job décrit une commande, une planification et une cible. On le crée via l'API avec curl. Ici, un job shell qui s'exécute toutes les 15 secondes sur l'agent porteur du tag worker :

Fenêtre de terminal
curl -s -XPOST http://localhost:8899/v1/jobs -H "Content-Type: application/json" -d '{
"name": "sauvegarde-demo",
"schedule": "@every 15s",
"timezone": "Europe/Paris",
"owner": "stephane",
"tags": {"worker": "true:1"},
"concurrency": "forbid",
"executor": "shell",
"executor_config": {
"shell": "true",
"command": "echo Sauvegarde OK sur $(hostname) a $(date +%H:%M:%S)"
}
}'

La clé "tags": {"worker": "true:1"} cible un nœud portant worker=true ; la valeur concurrency: "forbid" empêche deux exécutions simultanées du même job. On peut aussi créer un job depuis l'interface, avec le bouton Create :

Formulaire de création d'un job dans dkron

Le détail d'un job récapitule sa planification, son executor, ses tags et ses compteurs de succès :

Détail d'un job dkron : schedule, executor et tags

Chaque déclenchement produit une exécution tracée. La vue Executions liste l'historique, avec le nœud qui a exécuté, l'horodatage et le statut :

Historique des exécutions dkron, toutes en succès

En ouvrant une exécution, on lit sa sortie exacte, ce que cron ne conserve jamais :

Sortie d'une exécution dkron avec le résultat de la commande

La même information est disponible par l'API, utile pour la supervision :

Fenêtre de terminal
curl -s "http://localhost:8899/v1/jobs/sauvegarde-demo/executions" | tail
... "success":true, "output":"Sauvegarde OK sur agent1 a 09:28:04\n", "node_name":"agent1" ...

L'argument central de dkron, c'est de survivre à la panne du nœud qui planifie. On le vérifie en tuant le leader et en observant la ré-élection.

Fenêtre de terminal
# le leader avant la panne
curl -s http://localhost:8899/v1/leader | grep -o '"Name":"[^"]*"' # -> "Name":"dkron2"
# on arrête brutalement le leader
docker kill lab-dkron-dkron2-1
# quelques secondes plus tard, un nouveau leader a été élu
curl -s http://localhost:8899/v1/leader | grep -o '"Name":"[^"]*"' # -> "Name":"dkron3"

En moins de dix secondes, Raft a réélu dkron3 comme leader, et le job a continué de s'exécuter sur l'agent sans rien perdre. C'est très exactement le comportement sans SPOF annoncé.

Quelques réflexes évitent les mauvaises surprises. Utilisez shell: "true" dès que la commande contient des variables. Ciblez toujours vos jobs par tags plutôt que de laisser tous les nœuds s'exécuter. Posez concurrency: "forbid" sur les tâches longues pour éviter les chevauchements.

Côté production, deux points sont non négociables. Le trafic gossip entre nœuds doit être chiffré (clé d'encryption Serf), et l'API comme l'interface doivent passer derrière du TLS et une authentification. Un cluster dkron ouvert en clair, c'est une exécution de commandes à distance offerte au premier venu.

  • dkron est un cron distribué tolérant aux pannes : plus de crontab isolé, un cluster sans SPOF.
  • Il s'appuie sur Serf (appartenance, gossip) et Raft (cohérence, élection du leader).
  • Un cluster mêle serveurs (planifient) et agents (exécutent) ; on cible par tags.
  • On crée les jobs par API ou par l'interface, avec historique et sortie conservés.
  • La haute disponibilité est réelle : tuer le leader déclenche une ré-élection en quelques secondes.
  • En production, chiffrez le gossip et protégez l'API par TLS et authentification.

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn