“Clock skew detected” es uno de esos errores que da la sensación de que el ordenador te juzga por creer que el tiempo es real. Tu compilación se ejecuta durante 12 minutos y luego falla porque un archivo parece venir del futuro. Tu pipeline de despliegue se niega a firmar un artefacto porque TLS piensa que el certificado aún no es válido. Y tu canal de incidentes se convierte en una clase de filosofía.
En Ubuntu 24.04 puedes arreglar esto de forma fiable—si tratas la sincronización de tiempo como una dependencia de producción, no como una característica de fondo. Este es el manual práctico: cómo demostrar de dónde viene la desincronía, cómo detenerla y cómo mantenerla detenida en metal desnudo, VMs, contenedores y runners de CI.
Qué significa realmente “clock skew detected” (y por qué rompe compilaciones)
El mensaje normalmente proviene de make (o herramientas que se comportan de forma similar) cuando los tiempos de modificación de archivos parecen inconsistentes. El ejemplo clásico: un archivo generado tiene una marca temporal posterior a la hora del sistema actual, o un archivo dependencia parece más reciente que sus dependientes de una manera imposible. El sistema de compilación asume que tu reloj está mal porque se basa en el orden de los mtime para decidir qué necesita recompilarse.
Pero “clock skew detected” rara vez es solo sobre make. Es un síntoma de que el tiempo de pared ya no es monótono ni confiable en ese host. Una vez que eso ocurre, tienes una cascada:
- Compilaciones CI que se recompilan sin fin o fallan porque las marcas temporales retroceden o avanzan en medio de la ejecución.
- TLS y artefactos firmados que fallan cuando el sistema piensa que los certificados aún no son válidos o ya expiraron.
- APT y repositorios de paquetes que se quejan de “Release file is not valid yet” cuando el cliente está adelantado respecto a la marca del repositorio.
- Sistemas distribuidos que se vuelven extraños. No siempre rotos, pero sí extraños. Verás problemas de ordenamiento en logs, expiración de tokens, elecciones de líderes que fluctúan y auditorías que no coinciden.
El tiempo tiene dos caras importantes en Linux:
- Reloj de pared (CLOCK_REALTIME): lo que leen los humanos, lo que usan las marcas temporales y lo que usa TLS para chequear validez.
- Reloj monotónico (CLOCK_MONOTONIC): siempre avanza, usado para timeouts y medir duraciones.
La mayoría de los problemas de sincronización son problemas del reloj de pared. Pero las causas raíces a menudo viven debajo del SO: firmware, hipervisor, estados de energía de la CPU, selección de clocksource, o un host que simplemente no puede alcanzar sus servidores NTP.
Un modelo mental fiable: si tu entorno no puede mantener el tiempo, no puede mantener promesas. Compilaciones, despliegues y controles de seguridad asumen que las marcas temporales significan algo.
Idea parafraseada (atribuida): Gene Kranz defendía “duros y competentes”—las operaciones funcionan cuando mantienes los fundamentos sólidos bajo presión. La sincronización de tiempo es un fundamento.
Broma #1: Lo único peor que un clock skew es un clock skew en una línea de tiempo de un postmortem. De repente todos son inocentes porque “los logs mienten”.
Guía rápida de diagnóstico
Si estás en medio de un despliegue que falla, no tienes tiempo para un recorrido por la teoría de NTP. Este es el orden que encuentra el cuello de botella más rápido en Ubuntu 24.04.
Primero: confirma la desincronía y si aún está ocurriendo
- Comprueba la hora actual, la zona horaria y el estado de sincronización (un solo comando te da la mayor parte).
- Verifica si el tiempo está “saltando” (un gran paso) vs “derivando” (acumulación lenta de error).
Segundo: identifica quién debe sincronizar el tiempo
- ¿Es
systemd-timesyncdochronyd? - ¿Estás dentro de una VM/contenedor con reglas especiales de tiempo?
Tercero: valida la alcanzabilidad y la selección de fuentes de tiempo
- ¿Puedes alcanzar UDP/123 hacia tus servidores configurados?
- ¿Realmente te estás sincronizando con un buen servidor (bajo estrato, offset razonable, estable)?
Cuarto: revisa la plataforma: VM, hipervisor, clocksource, suspend/resume
- Las VMs que derivan a menudo significan que el tiempo del host está bien pero la integración del invitado está mal configurada.
- Los grandes saltos suelen correlacionarse con reanudación desde suspensión, restauración de snapshot o un host sobrecargado que pierde ticks de mantenimiento del tiempo.
Quinto: mitiga el impacto en producción
- Arregla el tiempo y luego invalida los artefactos corruptos (los outputs de build pueden estar contaminados por mtimes malos).
- Reinicia solo lo que haga falta (demonios de sincronización de tiempo, no toda la flota salvo que disfrutes del caos).
Hechos y contexto histórico que sí ayudan
- NTP es antiguo y probado en batalla. El Network Time Protocol data de los años 80 y sigue siendo la columna vertebral de la sincronización de tiempo en internet.
- Los segundos intercalados son un evento operativo real. Han causado interrupciones cuando los sistemas los manejaron de forma inconsistente (step vs smear vs ignore).
- Linux no “solo tiene un reloj”. Tiene múltiples relojes y múltiples clocksource (TSC, HPET, ACPI PM timer), y malas elecciones pueden aparecer como deriva.
- La virtualización cambió la forma de llevar el tiempo. Los invitados pueden quedar “retrasados” cuando el host está sobreasignado, pausado, con snapshot o migrado.
- Chrony fue creado para condiciones hostiles. Es popular en centros de datos porque maneja conectividad intermitente y grandes offsets iniciales mejor que el ntpd clásico en muchos casos.
- Systemd-timesyncd es intencionalmente minimalista. Sincroniza el tiempo pero no pretende ser una suite NTP completa; eso está bien hasta que necesitas diagnósticos y control.
- Los sistemas de compilación dependen de los mtimes porque es rápido. También es frágil en sistemas de archivos en red, restauraciones de VM y relojes desincronizados.
- TLS es una máquina del tiempo con reglas. Las ventanas de validez de certificados son estrictas; si tu reloj está mal, la seguridad te detendrá (con razón).
- El tiempo monotónico salvó mucho software. Muchos bugs de timeouts desaparecieron cuando el software dejó de usar el reloj de pared para duraciones—tus herramientas de build pueden no haber recibido el memo.
Tareas prácticas: comandos, salidas, decisiones (12+)
Estos son los comandos que ejecuto en Ubuntu 24.04 cuando el pager dice “clock skew” y la pipeline de CI está en llamas. Cada tarea incluye: comando, qué significa la salida y qué decisión tomar.
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
Significado: System clock synchronized: no es la bandera roja. El RTC difiere por ~70 segundos, también sospechoso.
Decisión: Confirma qué es realmente “NTP service” (chrony o systemd-timesyncd) y revisa por qué no se logra la sincronización.
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)
Significado: Chrony se está ejecutando; timesyncd está deshabilitado. Bien: un solo responsable, no dos.
Decisión: Usa chronyc para diagnósticos reales. Si ambos estuvieran activos, deshabilitarías uno (normalmente timesyncd si quieres 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
Significado: Estrato 0 con Reference ID 0 significa que chrony no tiene una fuente seleccionada. No está sincronizado.
Decisión: Mira las fuentes y la alcanzabilidad a continuación. Esto suele ser red, DNS o mala configuración.
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
Significado: ^? y Reach 0 significa que no está recibiendo respuestas. Estrato 0 aquí es “desconocido/inaccesible”, no “muy preciso”.
Decisión: Revisa la resolución DNS y el path UDP/123. No toques clocksource todavía; probablemente esté bloqueado por la red.
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
Significado: El nombre resuelve. Bien. Si esto falla, chrony parecerá “roto” pero solo es DNS.
Decisión: Si DNS falla, arregla el resolvedor primero. Si DNS está bien, revisa firewall/ruteo para 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
}
}
Significado: Política drop en input, sin regla explícita para UDP/123 entrante—está bien para un cliente. Pero también necesitas permitir el egreso y que el tráfico de retorno sea aceptado por estado (lo es: established/related).
Decisión: Si el egreso está bloqueado río arriba (security group en la nube, firewall corporativo), arregla allí. En el host, revisa la cadena de output si la aplicas.
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
Significado: Aquí vemos la causa real: fallo de resolución para una fuente; ninguna fuente adecuada en general.
Decisión: Arregla DNS o reemplaza fuentes con IPs temporalmente mientras DNS se repara.
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
Significado: El RTC está ~70 segundos detrás del tiempo del sistema. Eso puede pasar tras el arranque si NTP no se ha sincronizado y la hora del sistema también está mal.
Decisión: Una vez que NTP esté estable, sincroniza el RTC desde el tiempo del sistema (hwclock --systohc) en metal desnudo. En VMs, el RTC suele ser virtual; trátalo con cuidado.
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
Significado: Si usas timesyncd, esto es oro: estrato 2, offset bajo, jitter estable. Eso es saludable.
Decisión: Si el offset es enorme o falta el servidor, pasa a chrony para mejor recuperación y diagnósticos, especialmente en VMs o redes inestables.
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
Significado: Un paso de -38 segundos es un salto hacia atrás. Eso es exactamente cómo obtienes “archivo del futuro” o “dependencias en el pasado”.
Decisión: Identifica por qué ocurre el step. Chrony hace step en el arranque/grandes offsets por diseño (configurable). Si ocurre en medio del tiempo de actividad, sospecha de pausa/restore de VM o fuente de tiempo rota.
Task 11 — Validate the kernel clocksource (rare, but real)
cr0x@server:~$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc
Significado: tsc suele estar bien en hardware moderno y VMs, pero si ves inestabilidad o bugs conocidos de plataforma, cambiar puede ayudar (con precaución).
Decisión: Cambia el clocksource solo si tienes evidencia (saltos/deriva correlacionados con plataformas específicas). De lo contrario estarás tratando el síntoma con un martillo.
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
Significado: Offset sub-milisegundo: excelente. Esa no es la caja que causa tus fallos de compilación (a menos que los mtimes del sistema de archivos estén corruptos).
Decisión: Traslada la investigación al propio entorno de compilación (volúmenes compartidos, timestamps del checkout, tiempo del host del contenedor, 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
Significado: ext4 local es predecible. Si ves nfs, cifs o algo exótico, los mtimes pueden reflejar la hora del servidor, no la del cliente.
Decisión: Si el workspace de build está en NFS/CIFS, asegúrate de que el servidor esté sincronizado también, o mueve los builds a disco 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
Significado: Si la hora actual es 09:42 pero output.o es 09:50, el archivo futuro se creó con un reloj malo en el momento de su creación.
Decisión: Limpia y recompila tras arreglar el tiempo; no confíes en builds incrementales una vez que las marcas temporales están envenenadas.
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
Significado: Este es el estado final que deseas: synchronized yes, RTC alineado, UTC por todas partes.
Decisión: Ahora remedia los outputs de build (limpia el workspace, purga cachés que almacenen timestamps) y añade monitorización para que esto no vuelva el próximo martes.
Patrones de solución que funcionan en Ubuntu 24.04
Ubuntu 24.04 funcionará bien con systemd-timesyncd o chrony. Elige uno. Hazlo correcto. Mónitóralo. Los mayores incidentes de sincronización que he tratado no fueron causados por el “demonio equivocado”; fueron causados por ambigüedad y negligencia.
Patrón A: Servidores/VM estándar — usa chrony, mantenlo aburrido
Chrony suele ser la elección correcta para servidores y runners de CI porque maneja la “vida real”: conectividad intermitente, VMs que se pausan, nodos que arrancan desde snapshots y redes que a veces bloquean UDP por diversión.
Instalar y habilitar chrony (si no está ya)
cr0x@server:~$ sudo apt update
...output...
cr0x@server:~$ sudo apt install -y chrony
...output...
cr0x@server:~$ sudo systemctl enable --now chrony
...output...
Punto de decisión: Si ya tenías timesyncd activo, desactívalo para evitar bucles de disciplina enfrentados.
cr0x@server:~$ sudo systemctl disable --now systemd-timesyncd
Removed "/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service".
Configurar fuentes sensatas
Editar /etc/chrony/chrony.conf. En redes corporativas, apunta a servidores NTP internos (idealmente redundantes). En entornos más pequeños, usa los defaults del pool de Ubuntu o el servicio de tiempo de tu proveedor. Lo clave es redundancia y alcanzabilidad.
Ejemplo (no copies nombres a ciegas; usa tus servidores reales):
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
Lo que importa:
iburstacelera la sincronización inicial tras el arranque.makestep 1.0 3permite hacer step (saltar) el reloj si el offset es > 1s durante las primeras 3 actualizaciones. Bueno para el arranque; peligroso si lo ves después.
Consejo con opinión: mantén makestep habilitado para el arranque temprano. Los nodos de CI que arrancan con un reloj malo gastarán más dinero que lo que cuesta permitir un step.
Reiniciar y verificar
cr0x@server:~$ sudo systemctl restart chrony
...output...
cr0x@server:~$ chronyc sources -v
...output...
cr0x@server:~$ chronyc tracking
...output...
Punto de decisión: Quieres una fuente seleccionada (*), un registro de reach distinto de cero (no 0) y un estrato sensato (típicamente 2–4 en empresas). Si no tienes ninguna: sigue siendo red/DNS/firewall.
Patrón B: Escritorios minimalistas o appliances — timesyncd es suficiente
Systemd-timesyncd hace el trabajo para muchos sistemas no críticos. Pero es fácil superarlo y arrepentirse de no usar chrony. Si mantienes timesyncd, al menos fija una lista fiable de servidores.
Editar /etc/systemd/timesyncd.conf y establecer servidores explícitos si tu red bloquea pools públicos.
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...
Punto de decisión: Si timesyncd no puede alcanzar servidores, fallará silenciosamente hasta que algo más chille (como tu pipeline). Si necesitas diagnósticos y resiliencia más fuertes, cambia a chrony.
Patrón C: Invitados VM — no luches con el hipervisor, pero no confíes ciegamente
La deriva de tiempo en VM es común. El invitado puede estar correcto pero también puede ser pausado, restaurado desde snapshot, migrado o estrangulado. Todos esos son eventos de tiempo.
Guía práctica:
- Siempre ejecuta un servicio de sincronización en el invitado. Incluso si el hipervisor “ayuda”, quieres que el invitado se discipline a sí mismo.
- Alinea la estrategia host/guest. Si tu hipervisor inyecta tiempo y tu invitado también hace pasos agresivos, puedes provocar oscilación.
- Vigila eventos de step en tiempo de actividad. Eso normalmente no es “deriva normal”; es un evento de plataforma.
Si observas step mientras la VM corre normalmente, busca sobreasignación del host o steal de CPU. Eso es un problema de SRE disfrazado de problema de tiempo.
Patrón D: Contenedores — no puedes arreglar el tiempo del host desde dentro
Los contenedores usan el kernel del host. Si un contenedor de build dice “clock skew detected”, el tiempo del host está mal o el workspace está montado desde algún lugar con timestamps malos. Puedes instalar chrony dentro de un contenedor y sentirte productivo, pero no disciplinará el reloj del host a menos que hagas maniobras privilegiadas—lo cual es otro tipo de incidente.
Arregla el nodo. O arregla el sistema de archivos que provee los mtimes.
Patrón E: CI/CD — limpia artefactos tras corregir el tiempo
Una vez arreglado el tiempo, aún tienes artefactos envenenados: archivos generados con timestamps futuros, cachés con metadata y grafos incrementales de compilación que ahora mienten. La acción correcta suele ser:
- Limpiar workspace (
git clean -xfden un runner desechable; más cuidado en hosts persistentes). - Invalidar cachés que almacenan mtimes (cachés de compilador, caches de lenguaje, caches de artefactos).
- Reconstruir desde cero una vez para resetear la cadena de dependencias.
Broma #2: La sincronización de tiempo es como cepillarse los dientes—lo saltas una semana y de repente todo es caro y todo el mundo está molesto.
Tres micro-historias corporativas (anonimizadas, plausibles y técnicamente dolorosas)
Mini-historia 1 — El incidente causado por una suposición errónea
La empresa tenía una nueva imagen runner Ubuntu 24.04 para CI. Estaba “endurecida”, así que el UDP saliente estaba bloqueado por defecto. La suposición: “No ejecutamos servicios que necesiten UDP.” Esa frase suena ordenada en una hoja de cálculo y se vuelve fea en producción.
En horas, las compilaciones empezaron a fallar con make: warning: Clock skew detected. Mientras tanto, otro equipo reportó errores intermitentes de “certificate not valid yet” al tirar de un registro interno. Los síntomas parecían no relacionados. La causa compartida fue la deriva del tiempo: los runners arrancaban con el reloj algunos minutos desajustado y luego derivaban más porque NTP no podía alcanzar nada.
La revisión del incidente fue arqueología corporativa clásica. Seguridad había impuesto el bloqueo UDP. Plataforma había cambiado de timesyncd a chrony por “más precisión” sin validar las reglas de egreso. CI sufría las fallas pero no tenía responsabilidad sobre la política de red. Los dashboards mostraban CPU y memoria; la sincronización de tiempo no tenía monitorización.
La solución fue poco romántica: permitir egress UDP/123 desde los runners hacia los NTP internos, añadir una segunda fuente NTP y alertar cuando timedatectl reporte unsynchronized por más de unos minutos tras el arranque. El mayor cambio fue cultural: dejaron de asumir “UDP solo es para cosas heredadas raras”. NTP no es raro. Es una base.
Mini-historia 2 — La optimización que salió mal
Un equipo de infra quería despliegues más rápidos. Habilitaron escalado agresivo con snapshots para agentes de build: restaurar snapshot de VM, ejecutar build, descartar. Redujo el tiempo de aprovisionamiento dramáticamente—hasta la primera vez que el snapshot se tomó con el reloj ligeramente mal y las guest tools estaban pausadas.
Las VMs restauradas tenían offsets de tiempo que variaban desde segundos hasta minutos. A veces chrony lo corregía rápido. A veces hacía step hacia atrás en medio de una compilación, justo cuando el sistema de build generaba cabeceras. Los artefactos resultantes tenían timestamps incoherentes y las compilaciones empezaron a fallar esporádicamente. “Esporádicamente” es la palabra que envejece a los ingenieros.
El primer intento de solución del equipo fue deshabilitar el stepping porque “el stepping rompe builds”. Eso mejoró algunos fallos y empeoró otros. Sin stepping, algunas VMs permanecían desfasadas lo suficiente como para que TLS y la lógica de expiración de tokens fallaran, y las pulls del registro se volvieron inestables.
La solución real fue tratar los snapshots como no seguros respecto al tiempo a menos que diseñes para ello: asegurar que el snapshot se tome después de que la sincronización de tiempo esté estable, forzar una sincronización al arrancar y considerar descartar directorios de build cache que sobrevivieron al snapshot. También introdujeron una puerta de salud: si la VM no estaba sincronizada dentro de una ventana corta, se terminaba y reemplazaba. No es elegante. Es fiable. La fiabilidad vence a la elegancia en producción.
Mini-historia 3 — La práctica aburrida pero correcta que salvó el día
Otra organización tenía una regla: cada nodo tiene dos fuentes de tiempo independientes (appliances internas stratum-1 y un servicio de tiempo del proveedor), y cada clúster alerta si algún nodo está desincronizado por más de 10 minutos. Nadie amaba esa regla. Era “solo más ruido de monitorización” hasta que dejó de serlo.
Un martes, un cambio en el firewall corporativo bloqueó el acceso a los appliances NTP primarios desde una subred nueva. La mayoría de equipos no notó inmediatamente porque las cosas “funcionaban la mayor parte del tiempo”. Pero la monitorización sí lo hizo. Saltaron alertas: nodos estaban cayendo al secundario y mostrando mayor jitter.
Porque tenían redundancia, nada perceptible por el usuario se rompió. Los despliegues continuaron. Las compilaciones continuaron. TLS siguió feliz. El equipo tuvo tiempo para arreglar el firewall en horario laboral en vez de durante una interrupción.
Esto es lo que suena aburrido en un informe y glorioso a las 3 a.m.: la práctica correcta no era sofisticada. Era redundancia y alertas sobre el estado de sincronización. Les salvó de un incidente donde no puedes confiar en logs, tokens o certificados. Eso es un “incidente de toda la compañía”, no una “pequeña caída”.
Errores comunes: síntoma → causa raíz → solución
1) Síntoma: “Clock skew detected” durante make, especialmente en CI
Causa raíz: el tiempo del sistema se adelantó o retrocedió, o el workspace de build contiene archivos creados cuando la hora estaba mal (mtimes futuros).
Solución: estabiliza primero la sincronización de tiempo; luego limpia el workspace y recompila. No intentes “touch” solo algunos archivos y esperar que funcione. Usa ls -l --full-time para encontrar timestamps futuros y luego borra los outputs.
2) Síntoma: “Release file is not valid yet” de apt
Causa raíz: el reloj del nodo está adelantado respecto a las marcas temporales del repositorio.
Solución: arregla NTP; no fijes metadata vieja del repositorio como parche. Tras la sincronización, vuelve a ejecutar apt update.
3) Síntoma: errores TLS “certificate is not yet valid” o comportamiento raro de expiración de tokens
Causa raíz: offset de reloj (a menudo minutos) en cliente o servidor; a veces causado por restauración de VM o NTP bloqueado.
Solución: verifica que ambos extremos estén sincronizados. Arregla la alcanzabilidad de NTP. Para flotas, alerta sobre el estado de sincronización y el offset.
4) Síntoma: chrony corriendo pero nunca se sincroniza (stratum 0, reach 0)
Causa raíz: servidores NTP inalcanzables, fallos DNS, UDP/123 bloqueado o direcciones de servidor incorrectas.
Solución: valida resolución y path de red; añade fuentes redundantes; asegúrate de no apuntar a una dirección que solo funciona en otra VLAN.
5) Síntoma: el tiempo “salta” decenas de segundos durante la actividad
Causa raíz: pausa/restore de VM, restauración de snapshot, sobrecarga del host o stepping de chrony debido a un offset grande descubierto tarde.
Solución: investiga eventos de plataforma; ajusta makestep para permitir stepping solo en arranque; asegura que guest tools y NTP del host estén configurados sensatamente.
6) Síntoma: logs fuera de orden, trazas distribuidas incoherentes
Causa raíz: algunos nodos tienen skew; otros no. Tu stack de observabilidad registra mentiras fielmente.
Solución: aplica sincronización de tiempo en toda la flota; considera rechazar nodos que fallen las comprobaciones de salud de tiempo (especialmente workers de Kubernetes).
7) Síntoma: solo fallan builds en workspace respaldado por NFS con advertencias de skew
Causa raíz: desajuste hora servidor/cliente o semántica de timestamps del sistema de archivos, especialmente cuando el servidor NFS no está sincronizado.
Solución: sincroniza la hora del servidor NFS; mueve workspaces a local; asegúrate de que la infraestructura NFS forme parte del dominio de monitorización de sincronización de tiempo.
8) Síntoma: dos demonios de tiempo peleando (offset oscilante, eventos frecuentes de “stepped”)
Causa raíz: ambos timesyncd y chrony (u otras herramientas) intentando disciplinar el reloj.
Solución: elige un demonio. Desactiva el otro. Verifica estabilidad tras el cambio.
Listas de verificación / plan paso a paso
Checklist A — Respuesta de emergencia cuando compilaciones/despliegues fallan
- Confirma que la desincronía es real: ejecuta
timedatectly registra el estado de sincronización. - Identifica el demonio de tiempo:
systemctl status chrony systemd-timesyncd. - Revisa salud de fuentes de tiempo:
chronyc trackingychronyc sources -v(otimedatectl timesync-status). - Arregla la alcanzabilidad: valida DNS y la política de red para UDP/123.
- Forzar estabilización: reinicia el servicio de tiempo tras arreglar red/DNS.
- Verificar sincronía estable: synchronized = yes, existe fuente NTP seleccionada, offset bajo.
- Limpia outputs contaminados: borra workspace/directorios de build y recompila limpio una vez.
- Reintenta despliegue: si hubo fallos TLS/tokens, reintenta tras la corrección del tiempo.
Checklist B — Endurecer una flota para que no vuelva
- Estandarizar: elige chrony (recomendado para servidores/CI) o timesyncd (minimal), no ambos.
- Redundancia: configura al menos dos fuentes NTP en rutas de infraestructura diferentes.
- Monitorización: alerta sobre estado unsynchronized y offsets grandes. No esperes a que make te lo diga.
- Alineación de plataforma: asegúrate de que hipervisores y hosts bare metal también sincronicen tiempo; los invitados no pueden compensar para siempre.
- Higiene CI: trata las correcciones de tiempo como eventos de invalidación de caché; purga caches de artefactos cuando ocurra skew.
- Control de cambios: los cambios en firewall y DNS deberían incluir “¿sigue funcionando NTP?” como prueba.
- Migas de incidentes: guarda logs de eventos de step y cambios de fuente NTP para líneas de tiempo forenses.
Checklist C — Cuando sospechas deriva de tiempo en VM/plataforma
- Busca en logs “System clock was stepped”.
- Correlaciona con eventos del ciclo de vida de la VM (restore de snapshot, migración, pause/resume).
- Revisa clocksource y mensajes del kernel si la deriva es extrema.
- Valida la sincronización del host; un host malo crea invitados malos.
- Usa chrony y restringe el stepping al arranque salvo que tengas una razón fuerte.
Preguntas frecuentes
1) ¿Por qué aparece “clock skew detected” en make?
make se basa en los tiempos de modificación del sistema de archivos para decidir qué necesita recompilarse. Si una dependencia parece más reciente de lo que debería—o más reciente que “ahora”—te advierte porque no puede razonar confiablemente sobre el grafo de compilación.
2) Arreglé NTP, pero make sigue avisando. ¿Por qué?
Porque aún tienes archivos con timestamps futuros creados durante el período de tiempo malo. Arregla el tiempo primero, luego limpia outputs y recompila. Las compilaciones incrementales tras un evento de skew no son confiables a menos que sanitices los mtimes.
3) ¿Debería usar chrony o systemd-timesyncd en Ubuntu 24.04?
Para servidores, runners CI y cualquier cosa que deba recuperarse de redes imperfectas o rarezas de VM: chrony. Para escritorios simples o appliances minimalistas: timesyncd puede ser suficiente. La elección equivocada es ejecutar ambos.
4) ¿Puedo simplemente ajustar la hora con date y listo?
Puedes, pero es una cura temporal. Si la máquina no puede alcanzar NTP o sigue derivando por problemas de plataforma, volverá a fallar. Además: cambios manuales de hora en caliente pueden interrumpir TLS, caches y logs.
5) ¿Qué diferencia hay entre stepping y slewing?
Stepping salta el reloj a la hora correcta rápidamente. Slewing ajusta gradualmente. El stepping puede romper cargas sensibles a timestamps; el slewing puede dejarte mal por más tiempo. makestep de chrony ofrece un compromiso sensato: hacer step solo temprano en el arranque cuando ya estás en un estado frágil.
6) ¿La configuración de zona horaria causa errores de clock skew?
La mala configuración de zona horaria normalmente causa confusión humana, no skew. El tiempo del sistema (UTC internamente) puede seguir siendo correcto. Pero si ves discordancias RTC/localtime, puede indicar provisión descuidada. Mantén servidores en UTC. Siempre.
7) ¿Por qué los contenedores muestran errores de clock skew si no pueden ajustar la hora?
Porque heredan el tiempo del kernel del host. Si un contenedor de build se queja, arregla la sincronización del host o los timestamps del sistema de archivos montado. Instalar NTP dentro de un contenedor no privilegiado es en su mayoría teatro.
8) ¿Cuánto offset es “demasiado” para CI y despliegues?
Subsegundos es normal. Algunos segundos pueden romper sistemas estrictos (ciertos tokens, flujos de firma). Minutos romperán TLS y gestión de paquetes. Si ves decenas de segundos, trátalo como un defecto de producción.
9) Bloqueamos UDP por todas partes. ¿Podemos sincronizar sin UDP/123?
NTP clásico usa UDP/123. Algunos entornos usan métodos alternativos de distribución de tiempo internamente, pero la verdad operativa sigue siendo: debes permitir el protocolo de tiempo que elegiste. Si lo bloqueas, tus sistemas finalmente inventarán su propia línea temporal.
10) ¿Debería sincronizar también el reloj de hardware (RTC)?
En bare metal: sí, una vez que la hora del sistema sea correcta y estable, escríbela con hwclock --systohc. En VMs: ten precaución; el comportamiento del RTC depende del hipervisor y la integración del invitado.
Próximos pasos que deberías tomar
Si estás arreglando una falla activa: haz que la sincronización de tiempo funcione primero, luego elimina artefactos de compilación contaminados. No negocies con mtimes envenenadas. No mejoran con esperanza.
Para una solución duradera en Ubuntu 24.04:
- Estandariza en un servicio de tiempo (chrony es la opción pragmática para servidores y CI).
- Configura fuentes NTP redundantes que tu red realmente permita.
- Alerta sobre estado unsynchronized y sobre eventos de step de tiempo.
- Audita prácticas de ciclo de vida de VM (snapshots, restores, migraciones) por su impacto en el tiempo.
- Tras cualquier incidente de skew, limpia builds y cachés una vez para resetear el mundo.
La moraleja es aburrida, y por eso sabes que es correcta: el tiempo fiable es una dependencia como DNS y almacenamiento. No “lo configuras y te olvidas”. Lo ejecutas, lo monitorizas y lo mantienes aburrido.