如何在不知道产品中使用的NTP客户端的情况下检查系统时间是否同步到NTP服务器?我正在开发一个在容器或独立系统中运行的应用程序。我的应用程序需要确保系统时间在尝试执行某些操作之前是同步的。但是,即使主机操作系统中使用了一个或另一个NTP客户端,也无法保证NTP/chrony包的可用性在容器中可用。
所以我在寻找一种统一的方法来知道系统时间是否是同步的?
发布于 2021-09-15 17:12:22
通用计算机上的应用程序不可能在所有情况下都知道时间同步在运行它们的主机上是如何工作的。在容器中,您看不到并且无法连接到主机上运行的chronyd或ntpd,但这会使时间保持得很好。或者依赖于主机时间同步的VM客户机,也不可见。更难回答的是,有更多的ntp实现比您想象的要多: chrony、NTP、ntpsec、openntpd、w32tm。
通常,记录正确时间的重要性就足够了。
在一些平台上,对ntpd启动的依赖是相对直接的。在RHEL上,添加到等待时间同步 systemctl enable chrony-wait
并添加到系统单元中
After=time-sync.target
Requires=time-sync.target
然而,有些应用程序有严格的时间要求。我能想到的最苛刻的是时间戳当局,其中一种索赔标准要求不到1秒的抵消量,否则什么也不能发出。。响应的这种侵略性意味着应用程序会进行自己的时间检查。
也许将一个SNTP客户端捆绑在可配置的NTP服务器上,该客户机检查应用程序中的NTP偏移量。无法检查是否有正确的ntpd运行,但无论时间同步到主机的工作方式如何,都可以检查偏移量。
发布于 2021-09-15 08:24:13
有两种方法可以做到这一点。
如果正在运行的容器具有完整的systemd实现,那么timedatectl
程序可以通知您主机是否同步。
内部管理的方式是通过dbus进行管理,dbus可以与systemd-timedated
守护进程对话。它所做的是完成一个系统调用:adjtimex
,它可以从其中获取数据,指示正在执行的内核(如果有的话)的当前调整状态。
因此,不需要完全实现的第二种方法是使用adjtimex()
系统调用。
内核不希望在报告时间(或者更糟的是,向后移动的时间)中跳转时间,因为它在这样的时间内实现了一个偏斜,在几个小时的过程中,它将纠正一个系统时间(通过添加或延迟几毫秒每秒直到调整完成)。
NTP系统通常使用adjtimex
系统来改变时钟所面临的当前偏斜,以使其与真正的时钟源正确同步--但它也可用于获取时钟源倾斜的当前状态。因此,它使您能够窥探内核的想法,什么是同步正在进行(如果有的话)。
adjtimex
的手册页面提供了一些与您所要求的内容相关的有趣部分:
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.
和
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.
因此,如果您没有一个完全成熟的容器,那么仍然有可能获得这些数据。我编写了一个简单的程序,它将通过C中的adjtimex
获取内核的状态。您可以编译它,例如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);
}
运行在不同步的系统上:
$ ./timex
Error getting time
Clock is not syncronized
Microsecond resolution
Phase locked loop
在未同步的同一主机上运行的容器中:
# podman run -v /tmp/timex/timex:/timex docker.io/gammabytehosting/rockylinux /timex
Error getting time
Clock is not syncronized
Microsecond resolution
Phase locked loop
将主机系统中要同步的时间设置为:
# 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
在同一主机上的容器中执行相同的编程检查:
# podman run -v /tmp/timex/timex:/timex docker.io/gammabytehosting/rockylinux /timex
Time OK
Microsecond resolution
Phase locked loop
时间命名空间可能存在一些问题,我还没有对它们进行测试(虽然它们确实是非常新的),看看它们在单独的上下文中是否不同或是否支持adjtimex
(请参阅man 7 time_namespaces
),但从我所读到的可能仍然有效的内容来看--让您来确定。
发布于 2021-09-15 07:20:20
如何检查系统时间是否与NTP服务器同步?
没有。
我的应用程序需要确保系统时间在尝试执行某些操作之前是同步的。
应用程序没有责任设置要运行的正确环境,这取决于系统及其管理员。
应用程序依赖于系统返回的日期/时间。无论时间是“正确的”还是“错误的”,应用程序一般都无法知道这一点。它将简单地使用该系统日期/时间。
如果您有一个客户机-服务器模型,那么每当事务由于(极端)日期/时间偏移而被拒绝时,都会提供有用的错误消息。
请注意,这种设置的存在并不能告诉您客户端是否位于不正确的时钟上,或者服务器上,或者两者都有。
https://serverfault.com/questions/1077601
复制相似问题