제품에 사용되는 NTP 클라이언트를 모르고 시스템 시간이 NTP 서버에 동기화되었는지 확인하는 방법은 무엇입니까? 컨테이너 또는 독립 실행형 시스템 모두에서 실행될 것으로 예상되는 애플리케이션을 개발 중입니다. 내 응용 프로그램에는 특정 작업을 수행하기 전에 시스템 시간이 동기화되었는지 확인해야 하는 요구 사항이 있습니다. 그러나 NTP/chrony 패키지의 가용성은 호스트 OS에서 하나 또는 다른 NTP 클라이언트가 사용되더라도 컨테이너에서 사용 가능하다고 보장할 수 없습니다.
그렇다면 시스템 시간이 동기화되었는지 여부를 알 수 있는 통일된 방법을 찾고 있습니까?
답변1
범용 컴퓨팅의 애플리케이션은 실행 중인 호스트에서 시간 동기화가 작동하는 방식을 모든 경우에 알 수 없습니다. 컨테이너에서는 호스트에서 실행 중인 chronyd 또는 ntpd를 볼 수 없고 연결할 수 없지만 시간은 잘 유지됩니다. 또는 호스트 시간 동기화에 의존하는 VM 게스트도 표시되지 않습니다. 일반적인 대답을 더욱 어렵게 만드는 것은 생각보다 NTP 구현이 더 많다는 것입니다: chrony, ntp, ntpsec, openntpd, w32tm.
정확한 시간의 중요성을 문서화하는 것만으로도 충분할 때가 많습니다.
일부 플랫폼에서는 ntpd 시작에 대한 종속성을 만드는 것이 비교적 간단합니다. RHEL에서는시간 동기화를 기다려 systemctl enable chrony-wait
시스템 장치에 추가하십시오.
After=time-sync.target
Requires=time-sync.target
그러나 엄격한 시간 요구 사항을 적용하는 애플리케이션이 있습니다. 제가 생각할 수 있는 가장 까다로운 것은 타임 스탬프 권한입니다.청구 표준 중 하나가 1초 미만의 상쇄를 요구하거나 아무 것도 발행될 수 없는 경우. 이러한 공격적인 응답은 애플리케이션이 자체 시간 확인을 수행함을 의미합니다.
아마도 구성 가능한 NTP 서버에 대해 애플리케이션의 NTP 오프셋을 확인하는 SNTP 클라이언트를 번들로 묶을 수도 있습니다. 적절한 ntpd 실행을 확인할 수 없지만 호스트에 대한 시간 동기화 작동 방식에 관계없이 온전성 검사 오프셋은 가능합니다.
답변2
이를 수행하는 방법에는 두 가지가 있습니다.
실행 중인 컨테이너에 전체 시스템 구현이 있는 경우 프로그램 timedatectl
은 호스트가 동기화되었는지 여부를 알려줄 수 있습니다.
이것이 내부적으로 관리되는 방식은 systemd-timedated
데몬과 통신하는 dbus를 통해 이루어집니다. 수행 중인 작업은 시스템 호출을 수행하는 것입니다. adjtimex
이 호출에서 수행 중인 커널 조정(있는 경우)의 현재 상태를 나타내는 데이터를 다시 가져올 수 있습니다.
따라서 전체 구현 없이 이를 직접 수행하는 두 번째 방법은 adjtimex()
시스템 호출을 사용하는 것입니다.
커널은 시간 보고에서 시간 점프(또는 시간이 거꾸로 이동하는 경우)를 원하지 않습니다. 따라서 몇 시간에 걸쳐 시스템 시간을 수정하는 시간 왜곡을 구현합니다(완료됨). 조정이 완료될 때까지 초당 몇 밀리초를 추가하거나 지연하여)
시스템 adjtimex
호출은 일반적으로 NTP 시스템에서 시계가 직면하고 있는 현재 스큐를 변경하여 실제 시계 소스와 올바르게 동기화하도록 사용됩니다.하지만또한 클록 소스 왜곡의 현재 상태를 가져오는 데 사용할 수도 있습니다. 따라서 어떤 동기화가 수행되고 있는지(있는 경우) 커널 아이디어를 엿볼 수 있는 기능을 제공합니다.
매뉴얼 페이지는 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
제가 읽은 내용에 따르면 여전히 작동할 것입니다. - 그건 당신이 결정하도록 맡기겠습니다.
답변3
시스템 시간이 NTP 서버와 동기화되었는지 확인하는 방법은 무엇입니까?
없습니다.
내 애플리케이션에는 특정 작업을 수행하기 전에 시스템 시간이 동기화되었는지 확인해야 하는 요구 사항이 있습니다.
실행할 올바른 환경을 설정하는 것은 응용 프로그램의 책임이 아니며 시스템과 해당 관리자의 책임입니다.
애플리케이션은 시스템에서 반환된 날짜/시간에 의존합니다. 그 시간이 아니면"옳은"또는"잘못된"; 응용프로그램은 일반적으로 이를 알 수 있는 방법이 없습니다. 단순히 해당 시스템 날짜/시간을 사용합니다.
클라이언트-서버 모델이 있는 경우 (극단적인) 날짜/시간 오프셋으로 인해 트랜잭션이 거부될 때마다 유용한 오류 메시지를 제공하는 것이 좋습니다.
이러한 오프셋이 존재한다고 해서 클라이언트가 잘못된 시계에 있는지, 서버에 있는지, 아니면 둘 다에 있는지 알 수는 없습니다.