Есть два способа сделать это.
Если контейнер, который вы используете, имеет полную реализацию systemd, то timedatectl
программа может сообщить вам, если хост синхронизирован или нет.
Внутреннее управление осуществляется через dbus, который обращается к systemd-timedated
демон. Что он делает, так это выполняет системный вызов: adjtimex
из которого можно получить данные, указывающие на текущий статус корректировки в ядре (если таковая имеется), которая выполняется.
Следовательно, второй способ сделать это самостоятельно без полной реализации — использовать adjtimex()
системный вызов.
Ядро не хочет иметь временные скачки в своих отчетах о времени (или, что еще хуже, время перемещается назад), поэтому оно реализует перекос во времени, который в течение нескольких часов корректирует системное время (это сделано). путем добавления или задержки на несколько миллисекунд в секунду, пока настройка не будет завершена).
adjtimex
системный вызов обычно используется системами NTP для изменения текущего перекоса, с которым сталкиваются часы, чтобы заставить их правильно синхронизироваться с истинным источником часов - но его также можно использовать для получения текущего состояния перекоса источника тактового сигнала. Следовательно, это дает вам возможность заглянуть в ядро идеи о том, какая синхронизация выполняется (если есть).
справочная страница для adjtimex
предоставляет несколько интересных частей, которые относятся к тому, что вы спрашиваете:
Поле buf.status представляет собой битовую маску, которая используется для установки и/или получения битов состояния, связанных с реализацией NTP. Некоторые биты в маске
доступны как для чтения, так и для установки, в то время как другие доступны только для чтения.
...
STA_UNSYNC (чтение-запись)
Часы не синхронизированы.
и
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
В случае успеха adjtimex() и ntp_adjtime() возвращают состояние часов; то есть одно из следующих значений:
...
TIME_ERROR Системные часы не синхронизированы с надежным сервером. Это значение возвращается, когда выполняется любое из следующих условий:
* Установлен либо STA_UNSYNC, либо STA_CLOCKERR.
* STA_PPSSIGNAL сброшен, и установлено либо STA_PPSFREQ, либо STA_PPSTIME.
* Оба параметра STA_PPSTIME и STA_PPSJITTER установлены.
* Установлен STA_PPSFREQ и установлен либо STA_PPSWANDER, либо STA_PPSJITTER.
Символическое имя TIME_BAD является синонимом TIME_ERROR и предназначено для обратной совместимости.
Таким образом, если у вас нет полноценного контейнера, все равно можно получить эти данные. Я написал простую программу, которая будет получать статус перекоса ядра через adjtimex
в С.Вы можете скомпилировать его, например gcc -o timex timex.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ошибка.h>
#include <string.h>
#include <sys/timex.h>
/* Написано для https://serverfault.com/questions/1077601/how-to-check-whether-the-system-time-is-ynchronised-to-ntp-server-without-knowi */
недействительный test_status (
инт ст)
{
если (ст и STA_PLL)
printf("Цикл фазовой автоподстройки частоты\n");
если (ст и STA_PPSFREQ)
printf("Дисциплина частоты пульса в секунду\n");
если (ст и STA_FLL)
printf("Временная дисциплина PPS\n");
если (ст и STA_INS)
printf("Вставить дополнительную секунду и конец дня\n");
если (ст и STA_DEL)
printf("Удалить дополнительную секунду и конец дня\n");
если (ст и STA_UNSYNC)
printf("Часы не синхронизированы\n");
если (ст и STA_FREQHOLD)
printf("Удерживать частоту\n");
если (ст и STA_PPSSIGNAL)
printf("Имеется действительный сигнал PPS\n");
если (ст и STA_PPSJITTER)
printf("Превышено дрожание сигнала PPS\n");
если (ст и STA_PPSWANDER)
printf("Превышено отклонение сигнала PPS\n");
если (ст и STA_PPSERROR)
printf("Ошибка калибровки сигнала PPS\n");
если (ст и STA_CLOCKERR)
printf("Аппаратная ошибка часов\n");
если (ст и STA_NANO)
printf("Наносекундное разрешение\n");
еще
printf("Разрешение в микросекундах\n");
если (ст и STA_MODE)
printf("Цикл блокировки частоты\n");
еще
printf("Цикл фазовой автоподстройки частоты\n");
}
интервал основной () {
структура timex tx = {};
tx.modes = ADJ_OFFSET_SS_READ;
int ошибка = adjtimex(&tx);
переключатель (ошибка) {
Дело 1:
printf("Ошибка времени: %s\n", strerror(errno));
сломать;
случай TIME_WAIT:
printf("Вторая вставка/удаление завершена\n");
сломать;
случай TIME_INS:
printf("Високосная секунда будет добавлена на следующий день UTC\n");
сломать;
случай TIME_DEL:
printf("Високосная секунда будет удалена в следующий UTC-день\n");
сломать;
случай TIME_OOP:
printf("Выполняется вставка дополнительной секунды\n");
сломать;
случай TIME_ERROR:
printf("Ошибка получения времени\n");
сломать;
случай TIME_OK:
printf("Время в норме\n");
сломать;
По умолчанию:
printf("Время по умолчанию: %x (%d)\n", ошибка, ошибка);
сломать;
}
test_status (tx.статус);
выход (0);
}
Запуск в системе, которая не синхронизирована:
$ ./timex
Ошибка получения времени
Часы не синхронизированы
Микросекундное разрешение
Контур фазовой автоподстройки частоты
Запуск в контейнере на том же хосте, который не синхронизирован:
# podman run -v /tmp/timex/timex:/timex docker.io/gammabytehosting/rockylinux /timex
Ошибка получения времени
Часы не синхронизированы
Микросекундное разрешение
Контур фазовой автоподстройки частоты
Установка времени в хост-системе для синхронизации:
# systemctl запустить хронид
# хронические источники
210 Количество источников = 9
Имя MS/IP-адрес Stratum Poll Reach LastRx Последняя выборка
================================================== ==============================
^* _шлюз 2 6 7 1 +5568нс[-720мс] +/- 32мс
# ./таймекс
Время ОК
Микросекундное разрешение
Контур фазовой автоподстройки частоты
Выполнение той же программной проверки в контейнере на том же хосте:
# podman run -v /tmp/timex/timex:/timex docker.io/gammabytehosting/rockylinux /timex
Время ОК
Микросекундное разрешение
Контур фазовой автоподстройки частоты
Потенциально существует некоторая проблема с пространствами имен времени, которые я не тестировал (хотя они действительно очень новые), чтобы увидеть, отличаются ли они или уважают adjtimex
в отдельном контексте (см. человек 7 time_namespaces
), но из того, что я читал, он, вероятно, все еще будет работать - я оставлю это на ваше усмотрение.