Există două moduri de a face acest lucru.
Dacă containerul pe care îl rulați are o implementare systemd completă, atunci timedatectl
programul vă poate informa dacă gazda este sincronizată sau nu.
Modul în care acest lucru este gestionat intern este prin dbus care vorbește cu systemd-timedatat
demonul. Ceea ce face este să efectueze un apel de sistem: adjtimex
din care este posibil să se recupereze date care indică starea curentă a ajustării în nucleu (dacă există) care se face.
Prin urmare, a doua modalitate de a face acest lucru singur fără o implementare completă este utilizarea adjtimex()
apel de sistem.
Nucleul nu dorește să aibă salturi de timp în raportarea timpului (sau, mai rău, timpul călătorind înapoi), ca atare, implementează o denaturare a timpului care, în decurs de câteva ore, ar corecta timpul sistemului (s-a terminat). prin adăugarea sau întârzierea cu câteva milisecunde pe secundă până la finalizarea reglajului).
The adjtimex
Apelul de sistem este folosit de obicei de sistemele NTP pentru a modifica deformarea curentă cu care se confruntă ceasul pentru a se sincroniza corect cu o sursă de ceas adevărată -- dar poate fi folosit și pentru a prelua starea curentă a declinului sursei ceasului. Prin urmare, vă oferă posibilitatea de a arunca o privire în ideea nucleelor despre ce sincronizare se face (dacă există).
Pagina de manual pentru adjtimex
oferă câteva părți interesante care se referă la ceea ce cereți:
Câmpul buf.status este o mască de biți care este utilizată pentru a seta și/sau a prelua biții de stare asociați cu implementarea NTP. Câteva bucăți în mască
sunt atât lizibile, cât și setabile, în timp ce altele sunt doar citibile.
...
STA_UNSYNC (citire-scriere)
Ceas nesincronizat.
și
VALOARE RETURNATĂ
La succes, adjtimex() și ntp_adjtime() returnează starea ceasului; adică una dintre următoarele valori:
...
TIME_ERROR Ceasul sistemului nu este sincronizat cu un server de încredere. Această valoare este returnată atunci când oricare dintre următoarele este adevărată:
* Este setat fie STA_UNSYNC, fie STA_CLOCKERR.
* STA_PPSSIGNAL este clar și fie STA_PPSFREQ, fie STA_PPSTIME este setat.
* STA_PPSTIME și STA_PPSJITTER sunt ambele setate.
* STA_PPSFREQ este setat și fie STA_PPSWANDER, fie STA_PPSJITTER este setat.
Numele simbolic TIME_BAD este un sinonim pentru TIME_ERROR, furnizat pentru compatibilitate cu versiunea anterioară.
Ca atare, dacă nu aveți un container complet, este posibil să obțineți în continuare aceste date. Am scris un program simplu care va prelua starea kernel-urilor skew via adjtimex
în C.Îl poți compila, de exemplu gcc -o timex timex.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <șir.h>
#include <sys/timex.h>
/* Scris pentru https://serverfault.com/questions/1077601/how-to-check-whether-the-system-time-is-synchronised-to-ntp-server-without-knowi */
void test_status(
int st)
{
dacă (st și STA_PLL)
printf("Bucla blocată în fază\n");
dacă (st și STA_PPSFREQ)
printf("Disciplina de frecventa puls pe secunda\n");
dacă (st și STA_FLL)
printf("Disciplina de timp PPS\n");
dacă (st & STA_INS)
printf("Inserați secunda intercalată și sfârșitul zilei\n");
dacă (st & STA_DEL)
printf("Șterge secunda intercalată și sfârșitul zilei\n");
if (st & STA_UNSYNC)
printf("Ceasul nu este sincronizat\n");
dacă (st & STA_FREQHOLD)
printf("Frecventa de mentinere\n");
if (st & STA_PPSSIGNAL)
printf("Semnalul PPS valid este prezent\n");
if (st & STA_PPSJITTER)
printf("Titter-ul semnalului PPS a fost depășit\n");
dacă (st & STA_PPSWANDER)
printf("Winder semnal PPS depășit\n");
if (st & STA_PPSERROR)
printf("Eroare de calibrare a semnalului PPS\n");
if (st & STA_CLOCKERR)
printf("Eroare hardware ceas\n");
dacă (st & STA_NANO)
printf("Rezolutie in nanosecunde\n");
altfel
printf("Rezolutie in microsecunde\n");
dacă (st & STA_MODE)
printf("Bucla blocata de frecventa\n");
altfel
printf("Bucla blocată în fază\n");
}
int main() {
struct timex tx = {};
tx.modes = ADJ_OFFSET_SS_READ;
int err = adjtimex(&tx);
comuta(er) {
cazul 1:
printf("Eroare de timp: %s\n", strerror(errno));
pauză;
cazul TIME_WAIT:
printf("Inserarea/ștergerea secundă a fost finalizată\n");
pauză;
cazul TIME_INS:
printf("Secunda intercalată va fi adăugată următoarea zi UTC\n");
pauză;
cazul TIME_DEL:
printf("Secunda intercalată va fi ștearsă următoarea zi UTC\n");
pauză;
cazul TIME_OOP:
printf("Inserarea secunda interioara in curs\n");
pauză;
cazul TIME_ERROR:
printf("Eroare la obtinerea timpului\n");
pauză;
cazul TIME_OK:
printf("Ora OK\n");
pauză;
Mod implicit:
printf(„Ora implicită: %x (%d)\n”, err, err);
pauză;
}
stare_test(tx.status);
ieșire(0);
}
Rulează pe un sistem care nu este sincronizat:
$ ./timex
Eroare la obținerea timpului
Ceasul nu este sincronizat
Rezoluție în microsecunde
Buclă blocată în fază
Rularea într-un container pe aceeași gazdă care nu este sincronizat:
# podman run -v /tmp/timex/timex:/timex docker.io/gammabytehosting/rockylinux /timex
Eroare la obținerea timpului
Ceasul nu este sincronizat
Rezoluție în microsecunde
Buclă blocată în fază
Setarea orei în sistemul gazdă pentru sincronizare:
# systemctl start chronyd
# surse cronice
210 Număr de surse = 9
MS Nume/adresă IP Stratum Poll Reach LastRx Ultima mostră
==================================================== ==============================
^* _gateway 2 6 7 1 +5568ns[ -720ms] +/- 32ms
# ./timex
Ora OK
Rezoluție în microsecunde
Buclă blocată în fază
Efectuarea aceleiași verificări programatice în container pe aceeași gazdă:
# podman run -v /tmp/timex/timex:/timex docker.io/gammabytehosting/rockylinux /timex
Ora OK
Rezoluție în microsecunde
Buclă blocată în fază
Există potențial o problemă cu spațiile de nume de timp pe care nu le-am testat (sunt foarte noi totuși) pentru a vedea dacă diferă sau respect adjtimex
într-un context separat (vezi man 7 time_namespaces
), dar din ceea ce am citit probabil că va funcționa în continuare -- aș lăsa asta pe dvs. să determinați.