Langue: Français
note · scheduling
Pushkar Kumar 7 min de lecture
Migrer de cron vers les timers systemd
Un guide pratique pour convertir des entrées crontab en unités .timer et .service systemd : syntaxe OnCalendar, journalisation, délais et rattrapage.
- systemd
- cron
- linux
Sur cette page
Cron exécute les tâches planifiées du monde entier depuis quarante ans, et sur la plupart des serveurs il fonctionne encore très bien. Mais dès qu’une tâche a besoin d’une journalisation structurée, d’un environnement contrôlé, d’un ordonnancement des dépendances ou d’un moyen de rattraper son retard après l’arrêt de la machine, le modèle de cron commence à montrer ses limites. C’est là qu’interviennent les timers systemd — et si votre distribution exécute déjà systemd (c’est le cas de Debian, Ubuntu, RHEL, Fedora, Arch et SUSE), vous disposez d’un planificateur plus performant qui reste inutilisé.
Cet article détaille ce qui change réellement lors de la migration, avec de vraies unités que vous pouvez adapter.
Pourquoi se donner la peine d’abandonner cron
Cron tient sur une seule ligne. Cette concision fait son attrait, mais elle est aussi son plafond :
- Journalisation. La sortie d’une tâche cron part là où vous la redirigez, et si vous oubliez, elle est envoyée par e-mail dans une boîte que personne ne lit. Un service systemd écrit automatiquement dans le journal —
journalctl -u myjob.servicevous montre chaque exécution, avec horodatages et codes de sortie. - Environnement. Cron s’exécute avec un
PATHdélibérément minimal et presque aucun environnement, ce qui constitue le piège classique du « ça marche dans mon shell, ça échoue dans cron ». Une unité service déclare son environnement de façon explicite. - Exécutions manquées. Si l’hôte est en veille ou éteint à la minute planifiée, cron saute tout simplement la tâche. Un timer avec
Persistent=truel’exécute dès que la machine est de retour. - Chevauchement et ressources. systemd ne démarre pas une seconde copie d’une tâche tant que la première est encore en cours, et vous pouvez attacher
CPUQuota=,MemoryMax=et d’autres contrôles de ressources à une unité.
Vous n’avez pas besoin de tout migrer. Mais pour les tâches dont une défaillance silencieuse vous coûterait cher, les timers valent bien les deux fichiers qu’ils exigent.
Le modèle à deux fichiers
Une ligne cron réalise la planification et l’exécution au même endroit. systemd sépare cela en un service (quoi exécuter) et un timer (quand l’exécuter). Ils partagent un nom de base.
Prenons cette entrée crontab — exécuter un script de sauvegarde tous les jours à 02:30 :
30 2 * * * /usr/local/bin/backup.shCela devient deux unités dans /etc/systemd/system/.
Le service, backup.service :
[Unit]
Description=Nightly backup
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.shLe timer, backup.timer :
[Unit]
Description=Run nightly backup at 02:30
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.targetType=oneshot indique à systemd que la tâche est censée s’exécuter, se terminer et se quitter — le bon type pour presque toutes les tâches de style cron. La section [Install] du timer est ce qui fait fonctionner systemctl enable ; sans WantedBy=timers.target, le timer ne s’armera pas au démarrage.
Activez-le et démarrez-le :
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timerNotez que vous activez le timer, pas le service. Le timer entraîne le service lorsqu’il se déclenche.
Traduire la planification : OnCalendar
La partie la plus difficile de la migration est le champ de planification, car systemd utilise OnCalendar= plutôt que les cinq champs de cron. Le format est DOW YYYY-MM-DD HH:MM:SS, et il est réellement plus lisible une fois qu’on l’a appris. Quelques correspondances courantes :
# cron # OnCalendar
*/15 * * * * *-*-* *:0/15:00 (every 15 minutes)
0 * * * * *-*-* *:00:00 (hourly, on the hour)
30 2 * * * *-*-* 02:30:00 (daily at 02:30)
0 4 * * 1 Mon *-*-* 04:00:00 (Mondays at 04:00)
0 0 1 * * *-*-01 00:00:00 (1st of the month)
0 9 * * 1-5 Mon..Fri *-*-* 09:00:00 (weekdays at 09:00)Il existe aussi des raccourcis pratiques — hourly, daily, weekly, monthly — si bien que OnCalendar=daily équivaut à minuit chaque jour. La commande la plus utile durant la migration est systemd-analyze calendar, qui analyse une expression et vous montre les prochaines heures de déclenchement :
$ systemd-analyze calendar --iterations=3 'Mon..Fri *-*-* 09:00:00'
Original form: Mon..Fri *-*-* 09:00:00
Normalized form: Mon..Fri *-*-* 09:00:00
Next elapse: Mon 2026-06-08 09:00:00 UTC
From now: 4h 12min left
(next 3) Tue 2026-06-09 09:00:00 UTC
Wed 2026-06-10 09:00:00 UTCSi cette sortie correspond à ce que faisait votre ligne cron, la planification est correcte. Si ce n’est pas le cas, vous avez attrapé le bug avant sa mise en production.
Convertir cron en systemd : les planifications qui ne se transposent pas telles quelles
Le tableau ci-dessus couvre les champs numériques simples. Trois types de lignes cron demandent plus d’attention, car une conversion littérale s’exécute un autre jour, ou jamais.
Les raccourcis @. systemd a ses propres planifications nommées, et elles concordent pour la plupart avec celles de cron. Une seule fait exception :
# cron # systemd
@hourly OnCalendar=hourly (*-*-* *:00:00)
@daily OnCalendar=daily (*-*-* 00:00:00)
@weekly OnCalendar=weekly (Mon *-*-* 00:00:00, cron uses Sunday)
@monthly OnCalendar=monthly (*-*-01 00:00:00)
@yearly OnCalendar=yearly (*-01-01 00:00:00)
@reboot OnBootSec=1min (a monotonic timer, not OnCalendar)Le @weekly de cron correspond à 0 0 * * 0, le dimanche à minuit. Le weekly de systemd correspond au lundi à minuit. Si un rapport doit être prêt avant le lundi matin, écrivez OnCalendar=Sun *-*-* 00:00:00 plutôt que de vous fier au nom. @reboot n’a aucune forme calendaire : utilisez OnBootSec= dans le timer, ou renoncez au timer et donnez au service WantedBy=multi-user.target.
Jour du mois et jour de la semaine ensemble. Quand les deux champs sont restreints, cron exécute la tâche si l’un ou l’autre correspond. 0 9 1 * 1 se déclenche le 1er de chaque mois et chaque lundi. OnCalendar=Mon *-*-01 09:00:00 ne se déclenche que lorsque le 1er tombe un lundi, quelques fois par an. Pour conserver le comportement de cron, indiquez les deux expressions ; un timer accepte plusieurs lignes OnCalendar= et se déclenche sur n’importe laquelle :
[Timer]
OnCalendar=*-*-01 09:00:00
OnCalendar=Mon *-*-* 09:00:00Pas décalés et dimanche noté 7. 5-59/10 * * * * commence à la minute 5, ce qui donne *:05/10. cron accepte aussi bien 0 que 7 pour le dimanche ; systemd veut le nom, Sun. Passez chaque ligne convertie dans systemd-analyze calendar avant de l’activer. Cette vérification prend quelques secondes, et c’est ainsi qu’on repère les raccourcis qui semblent équivalents mais ne le sont pas.
Les pièges qui surgissent vraiment
Fuseau horaire. Cron utilise l’heure locale du système. Les timers systemd aussi par défaut, mais OnCalendar est évalué dans le fuseau horaire du timer, ce qui peut vous surprendre sur des serveurs réglés en UTC. Fixez-le explicitement avec OnCalendar=Mon *-*-* 04:00:00 America/New_York si l’heure locale compte, et n’oubliez pas que les transitions de l’heure d’été peuvent sauter ou dédoubler une exécution.
Effet de meute (thundering herd). Cron déclenche les tâches 0 * * * * exactement à :00 sur l’ensemble de votre flotte. Ajoutez RandomizedDelaySec= pour répartir la charge :
[Timer]
OnCalendar=hourly
RandomizedDelaySec=300
Persistent=trueCela décale aléatoirement chaque exécution jusqu’à cinq minutes — précieux lorsqu’une centaine d’hôtes sollicitent la même API.
Environnement et répertoire de travail. L’environnement clairsemé de cron fait trébucher les gens ; supposer un répertoire de travail aussi. Soyez explicite dans le service :
[Service]
Type=oneshot
WorkingDirectory=/opt/app
Environment=PATH=/usr/local/bin:/usr/bin:/bin
EnvironmentFile=-/etc/app/env
ExecStart=/opt/app/run.shLe - en tête de EnvironmentFile signifie « ne pas échouer si le fichier est absent », ce qui reproduit le comportement tolérant de cron.
Tâches par utilisateur. Une crontab utilisateur correspond à une unité utilisateur. Déposez les fichiers dans ~/.config/systemd/user/, activez avec systemctl --user enable --now myjob.timer, et exécutez loginctl enable-linger $USER pour que le timer survive à la déconnexion.
Vérifier la migration
Après l’activation, confirmez que le timer est armé et examinez son historique :
systemctl list-timers --all # see next/last run for every timer
journalctl -u backup.service --since today # read the job's output
sudo systemctl start backup.service # trigger a manual run to test nowsystemctl start backup.service exécute la tâche immédiatement, indépendamment de la planification — le moyen le plus propre de confirmer que la moitié service fonctionne avant de faire confiance au timer.
Ne traduisez pas chaque champ à la main
La partie mécanique — transformer cinq champs cron en une ligne OnCalendar et échafauder la paire .timer/.service — est exactement le genre de chose qu’il est facile de se tromper subtilement à la main, surtout avec les valeurs de pas, les plages et les cas limites du jour de la semaine. Notre convertisseur Cron vers systemd le fait dans le navigateur : collez une ligne crontab, obtenez une unité timer et service prête à éditer avec l’expression OnCalendar correcte et des notes de migration, sans que rien ne soit téléversé où que ce soit.
Articles liés
-
8 min de lecture
Commande chown sous Linux : changer le propriétaire et le groupe
La commande chown sous Linux expliquée : syntaxe user:group, chown -R et liens symboliques, --reference, chgrp, chmod vs chown, et corriger les permissions des volumes Docker avec des ID numériques.
-
11 min de lecture
Commande chmod sous Linux : syntaxe, exemples et erreurs courantes
La commande chmod sous Linux expliquée : modes octal et symbolique, chmod +x, chmod -R et ses pièges, setuid, setgid et sticky bit, umask, et comment corriger Permission denied.
-
7 min de lecture
Lire les expressions cron : un guide champ par champ
Un guide pratique, champ par champ, pour lire les expressions cron : les cinq champs temporels, les plages, les pas, les listes, les @macros et leurs pièges.