Kubernetes

CronJob planifie un pod. Il n'orchestre rien.

Kubernetes sait déjà planifier. Ce qu'il ne fait pas : exprimer l'ordre entre les jobs, conserver les logs une fois le pod collecté, ou atteindre quoi que ce soit hors du cluster. Dagu exécute chaque étape comme un Job Kubernetes et ajoute autour le graphe, l'historique et le franchissement de frontière.

Chaque étape est un vrai Job Kubernetes, pas un script autour de kubectl
Les logs des pods entrent dans l'historique de Dagu et survivent au pod
Un workflow peut couvrir plusieurs clusters via les contextes kubeconfig
Les étapes cluster côtoient SSH, HTTP et validation dans le même graphe
01

Ce que CronJob ne fait pas

CronJob est un bon planificateur pour un pod. Les manques apparaissent dès qu'un batch dépasse un pod, et toutes les équipes rencontrent les trois mêmes.

  • Il n'existe aucune dépendance entre CronJobs. L'ordre s'exprime en devinant des décalages horaires, ce qui casse silencieusement le premier jour où un job dure plus longtemps
  • L'historique est superficiel par défaut : trois exécutions réussies et une échouée sont conservées, et les logs disparaissent avec les pods. Expliquer l'échec de mardi dernier est souvent impossible
  • Si plus de cent échéances consécutives sont manquées et que startingDeadlineSeconds n'est pas défini, le CronJob cesse totalement de planifier et attend qu'un humain s'en aperçoive
02

Les étapes sont des Jobs, et les logs reviennent

Dagu crée un Job mono-conteneur par étape, l'attend, diffuse les logs du pod et utilise le code de sortie du conteneur terminé. Les logs sont écrits dans l'historique d'exécution : ils sont encore là quand le pod et le Job ont disparu.

  • depends exprime l'ordre directement, si bien qu'une extraction en échec arrête le chargement au lieu de l'alimenter avec rien
  • retry_policy rejoue l'étape en créant un nouveau Job, ce qui diffère de backoffLimit qui redémarre un pod sur place
  • Les Jobs sont supprimés après exécution par défaut, donc un graphe nocturne ne laisse pas derrière lui une traînée de Jobs terminés

Kubernetes expose un flux de logs de conteneur fusionné : pour ce type d'étape, stdout et stderr arrivent entrelacés en un seul flux.

Un batch en trois étapes sous forme de vrais Jobs Kubernetes
# k8s-nightly-etl.yaml
schedule: "0 2 * * *"
max_active_runs: 1

kubernetes:
  namespace: batch
  service_account: dagu-runner
  resources:
    requests:
      cpu: "250m"
      memory: "512Mi"

steps:
  - id: extract
    action: k8s.run
    with:
      image: ghcr.io/example/extract:1.4.0
      command: extract --source warehouse
    retry_policy:
      limit: 2
      interval_sec: 120

  - id: transform
    action: k8s.run
    with:
      image: ghcr.io/example/transform:1.4.0
    depends: extract

  - id: load
    action: k8s.run
    with:
      image: ghcr.io/example/load:1.4.0
      resources:
        limits:
          cpu: "2"
          memory: "4Gi"
    depends: transform

handler_on:
  failure:
    run: ./scripts/page-oncall.sh

mail_on:
  failure: true
03

Le travail qui ne tient pas dans un cluster

C'est la partie que CronJob ne peut accomplir à aucun prix, car un CronJob est limité au cluster où il vit. Un workflow qui touche deux clusters, ou un cluster et un système sur site, n'a nulle part où exister dans Kubernetes.

  • kubeconfig et context se règlent par étape : la préproduction et la production deviennent deux étapes d'un workflow au lieu de deux déploiements du même manifeste
  • Une étape cluster peut se placer entre une étape SSH sur un hôte historique et un appel HTTP vers une API SaaS, parce que l'orchestrateur n'est pas lui-même une ressource du cluster
  • Une étape human.task suspend le workflow pour une validation typée, sans occuper de processus pendant l'attente, puis poursuit vers l'étape de production
Promouvoir une migration entre clusters, avec validation
# k8s-promote-across-clusters.yaml
max_active_runs: 1

kubernetes:
  namespace: batch
  service_account: dagu-runner

steps:
  - id: migrate_staging
    action: k8s.run
    with:
      context: staging
      image: ghcr.io/example/migrator:3.2
      command: migrate up

  - id: verify_staging
    run: ./scripts/verify-schema.sh staging
    depends: migrate_staging

  - id: approve
    action: human.task
    with:
      prompt: Promote the migration to production?
      form:
        type: object
        properties:
          change_ticket:
            type: string
          confirmed:
            type: boolean
        required: [change_ticket, confirmed]
    depends: verify_staging

  - id: migrate_production
    action: k8s.run
    with:
      context: production
      image: ghcr.io/example/migrator:3.2
      command: migrate up
    depends: approve

  - id: record
    run: ./scripts/record-change.sh "${steps.approve.outputs.change_ticket}"
    depends: migrate_production

handler_on:
  failure:
    run: ./scripts/page-oncall.sh

mail_on:
  failure: true
04

Là où Argo Workflows est la meilleure réponse

Argo Workflows est la réponse native Kubernetes au même problème, et c'est la bonne pour une large catégorie de travaux. L'arbitrage porte sur l'endroit où vit l'orchestrateur.

  • Argo tourne en CRD et contrôleur dans le cluster : un avantage si tout ce que vous orchestrez s'y trouve déjà, une contrainte sinon
  • Dagu est un binaire qui peut résider hors du cluster, ce qui rend possibles les graphes multi-clusters et transfrontaliers
  • Si vous voulez que les définitions de workflow soient des objets Kubernetes, gérés par les mêmes RBAC et flux GitOps que le reste du cluster, c'est la conception d'Argo, pas celle de Dagu
05

Ce que l'exécuteur n'expose délibérément pas

Le type d'étape Kubernetes est volontairement étroit. Il couvre bien la forme habituelle d'une étape batch et ne cherche pas à devenir un applicateur de manifestes généraliste.

  • Un conteneur par étape, avec une seule commande. Aucun passage direct d'une spec Pod ou Job brute
  • parallelism, completions, completion mode et success policy des Jobs ne sont pas exposés : les Jobs indexés et parallèles restent hors périmètre
  • restart_policy n'est pas configurable, et les options spécifiques à Windows, SELinux, AppArmor et proc_mount ne sont pas disponibles

Si un champ n'est pas documenté pour ce type d'étape, considérez-le comme non pris en charge. Un travail qui exige une spec de Job complète s'applique mieux via kubectl depuis une étape de commande, ou se confie à Argo.

FAQ

Practical questions before adopting

Dagu doit-il tourner dans le cluster ?

Non. Il résout le cluster via une kubeconfig explicite, puis les règles normales de chargement, puis la configuration in-cluster : les deux fonctionnent. Le placer dehors est ce qui rend possibles les workflows multi-clusters et transfrontaliers ; le placer dedans convient quand tout ce qu'il touche est dans ce cluster.

En quoi cela diffère-t-il d'un CronJob qui lance un script appelant kubectl ?

Ce schéma donne l'ordre et rien d'autre : le code de sortie du pod enveloppant masque l'étape en échec, les reprises relancent tout le script, et les logs forment un flux indifférencié qui disparaît avec le pod. Dagu crée un Job par étape, si bien que chaque étape a son statut, sa reprise et son log conservé.

Les étapes partagent-elles un système de fichiers ?

Non. Chaque étape est un Job distinct, donc un pod distinct. Transmettez les données via un stockage objet, un volume persistant monté dans chaque étape, ou les sorties d'étape pour de petites valeurs, exactement comme entre des Jobs séparés.

Qu'advient-il du Job quand une exécution est annulée ?

Les chemins d'annulation, d'arrêt forcé et de dépassement de délai forcent le nettoyage même lorsque cleanup_policy vaut keep : une exécution interrompue ne laisse donc pas le Job derrière elle. En fonctionnement normal, le Job est supprimé une fois terminé.

Faut-il l'utiliser à la place d'Argo Workflows ?

Seulement si le fait que l'orchestrateur soit hors du cluster vous est utile. Si toutes les tâches sont des conteneurs d'un même cluster et que vous voulez des workflows sous forme d'objets Kubernetes régis par les mêmes RBAC et GitOps, Argo convient mieux. Dagu s'adapte aux graphes mêlant jobs de cluster, hôtes, API et validations humaines.

Next step

Start with one workflow.

Install Dagu, move one script that runs on cron today into YAML, and decide from a real run history.