Ubuntu 24.04 « Clock skew detected » — corriger la synchronisation horaire et stopper les échecs de build/deploiement (cas n°46)

Cet article vous a aidé ?

« Clock skew detected » est l’un de ces messages qui donne l’impression que l’ordinateur vous juge parce que vous croyez que le temps est réel. Votre build tourne pendant 12 minutes, puis s’arrête parce qu’un fichier semble venir du futur. Votre pipeline de déploiement refuse de signer un artefact parce que TLS estime que le certificat n’est pas encore valide. Et votre canal d’incident se transforme en cours de philosophie.

Sur Ubuntu 24.04, vous pouvez corriger cela de manière fiable — si vous traitez la synchronisation horaire comme une dépendance de production, pas comme une fonctionnalité en arrière-plan. Voici le playbook pratique : comment prouver d’où vient la dérive, comment l’arrêter, et comment la maintenir arrêtée sur du bare metal, des VM, des conteneurs et des runners CI.

Ce que « Clock skew detected » signifie réellement (et pourquoi ça casse les builds)

Ce message provient généralement de make (ou d’outils qui se comportent de façon similaire) lorsque les dates de modification des fichiers semblent incohérentes. L’exemple classique : un fichier généré a une date postérieure à l’heure système actuelle, ou un fichier dépendance paraît plus récent que ses dépendants d’une manière impossible. Le système de build suppose que votre horloge est fausse parce qu’il se base sur l’ordre des mtimes pour décider quoi reconstruire.

Mais « Clock skew detected » n’est rarement seulement une affaire de make. C’est le symptôme que l’horloge murale n’est plus monotone et digne de confiance sur cet hôte. Une fois que cela arrive, vous obtenez une cascade :

  • CI builds se reconstruisent indéfiniment ou échouent parce que les horodatages sautent en arrière ou en avant en cours d’exécution.
  • TLS et artefacts signés échouent quand le système pense que les certificats ne sont pas encore valides / sont déjà expirés.
  • APT et dépôts de paquets se plaignent de « Release file is not valid yet » quand le client est en avance sur l’horodatage du dépôt.
  • Systèmes distribués deviennent bizarres. Pas toujours cassés, mais bizarres. Vous verrez des problèmes d’ordre des logs, d’expiration de jetons, d’élections de leader instables et des audits désynchronisés.

Le temps a deux grandes facettes sous Linux :

  • Horloge murale (CLOCK_REALTIME) : ce que lisent les humains, ce que les horodatages utilisent, ce que TLS vérifie.
  • Horloge monotone (CLOCK_MONOTONIC) : avance toujours, utilisée pour les timeouts et mesurer les durées.

La plupart des problèmes de synchronisation concernent l’horloge murale. Mais les causes racines se trouvent souvent sous l’OS : firmware, hyperviseur, états d’alimentation CPU, sélection de clocksource, ou un hôte qui ne peut tout simplement pas atteindre ses serveurs NTP.

Un modèle mental fiable : si votre environnement n’arrive pas à garder l’heure, il n’arrive pas à tenir ses promesses. Les builds, les déploiements et les contrôles de sécurité supposent tous que les horodatages ont du sens.

Idée paraphrasée (attribuée) : Gene Kranz prêchait la « toughness and competence » — les opérations fonctionnent quand vous gardez vos fondamentaux solides sous pression. La synchronisation horaire est un fondamental.

Bêtise #1 : La seule chose pire qu’un « clock skew » est un « clock skew » dans une timeline de postmortem. Soudain tout le monde est innocent parce que « les logs mentent ».

Playbook de diagnostic rapide

Si vous êtes en pleine panne de déploiement, vous n’avez pas le temps pour un cours sur la théorie NTP. Voici l’ordre qui trouve le goulet le plus rapidement sur Ubuntu 24.04.

Première étape : confirmer la dérive et si elle est toujours en cours

  1. Vérifiez l’heure actuelle, le fuseau horaire et l’état de synchronisation (une seule commande donne la plupart des infos).
  2. Vérifiez si le temps « saute » (un grand pas) ou « dérive » (erreur qui s’accumule lentement).

Deuxième étape : identifier qui est chargé de la synchronisation

  1. Est-ce systemd-timesyncd ou chronyd ?
  2. Êtes-vous dans une VM/containeur avec des règles de temps particulières ?

Troisième étape : valider l’accessibilité et le choix des sources de temps

  1. Pouvez-vous joindre UDP/123 vers vos serveurs configurés ?
  2. Êtes-vous réellement synchronisé sur un bon serveur (faible stratum, offset raisonnable, stable) ?

Quatrième étape : vérifier la plateforme : VM, hyperviseur, clocksource, suspend/reprise

  1. Des VM qui dérivent souvent signifient que l’hôte est correct mais l’intégration invité est mal configurée.
  2. Les grands sauts corrèlent souvent avec une reprise depuis suspension, une restauration de snapshot, ou un hôte tellement surchargé qu’il manque des ticks de tenue du temps.

Cinquième étape : atténuer l’impact en production

  1. Corrigez l’heure, puis invalidez les artefacts corrompus (les sorties de build peuvent être empoisonnées par de mauvais mtimes).
  2. Redémarrez seulement ce qu’il faut redémarrer (daemons de synchronisation horaire, pas toute la flotte à moins d’aimer le chaos).

Faits et contexte historique réellement utiles

  • NTP est ancien et éprouvé. Le Network Time Protocol date des années 1980 et reste l’épine dorsale de la synchronisation horaire sur Internet.
  • Les secondes intercalaires sont un événement opérationnel réel. Elles ont provoqué des incidents quand les systèmes les ont gérées de façon incohérente (step vs smear vs ignore).
  • Linux n’a pas qu’« une horloge ». Il a plusieurs horloges et plusieurs clocksource (TSC, HPET, ACPI PM timer), et de mauvais choix peuvent se traduire par de la dérive.
  • La virtualisation a changé la tenue du temps. Les invités peuvent « courir en retard » quand l’hôte est surchargé, mis en pause, snapshotté ou migré.
  • Chrony a été conçu pour les conditions hostiles. Il est populaire en datacenter parce qu’il gère mieux la connectivité intermittente et les grands offsets initiaux que ntpd classique dans de nombreux contextes.
  • Systemd-timesyncd est volontairement minimal. Il synchronise le temps mais n’a pas vocation à être une suite NTP complète ; ça suffit jusqu’à ce que vous ayez besoin de diagnostics et de contrôle.
  • Les systèmes de build dépendent des mtimes parce que c’est rapide. C’est aussi fragile sur des filesystems réseau, des restaurations de VM et des horloges décalées.
  • TLS est une machine temporelle avec des règles. Les fenêtres de validité des certificats sont strictes ; si votre horloge est fausse, la sécurité vous arrête (à raison).
  • L’horloge monotone a sauvé beaucoup de logiciels. Beaucoup de bugs de timeout ont disparu quand le logiciel a cessé d’utiliser l’horloge murale pour mesurer des durées — vos outils de build n’ont peut‑être pas reçu la mise à jour.

Tâches pratiques : commandes, sorties, décisions (12+)

Voici les commandes que j’exécute sur Ubuntu 24.04 quand le pager affiche « clock skew » et que le pipeline CI est en feu. Chaque tâche inclut : la commande, ce que signifie la sortie, et la décision à prendre.

Task 1 — Check system time, sync status, and which service is in charge

cr0x@server:~$ timedatectl
               Local time: Mon 2025-12-30 09:41:12 UTC
           Universal time: Mon 2025-12-30 09:41:12 UTC
                 RTC time: Mon 2025-12-30 09:40:02
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: no
              NTP service: active
          RTC in local TZ: no

Signification : System clock synchronized: no est le signal d’alerte. Le RTC diffère d’environ 70 secondes, aussi suspect.

Décision : Confirmer ce qu’est réellement le « NTP service » (chrony ou systemd-timesyncd) et vérifier pourquoi la synchronisation n’est pas atteinte.

Task 2 — Identify active time sync daemon(s)

cr0x@server:~$ systemctl status chrony systemd-timesyncd --no-pager
● chrony.service - chrony, an NTP client/server
     Loaded: loaded (/usr/lib/systemd/system/chrony.service; enabled; preset: enabled)
     Active: active (running) since Mon 2025-12-30 09:37:01 UTC; 4min 11s ago
● systemd-timesyncd.service - Network Time Synchronization
     Loaded: loaded (/usr/lib/systemd/system/systemd-timesyncd.service; disabled; preset: enabled)
     Active: inactive (dead)

Signification : Chrony est actif ; timesyncd est désactivé. Bien : un seul responsable, pas deux.

Décision : Utiliser chronyc pour les diagnostics réels. Si les deux étaient actifs, désactivez-en un (généralement timesyncd si vous voulez chrony).

Task 3 — Quick chrony health: tracking

cr0x@server:~$ chronyc tracking
Reference ID    : 00000000 ()
Stratum         : 0
Ref time (UTC)  : Thu Jan 01 00:00:00 1970
System time     : 0.832145678 seconds fast of NTP time
Last offset     : +0.832145678 seconds
RMS offset      : 0.500000000 seconds
Frequency       : 0.000 ppm
Residual freq   : +0.000 ppm
Skew            : 0.000 ppm
Root delay      : 1.000000000 seconds
Root dispersion : 10.000000000 seconds
Update interval : 0.0 seconds
Leap status     : Not synchronised

Signification : Stratum 0 avec Reference ID 0 signifie que chrony n’a pas de source sélectionnée. Non synchronisé.

Décision : Examiner les sources et leur accessibilité ensuite. Typiquement réseau, DNS ou mauvaise configuration.

Task 4 — See configured sources and whether they’re reachable

cr0x@server:~$ chronyc sources -v
  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^? ntp1.corp.lan                 0   6     0     -     +0ns[   +0ns] +/-    0ns
^? ntp2.corp.lan                 0   6     0     -     +0ns[   +0ns] +/-    0ns

Signification : ^? et Reach 0 signifient qu’il ne reçoit pas de réponses. Stratum 0 ici est « inconnu/injoignable », pas « très précis ».

Décision : Vérifier la résolution DNS et le chemin UDP/123. Ne touchez pas encore au clocksource ; c’est probablement juste bloqué.

Task 5 — Confirm DNS resolution for NTP hosts

cr0x@server:~$ getent ahosts ntp1.corp.lan
10.20.30.40     STREAM ntp1.corp.lan
10.20.30.40     DGRAM  ntp1.corp.lan
10.20.30.40     RAW    ntp1.corp.lan

Signification : Le nom se résout. Bien. Si cela échoue, chrony paraîtra « cassé » alors que c’est juste le DNS.

Décision : Si le DNS échoue, corrigez le résolveur d’abord. Si le DNS est correct, vérifiez le pare-feu/le routage pour UDP/123.

Task 6 — Validate UDP/123 connectivity (firewall or routing issues)

cr0x@server:~$ sudo nft list ruleset | sed -n '1,80p'
table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    iif "lo" accept
    ct state established,related accept
    tcp dport 22 accept
    ip protocol icmp accept
  }
}

Signification : Politique drop sur input, pas de règle explicite UDP/123 entrante — correct pour un client. Mais il faut aussi permettre l’egress et l’état de retour (c’est fait : established/related).

Décision : Si l’egress est bloqué en amont (cloud SG, pare-feu corporate), corrigez là-bas. Sur l’hôte, vérifiez la chaîne output si vous l’appliquez.

Task 7 — Watch chrony logs for “no reply” and step events

cr0x@server:~$ sudo journalctl -u chrony --since "30 min ago" --no-pager
Dec 30 09:37:01 server chronyd[932]: chronyd version 4.5 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER)
Dec 30 09:37:02 server chronyd[932]: Could not resolve address for ntp2.corp.lan: Name or service not known
Dec 30 09:37:05 server chronyd[932]: No suitable source for synchronisation

Signification : Ici on voit la cause réelle : échec de résolution pour une source ; pas de source adaptée globalement.

Décision : Corriger le DNS ou remplacer temporairement les sources par des adresses IP pendant que DNS est réparé.

Task 8 — Check whether the RTC is drifting or set wrong

cr0x@server:~$ sudo hwclock --verbose
hwclock from util-linux 2.39.3
System Time: 1735551672.123456
Trying to open: /dev/rtc0
Using the rtc interface to the clock.
Last drift adjustment done at 0 seconds after 1969
RTC time: 1735551602.000000, RTC epoch: 1900, offset: 0
Time since last adjustment is 1735551602 seconds
Calculated Hardware Clock drift is 0.000000 seconds
Hardware clock is on UTC time

Signification : Le RTC a ~70 secondes de retard sur l’heure système. Cela peut arriver après un boot si NTP n’a pas encore synchronisé et que l’heure système est aussi incorrecte.

Décision : Une fois NTP stable, synchroniser le RTC depuis l’heure système (hwclock --systohc) sur du bare metal. Dans les VM, le RTC est souvent virtualisé ; traitez‑le avec précaution.

Task 9 — Confirm what time source systemd thinks is configured (timesyncd setups)

cr0x@server:~$ timedatectl timesync-status
       Server: 185.125.190.57 (ntp.ubuntu.com)
Poll interval: 32min 0s (min: 32s; max 34min 8s)
         Leap: normal
      Version: 4
      Stratum: 2
    Reference: 7B5E1A2F
    Precision: 1us (-20)
Root distance: 28.217ms (max: 5s)
       Offset: +3.122ms
        Delay: 24.503ms
       Jitter: 2.731ms
 Packet count: 41
    Frequency: -12.345ppm

Signification : Si vous utilisez timesyncd, ceci est de l’or : stratum 2, faible offset, jitter stable. C’est sain.

Décision : Si l’offset est énorme ou que le serveur manque, migrez vers chrony pour une meilleure récupération et des diagnostics, surtout sur VM ou réseaux instables.

Task 10 — Detect time jumps (suspend, VM restore, or host pausing)

cr0x@server:~$ sudo journalctl --since "2 hours ago" | grep -E "Time has been changed|clock.*jump|System clock"
Dec 30 08:55:11 server systemd[1]: Time has been changed
Dec 30 08:55:11 server chronyd[932]: System clock was stepped by -38.214567 seconds

Signification : Un pas de -38 secondes est un saut en arrière. C’est exactement ainsi que vous obtenez « fichier venant du futur » ou « dépendances dans le passé ».

Décision : Identifier pourquoi le stepping se produit. Chrony effectue des steps au démarrage/grands offsets par conception (configurable). Si cela survient en cours d’uptime, suspectez une pause/restore de VM ou une source de temps défaillante.

Task 11 — Validate the kernel clocksource (rare, but real)

cr0x@server:~$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc

Signification : tsc est généralement correct sur le matériel moderne et les VM, mais si vous observez de l’instabilité ou des bugs connus de plateforme, changer peut aider (prudemment).

Décision : Ne changez le clocksource que si vous avez des preuves (sauts/dérive corrélés à des plateformes spécifiques). Sinon, vous soignez le symptôme au marteau.

Task 12 — Compare time against a known-good external reference quickly

cr0x@server:~$ chronyc -n tracking | sed -n '1,6p'
Reference ID    : C0A80101 (192.168.1.1)
Stratum         : 3
Ref time (UTC)  : Mon Dec 30 09:42:01 2025
System time     : -0.000231456 seconds slow of NTP time
Last offset     : -0.000120001 seconds

Signification : Offset sub-millisecondes : excellent. Ce n’est pas la machine qui cause vos échecs de build (sauf si vos mtimes sont corrompus).

Décision : Déplacez l’investigation vers l’environnement de build lui-même (volumes partagés, horodatages du checkout, temps du host de conteneur, etc.).

Task 13 — Find whether you’re building on a network filesystem with timestamp weirdness

cr0x@server:~$ findmnt -T "$PWD"
TARGET SOURCE                FSTYPE OPTIONS
/      /dev/mapper/vg0-root  ext4   rw,relatime

Signification : ext4 local est prévisible. Si vous voyez nfs, cifs ou quelque chose d’exotique, les mtimes peuvent refléter l’heure du serveur, pas celle du client.

Décision : Si l’espace de travail de build est sur NFS/CIFS, assurez-vous que le serveur est aussi synchronisé, ou déplacez les builds sur disque local.

Task 14 — Prove the mtime anomaly that triggers make

cr0x@server:~$ ls -l --full-time build/output.o src/input.c
-rw-r--r-- 1 cr0x cr0x  8216 2025-12-30 09:50:01.000000000 +0000 build/output.o
-rw-r--r-- 1 cr0x cr0x   412 2025-12-30 09:41:10.000000000 +0000 src/input.c

Signification : Si l’heure courante est 09:42 mais que output.o est à 09:50, le fichier futur a été créé avec une horloge erronée.

Décision : Nettoyez et rebuildez après correction du temps ; ne faites pas confiance aux builds incrémentaux une fois les mtimes empoisonnés.

Task 15 — After fixing sync: verify “synchronized” and stable sources

cr0x@server:~$ timedatectl
               Local time: Mon 2025-12-30 09:43:22 UTC
           Universal time: Mon 2025-12-30 09:43:22 UTC
                 RTC time: Mon 2025-12-30 09:43:22
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Signification : C’est l’état final souhaité : synchronized yes, RTC aligné, UTC partout.

Décision : Maintenant remédiez aux sorties de build (clean workspace, purge des caches qui stockent des timestamps) et ajoutez du monitoring pour éviter que cela ne revienne mardi prochain.

Schémas de correction qui fonctionnent sur Ubuntu 24.04

Ubuntu 24.04 fonctionnera volontiers avec systemd-timesyncd ou chrony. Choisissez-en un. Configurez‑le correctement. Supervisez‑le. Les plus gros incidents de synchronisation que j’ai gérés n’étaient pas causés par le « mauvais » daemon ; ils étaient causés par l’ambiguïté et la négligence.

Pattern A: Standard server/VM fleet — use chrony, keep it boring

Chrony est généralement le bon choix par défaut pour les serveurs et les runners CI parce qu’il gère la « vraie vie » : connectivité intermittente, VM en pause, nœuds bootant depuis des snapshots, et réseaux qui bloquent parfois l’UDP pour le plaisir.

Install and enable chrony (if not already)

cr0x@server:~$ sudo apt update
...output...
cr0x@server:~$ sudo apt install -y chrony
...output...
cr0x@server:~$ sudo systemctl enable --now chrony
...output...

Point de décision : Si vous aviez déjà timesyncd actif, désactivez‑le pour éviter des boucles de discipline concurrentes.

cr0x@server:~$ sudo systemctl disable --now systemd-timesyncd
Removed "/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service".

Configure sane sources

Éditez /etc/chrony/chrony.conf. En réseau d’entreprise, pointez vers des serveurs NTP internes (idéalement redondants). Dans des environnements plus petits, utilisez les pools Ubuntu ou le service horaire de votre fournisseur. L’essentiel est la redondance et l’accessibilité.

Exemple (ne copiez pas aveuglément les noms ; utilisez vos serveurs réels) :

cr0x@server:~$ sudo sed -n '1,80p' /etc/chrony/chrony.conf
pool ntp.ubuntu.com        iburst maxsources 4
keyfile /etc/chrony/chrony.keys
driftfile /var/lib/chrony/chrony.drift
ntsdumpdir /var/lib/chrony
logdir /var/log/chrony
makestep 1.0 3

Ce qui compte :

  • iburst accélère la synchronisation initiale au démarrage.
  • makestep 1.0 3 permet de faire des steps (sauts) si l’offset > 1s durant les 3 premières mises à jour. Utile au boot ; dangereux si cela se produit ensuite.

Conseil d’opinion : laissez makestep activé pour le démarrage. Les nœuds CI qui démarrent avec une mauvaise heure gaspillent plus d’argent que ce que coûte un step.

Restart and verify

cr0x@server:~$ sudo systemctl restart chrony
...output...
cr0x@server:~$ chronyc sources -v
...output...
cr0x@server:~$ chronyc tracking
...output...

Point de décision : Vous voulez une source sélectionnée (*), un registre reach non nul (pas 0) et un stratum raisonnable (typiquement 2–4 en entreprise). Si vous n’en avez aucune : c’est toujours réseau/DNS/pare-feu.

Pattern B: Minimal desktops or appliances — timesyncd is fine

Systemd-timesyncd suffit pour de nombreux systèmes non critiques. Mais il est plus facile de le dépasser que de regretter chrony. Si vous gardez timesyncd, au moins verrouillez une liste fiable de serveurs.

Éditez /etc/systemd/timesyncd.conf et définissez des serveurs explicites si votre réseau bloque les pools publics.

cr0x@server:~$ sudo sed -n '1,120p' /etc/systemd/timesyncd.conf
[Time]
NTP=ntp1.corp.lan ntp2.corp.lan
FallbackNTP=ntp.ubuntu.com
cr0x@server:~$ sudo systemctl restart systemd-timesyncd
...output...
cr0x@server:~$ timedatectl timesync-status
...output...

Point de décision : Si timesyncd ne peut pas joindre les serveurs, il échouera silencieusement jusqu’à ce que quelque chose d’autre crie (comme votre pipeline). Si vous avez besoin de diagnostics et de résilience plus forts, migrez vers chrony.

Pattern C: VM guests — stop fighting the hypervisor, but don’t trust it blindly

La dérive temporelle des VM est courante. L’invité peut être correct mais aussi être mis en pause, restauré depuis un snapshot, migré ou limité. Ce sont tous des événements temporels.

Conseils pratiques :

  • Exécutez toujours un service de synchronisation invité. Même si l’hyperviseur aide, vous voulez que l’invité se discipline lui‑même.
  • Alignez stratégie hôte/invité. Si l’hyperviseur injecte l’heure et que l’invité effectue des steps agressifs, vous pouvez obtenir des oscillations.
  • Surveillez les events de step en cours d’uptime. Ce n’est généralement pas de la simple dérive ; c’est un événement de plateforme.

Si vous observez des steps pendant que la VM fonctionne normalement, cherchez une sur‑souscription de l’hôte ou du CPU steal. C’est un problème SRE déguisé en problème temporel.

Pattern D: Containers — you can’t fix host time from inside the container

Les conteneurs utilisent le noyau hôte. Si un conteneur de build indique « clock skew detected », l’heure de l’hôte est erronée ou l’espace de travail est monté depuis un endroit avec de mauvais timestamps. Vous pouvez installer chrony dans un conteneur et vous sentir productif, mais cela ne disciplinera pas l’horloge de l’hôte sauf à faire des opérations privilegiées—ce qui est un autre type d’incident.

Corrigez le nœud. Ou corrigez le système de fichiers qui fournit les mtimes.

Pattern E: CI/CD — clean artifacts after time correction

Une fois le temps corrigé, vous avez encore des artefacts empoisonnés : fichiers générés avec des horodatages futurs, caches contenant des métadonnées, et graphes de build incrémental qui mentent maintenant. L’action correcte est généralement :

  • Nettoyer l’espace de travail (git clean -xfd dans un runner jetable ; plus prudent sur des hôtes persistants).
  • Invalider les caches qui stockent des mtimes (caches de build spécifiques aux langages, caches de compilateur, caches d’artefacts).
  • Rebuild une fois à partir de zéro pour réinitialiser la chaîne des dépendances.

Bêtise #2 : La synchronisation horaire est comme se brosser les dents — vous l’ignorez une semaine et soudain tout devient cher et tout le monde est fâché.

Trois mini-récits d’entreprise (anonymisés, plausibles et techniquement douloureux)

Mini-récit 1 — L’incident causé par une mauvaise hypothèse

L’entreprise avait une nouvelle image runner Ubuntu 24.04 pour le CI. Elle était « hardenée », donc l’UDP sortant était bloqué par défaut. L’hypothèse : « Nous n’exécutons pas de services qui ont besoin d’UDP. » Cette phrase a l’air propre dans un tableur et devient moche en production.

En quelques heures, les builds ont commencé à échouer avec make: warning: Clock skew detected. Parallèlement, une autre équipe signalait des erreurs intermittentes « certificate not valid yet » lors des pulls depuis un registre interne. Les symptômes semblaient sans rapport. La cause commune était la dérive temporelle : les runners démarraient avec une horloge décalée de quelques minutes, puis dérivaient davantage parce que NTP ne pouvait rien atteindre.

La revue d’incident fut de l’archéologie d’entreprise classique. La sécurité avait imposé le blocage UDP. La plateforme était passée de timesyncd à chrony pour « meilleure précision » sans valider les règles d’egress. Le CI subissait les échecs mais ne possédait pas la politique réseau. Les dashboards montraient CPU et mémoire ; la synchronisation horaire n’était pas du tout monitorée.

La correction fut peu romantique : autoriser l’egress UDP/123 des runners vers les serveurs NTP internes, ajouter une seconde source NTP, et alerter quand timedatectl signale non synchronisé pendant plus de quelques minutes après le boot. Le plus grand changement fut culturel : ils ont cessé de supposer que « l’UDP n’est que pour des trucs legacy bizarres ». NTP n’est pas bizarre. C’est une fondation.

Mini-récit 2 — L’optimisation qui s’est retournée contre eux

Une équipe infra voulait des déploiements plus rapides. Ils ont activé un scaling agressif basé sur des snapshots pour les agents de build : restaurer un snapshot VM, exécuter un build, jeter. Le provisioning était bien plus rapide — jusqu’à la première fois où le snapshot avait été pris alors que l’horloge était légèrement erronée et que les tools invités avaient été mis en pause.

Les VM restaurées avaient des offsets variant de secondes à minutes. Parfois chrony corrigeait vite. Parfois il faisait un pas en arrière en plein build, justement quand le système de build générait des headers. Les artefacts résultants avaient des horodatages incohérents, et les builds ont commencé à échouer de façon sporadique. « Sporadiquement » est le mot qui vieillit les ingénieurs.

La première tentative de correction fut de désactiver le stepping parce que « le stepping casse les builds ». Cela améliora certains échecs et en aggravera d’autres. Sans stepping, certaines VM restaient décalées assez longtemps pour que TLS et la logique d’expiration de jetons échouent, et le pull du registry devint instable lui aussi.

La vraie solution fut de traiter les snapshots comme « non sûrs temporellement » à moins de concevoir pour ça : prendre le snapshot après que la sync soit stable, forcer un sync au boot, et envisager de supprimer tout répertoire de build mis en cache qui aurait survécu au snapshot. Ils ont aussi introduit une porte de santé : si la VM n’était pas synchronisée dans une fenêtre courte, elle était terminée et remplacée. Ce n’est pas élégant. C’est fiable. La fiabilité bat l’élégance en production.

Mini-récit 3 — La pratique ennuyeuse mais correcte qui a sauvé la mise

Une autre organisation avait une règle : chaque nœud a deux sources de temps indépendantes (appliances stratum-1 internes et un service temps fournisseur), et chaque cluster alerte si un nœud n’est pas synchronisé depuis plus de 10 minutes. Personne n’aimait cette règle. C’était « juste du bruit de monitoring » jusqu’à ce que ce ne le soit plus.

Un mardi, un changement de pare-feu corporate a bloqué l’accès aux appliances NTP primaires depuis un nouveau subnet. La plupart des équipes ne remarquèrent pas tout de suite parce que les choses « marchaient à peu près ». Mais le monitoring le fit. Les alertes ont déclenché : les nœuds basculaient sur la source secondaire et montraient un jitter accru.

Parce qu’ils avaient de la redondance, rien d’utile pour l’utilisateur ne se brisa. Les déploiements ont continué. Les builds ont continué. TLS est resté heureux. L’équipe a eu le temps de corriger le pare-feu pendant les heures ouvrables au lieu d’un incident nocturne.

C’est la partie qui semble ennuyeuse dans un rapport et glorieuse à 3h du matin : la bonne pratique n’était pas fancy. C’était la redondance et l’alerte sur l’état de synchronisation horaire. Cela les a sauvés d’un incident où l’on ne peut pas faire confiance aux logs, aux jetons ou aux certificats. C’est un « incident entreprise », pas une « petite panne ».

Erreurs courantes : symptôme → cause racine → correctif

1) Symptom: “Clock skew detected” during make, especially in CI

Root cause: system time stepped backwards or forwards, or build workspace contains files created when time was wrong (future mtimes).

Fix: stabilize time sync first; then clean the workspace and rebuild. Don’t try to “touch” a few files and hope. Use ls -l --full-time to find future timestamps, then wipe outputs.

2) Symptom: “Release file is not valid yet” from apt

Root cause: your node’s clock is ahead of repository metadata timestamps.

Fix: fix NTP; do not pin old repository metadata as a workaround. After sync, rerun apt update.

3) Symptom: TLS errors “certificate is not yet valid” or token expiry weirdness

Root cause: clock offset (often minutes) on client or server; sometimes caused by VM restore or blocked NTP.

Fix: verify both ends are synchronized. Fix network reachability to NTP. For fleets, alert on sync state and offset.

4) Symptom: chrony running but never synchronizes (stratum 0, reach 0)

Root cause: NTP servers unreachable, DNS failures, UDP/123 blocked, or wrong server addresses.

Fix: validate resolution and network path; add redundant sources; ensure you’re not pointing to an address that only works on a different VLAN.

5) Symptom: time “snaps” by tens of seconds during uptime

Root cause: VM pause/resume, snapshot restore, host overload, or chrony stepping due to huge offset discovered late.

Fix: investigate platform events; tune makestep to only allow early boot stepping; ensure VM guest tools and host NTP are configured sanely.

6) Symptom: logs out of order, distributed traces nonsense

Root cause: some nodes have skew; others don’t. Your observability stack is faithfully recording lies.

Fix: enforce time sync across the fleet; consider rejecting nodes that fail time sync health checks (especially for Kubernetes workers).

7) Symptom: only builds on NFS-backed workspace fail with skew warnings

Root cause: server/client time mismatch or filesystem timestamp semantics, especially when the NFS server isn’t synced.

Fix: sync NFS server time; move workspaces local; ensure the NFS infrastructure is part of the time-sync monitoring domain.

8) Symptom: two time daemons fighting (oscillating offset, frequent “stepped” events)

Root cause: both timesyncd and chrony (or other tools) are trying to discipline the clock.

Fix: pick one daemon. Disable the other. Verify sync stability after the change.

Checklists / plan étape par étape

Checklist A — Emergency response when builds/deploys are failing

  1. Confirm skew is real: run timedatectl and record sync state.
  2. Identify the time daemon: systemctl status chrony systemd-timesyncd.
  3. Check time source health: chronyc tracking and chronyc sources -v (or timedatectl timesync-status).
  4. Fix reachability: validate DNS and network policy for UDP/123.
  5. Force stabilization: restart the time service after fixing network/DNS.
  6. Verify stable sync: synchronized = yes, selected NTP source exists, low offset.
  7. Clean tainted build outputs: wipe workspace/build directories and rebuild once cleanly.
  8. Re-run deploy: if TLS/token failures were present, retry after time correction.

Checklist B — Hardening a fleet so this doesn’t come back

  1. Standardize: choose chrony (recommended for servers/CI) or timesyncd (minimal), not both.
  2. Redundancy: configure at least two NTP sources on different infrastructure paths.
  3. Monitoring: alert on unsynchronized state and large offsets. Don’t wait for make to tell you.
  4. Platform alignment: ensure hypervisors and bare metal hosts also sync time; guests can’t compensate forever.
  5. CI hygiene: treat time fixes as cache invalidation events; purge artifact caches when skew occurs.
  6. Change control: firewall and DNS changes should include “does NTP still work?” as a test.
  7. Incident breadcrumbs: keep logs of time step events and NTP source changes for forensic timelines.

Checklist C — When you suspect VM/platform time drift

  1. Search logs for “System clock was stepped”.
  2. Correlate with VM lifecycle events (snapshot restore, migration, pause/resume).
  3. Check clocksource and kernel messages if drift is extreme.
  4. Validate host time sync; a bad host creates bad guests.
  5. Use chrony and restrict stepping to early boot unless you have a strong reason.

FAQ

1) Why does “clock skew detected” show up in make at all?

make s’appuie sur les dates de modification du système de fichiers pour décider ce qui doit être reconstruit. Si une dépendance paraît plus récente qu’elle ne devrait l’être — ou plus récente que « maintenant » — il vous alerte parce qu’il ne peut pas raisonner de façon fiable sur le graphe de build.

2) I fixed NTP, but make still warns. Why?

Parce que vous avez encore des fichiers avec des horodatages futurs créés pendant la période de mauvaise heure. Corrigez le temps d’abord, puis nettoyez les sorties et rebuild. Les builds incrémentaux après un événement de skew ne sont pas fiables sauf si vous assainissez les mtimes.

3) Should I use chrony or systemd-timesyncd on Ubuntu 24.04?

Pour les serveurs, runners CI et tout ce qui doit récupérer d’un réseau imparfait ou des bizarreries de VM : chrony. Pour des desktops simples ou des appliances minimales : timesyncd peut suffire. Le mauvais choix est d’exécuter les deux.

4) Can I just manually set the time with date and move on?

Vous pouvez, mais c’est un pansement temporaire. Si la machine ne peut pas joindre NTP ou continue de dériver à cause de problèmes de plateforme, ça repartira. De plus : changer manuellement l’heure en vol peut perturber TLS, les caches et les logs.

5) What’s the deal with stepping vs slewing?

Stepping saute l’horloge à la bonne heure rapidement. Slewing ajuste progressivement. Le stepping peut casser des charges sensibles aux horodatages ; le slewing peut vous laisser incorrect plus longtemps. Le makestep de chrony offre un compromis sensé : step seulement tôt au démarrage quand vous êtes déjà fragile.

6) Does timezone configuration cause clock skew errors?

Une mauvaise configuration de fuseau horaire cause généralement de la confusion humaine, pas du skew. L’heure système (UTC en interne) peut rester correcte. Mais si vous voyez des réglages RTC/localtime contradictoires, cela peut indiquer une provision négligée. Gardez les serveurs en UTC. Toujours.

7) Why do containers get clock skew errors if they can’t set time?

Parce qu’ils héritent du temps du noyau hôte. Si un conteneur de build se plaint, corrigez la synchronisation de l’hôte ou les timestamps du système de fichiers monté. Installer NTP dans un conteneur non privilégié est surtout de la mise en scène.

8) How much offset is “too much” for CI and deploys?

Le sous-seconde est normal. Quelques secondes peuvent casser des systèmes stricts (certains jetons, certains workflows de signature). Des minutes casseront absolument TLS et la gestion des paquets. Si vous voyez des dizaines de secondes, considérez‑le comme un défaut en production.

9) We blocked UDP everywhere. Can we sync time without UDP/123?

NTP classique utilise UDP/123. Certains environnements utilisent des méthodes alternatives de distribution du temps en interne, mais la vérité opérationnelle reste : vous devez autoriser le protocole de temps que vous avez choisi. Si vous le bloquez, vos systèmes finiront par inventer leur propre chronologie.

10) Should I sync the hardware clock (RTC) too?

Sur du bare metal : oui, une fois que votre temps système est correct et stable, écrivez‑le sur le RTC avec hwclock --systohc. Sur des VM : soyez prudent ; le comportement du RTC dépend de l’hyperviseur et de l’intégration invité.

Prochaines étapes que vous devriez réellement entreprendre

Si vous corrigez une défaillance active : faites fonctionner la synchronisation horaire en premier, puis supprimez les artefacts de build empoisonnés. Ne négociez pas avec des mtimes empoisonnés. Ils ne s’améliorent pas par l’espoir.

Pour une correction durable sur Ubuntu 24.04 :

  • Standardisez sur un service horaire (chrony est le choix pragmatique pour serveurs et CI).
  • Configurez des sources NTP redondantes que votre réseau autorise réellement.
  • Alertez quand l’état est non synchronisé et sur les événements de step.
  • Auditez vos pratiques lifecycle VM (snapshots, restaurations, migrations) pour leur impact temporel.
  • Après tout incident de skew, nettoyez builds et caches une fois pour réinitialiser le monde.

La chute est ennuyeuse, ce qui est le signe qu’elle est correcte : un temps fiable est une dépendance comme le DNS et le stockage. Vous ne le « configurez pas et l’oubliez ». Vous l’exploitez, vous le surveillez et vous le maintenez ennuyeux.

← Précédent
ZFS Raw Send : Répliquer des données chiffrées sans partager les clés
Suivant →
Undervolting et limites de puissance : des PC plus silencieux sans regret

Laisser un commentaire