Wie kann ich überprüfen, ob die Systemzeit mit dem NTP-Server synchronisiert ist, ohne den im Produkt verwendeten NTP-Client zu kennen?

Wie kann ich überprüfen, ob die Systemzeit mit dem NTP-Server synchronisiert ist, ohne den im Produkt verwendeten NTP-Client zu kennen?

Wie kann ich überprüfen, ob die Systemzeit mit dem NTP-Server synchronisiert ist, ohne den im Produkt verwendeten NTP-Client zu kennen? Ich entwickle eine Anwendung, die sowohl in Containern als auch in eigenständigen Systemen ausgeführt werden soll. Meine Anwendung muss sicherstellen, dass die Systemzeit synchronisiert ist, bevor sie versucht, bestimmte Vorgänge auszuführen. Die Verfügbarkeit des NTP/Chrony-Pakets im Container kann jedoch nicht garantiert werden, selbst wenn im Host-Betriebssystem der eine oder andere NTP-Client verwendet wird.

Ich suche also nach einer einheitlichen Möglichkeit, um herauszufinden, ob die Systemzeit synchronisiert ist oder nicht.

Antwort1

Anwendungen auf Allzweckrechnern können nicht in allen Fällen wissen, wie die Zeitsynchronisierung auf den Hosts funktioniert, auf denen sie ausgeführt werden. In einem Container sehen Sie den auf dem Host ausgeführten Chronyd oder NTPd nicht und können auch keine Verbindung zu ihm herstellen, dennoch hält dieser die Zeit einwandfrei. Oder ein VM-Gast, der auf die Host-Zeitsynchronisierung angewiesen ist, ist ebenfalls nicht sichtbar. Eine allgemeine Antwort wird dadurch erschwert, dass es mehr NTP-Implementierungen gibt, als Sie vielleicht denken: Chrony, NTP, NTPsec, OpenNTPD, W32TM.

Oftmals reicht es aus, die Wichtigkeit der richtigen Zeit zu dokumentieren.

Auf einigen Plattformen ist es relativ einfach, eine Abhängigkeit von einem ntpd-Start zu erstellen. Auf RHELwarte auf die Zeitsynchronisierung systemctl enable chrony-waitund fügen Sie es zu Ihrer systemd-Einheit hinzu

After=time-sync.target
Requires=time-sync.target

Dennoch gibt es Anwendungen mit strengen Zeitanforderungen. Die anspruchsvollsten, die mir einfallen, sind Zeitstempelbehörden,Einer von ihnen behauptet, dass die Standards einen Versatz von weniger als einer Sekunde erfordern, sonst kann nichts ausgegeben werden. Eine so aggressive Antwort setzt voraus, dass die Anwendung ihre eigenen Zeitprüfungen durchführt.

Vielleicht bündeln Sie einen SNTP-Client, der NTP-Offsets in Ihrer Anwendung mit konfigurierbaren NTP-Servern überprüft. Sie können nicht überprüfen, ob ein ordnungsgemäß ausgeführter NTP-Server vorhanden ist, können aber Offsets auf Plausibilität prüfen, unabhängig davon, wie die Zeitsynchronisierung mit dem Host funktioniert.

Antwort2

Hierfür gibt es zwei Möglichkeiten.

Wenn der von Ihnen ausgeführte Container über eine vollständige systemd-Implementierung verfügt, timedatectlkann das Programm Sie darüber informieren, ob der Host synchronisiert ist oder nicht.

Dies wird intern über dbus verwaltet, das mit dem systemd-timedatedDaemon kommuniziert. Dabei wird ein Systemaufruf ausgeführt, adjtimexvon dem aus Daten abgerufen werden können, die den aktuellen Status der Anpassung im Kernel (sofern vorhanden) angeben.

Daher besteht die zweite Möglichkeit, dies selbst ohne vollständige Implementierung zu tun, in der Verwendung des adjtimex()Systemaufrufs.

Der Kernel möchte keine Zeitsprünge in seiner Zeitberichterstattung haben (oder schlimmer noch, Zeitreisen rückwärts) und deshalb implementiert er eine Zeitabweichung, die die Systemzeit im Verlauf von ein paar Stunden korrigieren würde (dies geschieht durch Hinzufügen oder Verzögern von ein paar Millisekunden pro Sekunde, bis die Anpassung abgeschlossen ist).

Der adjtimexSystemaufruf wird typischerweise von NTP-Systemen verwendet, um die aktuelle Abweichung der Uhr zu ändern, damit sie korrekt mit einer echten Uhrquelle synchronisiert wird -AberEs kann auch verwendet werden, um den aktuellen Status der Abweichung der Taktquelle abzurufen. Daher können Sie einen Blick in die Vorstellung des Kernels werfen, welche Synchronisierung durchgeführt wird (falls überhaupt eine).

Die Manpage für adjtimexenthält einige interessante Abschnitte, die sich auf Ihre Frage beziehen:

       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.

Und

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.

Wenn Sie also keinen vollwertigen Container haben, ist es trotzdem möglich, diese Daten abzurufen. Ich habe ein einfaches Programm geschrieben, das den Status der Kernel-Skew-Überprüfung adjtimexin C abruft. Sie können es beispielsweise kompilierengcc -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);
}

Ausführung auf einem nicht synchronisierten System:

$ ./timex 
Error getting time
Clock is not syncronized
Microsecond resolution
Phase locked loop

Ausführung in einem Container auf demselben Host, der nicht synchronisiert ist:

# podman run -v /tmp/timex/timex:/timex  docker.io/gammabytehosting/rockylinux /timex
Error getting time
Clock is not syncronized
Microsecond resolution
Phase locked loop

Einstellen der Uhrzeit im zu synchronisierenden Host-System:

# 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

Durchführen der gleichen programmgesteuerten Prüfung im Container auf demselben Host:

# podman run -v /tmp/timex/timex:/timex  docker.io/gammabytehosting/rockylinux /timex
Time OK
Microsecond resolution
Phase locked loop

Es besteht möglicherweise ein Problem mit Zeitnamespaces, das ich nicht getestet habe (sie sind jedoch wirklich sehr neu), um festzustellen, ob sie sich unterscheiden oder adjtimexin einem separaten Kontext berücksichtigt werden (siehe man 7 time_namespaces), aber nach dem, was ich gelesen habe, wird es wahrscheinlich trotzdem funktionieren – das überlasse ich Ihnen.

Antwort3

Wie überprüfe ich, ob die Systemzeit mit einem NTP-Server synchronisiert ist?

Das gibt es nicht.

Meine Anwendung muss sicherstellen, dass die Systemzeit synchronisiert ist, bevor sie versucht, bestimmte Vorgänge auszuführen

Es liegt nicht in der Verantwortung der Anwendung, die richtige Ausführungsumgebung einzurichten, dies ist Aufgabe des Systems und seines Administrators.

Anwendungen sind auf das vom System zurückgegebene Datum/die Uhrzeit angewiesen. Ob diese Zeit entweder"richtig"oder"falsch"; die Anwendung kann das im Allgemeinen nicht wissen. Sie verwendet einfach das Systemdatum/die Systemzeit.

Wenn Sie ein Client-Server-Modell haben, wäre es gut, eine nützliche Fehlermeldung bereitzustellen, wenn Transaktionen aufgrund (extremer) Datums-/Zeitabweichungen abgelehnt werden.
Beachten Sie, dass die Existenz einer solchen Abweichung Ihnen nicht sagt, ob der Client, der Server oder beide eine falsche Uhr haben.

verwandte Informationen