¿Cómo comprobar si la hora del sistema está sincronizada con el servidor NTP sin conocer el cliente NTP utilizado en el producto? Estoy desarrollando una aplicación que se espera que se ejecute tanto en contenedores como en sistemas independientes. Mi aplicación tiene el requisito de garantizar que la hora del sistema esté sincronizada antes de intentar realizar determinadas operaciones. Sin embargo, no se puede garantizar que la disponibilidad del paquete NTP/chrony esté disponible en el contenedor aunque se utilice uno u otro cliente NTP en el sistema operativo host.
Entonces, estoy buscando una forma unificada de saber si la hora del sistema está sincronizada o no.
Respuesta1
Las aplicaciones de computación de propósito general no pueden saber en todos los casos cómo funciona la sincronización horaria en los hosts en los que se ejecutan. En un contenedor, no ve ni puede conectarse al chronyd o ntpd que se ejecuta en el host, pero esto mantiene el tiempo bien. O un invitado de VM que depende de la sincronización horaria del host, que tampoco es visible. Para dificultar aún más una respuesta general, hay más implementaciones de NTP de las que podría pensar: chrony, ntp, ntpsec, openntpd, w32tm.
A menudo es suficiente documentar la importancia de la hora correcta.
En algunas plataformas, depender de un inicio ntpd es relativamente sencillo. En RHEL, aespera a que se sincronice el tiempo systemctl enable chrony-wait
y agregar a su unidad systemd
After=time-sync.target
Requires=time-sync.target
Sin embargo, hay aplicaciones con requisitos de tiempo estrictos. Lo más exigente que se me ocurre son las autoridades de sellado de tiempo,uno de los cuales los estándares de reclamos requieren menos de un segundo de compensación o no se puede emitir nada. Esta respuesta tan agresiva implica que la aplicación realiza sus propias comprobaciones de tiempo.
Quizás agrupar un cliente SNTP, que verifica las compensaciones NTP en su aplicación, con servidores NTP configurables. No se puede verificar si ntpd se está ejecutando correctamente, pero puede verificar las compensaciones sin importar cómo funciona la sincronización de tiempo con el host.
Respuesta2
Hay dos maneras de hacer esto.
Si el contenedor que está ejecutando tiene una implementación systemd completa, entonces el timedatectl
programa puede informarle si el host está sincronizado o no.
La forma en que esto se gestiona internamente es a través de dbus que habla con el systemd-timedated
demonio. Lo que está haciendo es realizar una llamada al sistema: adjtimex
de la cual es posible obtener datos que indiquen el estado actual del ajuste en el kernel (si lo hay) que se está realizando.
Por lo tanto, la segunda forma de hacerlo usted mismo sin una implementación completa es mediante la adjtimex()
llamada al sistema.
El kernel no quiere tener saltos en el tiempo en sus informes de la hora (o peor, el tiempo retrocede), por lo que implementa un sesgo en la hora que en el transcurso de unas pocas horas corregiría la hora del sistema (ya está hecho). agregando o retrasando unos pocos milisegundos por segundo hasta que se complete el ajuste).
adjtimex
Los sistemas NTP suelen utilizar la llamada al sistema para cambiar la desviación actual del reloj para que se sincronice correctamente con una fuente de reloj real.peroTambién se puede utilizar para obtener el estado actual de la desviación de la fuente del reloj. Por lo tanto, le brinda la posibilidad de echar un vistazo a la idea del kernel de qué sincronización se está realizando (si se realiza alguna).
La página de manual adjtimex
proporciona un par de partes interesantes relacionadas con lo que está preguntando:
The buf.status field is a bit mask that is used to set and/or retrieve status bits associated with the NTP implementation. Some bits in the mask
are both readable and settable, while others are read-only.
...
STA_UNSYNC (read-write)
Clock unsynchronized.
y
RETURN VALUE
On success, adjtimex() and ntp_adjtime() return the clock state; that is, one of the following values:
...
TIME_ERROR The system clock is not synchronized to a reliable server. This value is returned when any of the following holds true:
* Either STA_UNSYNC or STA_CLOCKERR is set.
* STA_PPSSIGNAL is clear and either STA_PPSFREQ or STA_PPSTIME is set.
* STA_PPSTIME and STA_PPSJITTER are both set.
* STA_PPSFREQ is set and either STA_PPSWANDER or STA_PPSJITTER is set.
The symbolic name TIME_BAD is a synonym for TIME_ERROR, provided for backward compatibility.
Como tal, si no tiene un contenedor completo, aún es posible obtener estos datos. Escribí un programa simple que obtendrá el estado de los núcleos sesgados adjtimex
en C. Puedes compilarlo, por ejemplo.gcc -o timex timex.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/timex.h>
/* Written for https://serverfault.com/questions/1077601/how-to-check-whether-the-system-time-is-synchronised-to-ntp-server-without-knowi */
void test_status(
int st)
{
if (st & STA_PLL)
printf("Phase locked loop\n");
if (st & STA_PPSFREQ)
printf("Pulse per second frequency discipline\n");
if (st & STA_FLL)
printf("PPS Time discipline\n");
if (st & STA_INS)
printf("Insert leap second and end-of-day\n");
if (st & STA_DEL)
printf("Delete leap second and end-of-day\n");
if (st & STA_UNSYNC)
printf("Clock is not syncronized\n");
if (st & STA_FREQHOLD)
printf("Hold frequency\n");
if (st & STA_PPSSIGNAL)
printf("Valid PPS signal is present\n");
if (st & STA_PPSJITTER)
printf("PPS signal jitter exceeded\n");
if (st & STA_PPSWANDER)
printf("PPS Signal wander exceeded\n");
if (st & STA_PPSERROR)
printf("PPS signal calibration error\n");
if (st & STA_CLOCKERR)
printf("Clock hardware fault\n");
if (st & STA_NANO)
printf("Nanosecond resolution\n");
else
printf("Microsecond resolution\n");
if (st & STA_MODE)
printf("Frequency locked loop\n");
else
printf("Phase locked loop\n");
}
int main() {
struct timex tx = {};
tx.modes = ADJ_OFFSET_SS_READ;
int err = adjtimex(&tx);
switch(err) {
case -1:
printf("Time error: %s\n", strerror(errno));
break;
case TIME_WAIT:
printf("Leap second insert/delete completed\n");
break;
case TIME_INS:
printf("Leap second to be added next UTC day\n");
break;
case TIME_DEL:
printf("Leap second to be deleted next UTC day\n");
break;
case TIME_OOP:
printf("Leap second insertion in progress\n");
break;
case TIME_ERROR:
printf("Error getting time\n");
break;
case TIME_OK:
printf("Time OK\n");
break;
default:
printf("Time default: %x (%d)\n", err, err);
break;
}
test_status(tx.status);
exit(0);
}
Ejecutándose en un sistema que no está sincronizado:
$ ./timex
Error getting time
Clock is not syncronized
Microsecond resolution
Phase locked loop
Ejecutándose en un contenedor en el mismo host que no está sincronizado:
# podman run -v /tmp/timex/timex:/timex docker.io/gammabytehosting/rockylinux /timex
Error getting time
Clock is not syncronized
Microsecond resolution
Phase locked loop
Configuración de la hora en el sistema host a sincronizar:
# systemctl start chronyd
# chronyc sources
210 Number of sources = 9
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* _gateway 2 6 7 1 +5568ns[ -720ms] +/- 32ms
# ./timex
Time OK
Microsecond resolution
Phase locked loop
Realizando la misma verificación programática en el contenedor en el mismo host:
# podman run -v /tmp/timex/timex:/timex docker.io/gammabytehosting/rockylinux /timex
Time OK
Microsecond resolution
Phase locked loop
Potencialmente existe algún problema con los espacios de nombres de tiempo que no he probado (aunque en realidad son muy nuevos) para ver si difieren o respetan adjtimex
en un contexto separado (ver man 7 time_namespaces
), pero por lo que he leído probablemente todavía funcione. - Dejaría que tú lo determines.
Respuesta3
¿Cómo comprobar si la hora del sistema está sincronizada con un servidor NTP?
No lo hay.
Mi aplicación tiene el requisito de garantizar que la hora del sistema esté sincronizada antes de intentar realizar ciertas operaciones.
No es responsabilidad de la aplicación configurar el entorno correcto para ejecutarse, eso depende del sistema y su administrador.
Las aplicaciones se basan en la fecha/hora devuelta por el sistema. Si ese momento es"correcto"o"equivocado"; la aplicación generalmente no tiene forma de saberlo. Simplemente utilizará la fecha/hora del sistema.
Si tiene un modelo cliente-servidor, sería bueno proporcionar un mensaje de error útil cada vez que las transacciones vayan a ser rechazadas debido a compensaciones (extremas) de fecha/hora.
Tenga en cuenta que la existencia de dicha compensación no le indica si el cliente tiene un reloj incorrecto, o el servidor, o ambos.