La foret rouge

Linux/Windows 시간 동기화

Published on
Published on
Revised on

최근에 NTP 서버 대개체 작업을 진행했습니다. 기존 NTP 서버는 RHEL7 + ntpd로 구성되어 있었는데, RHEL7이 EOL되었기 때문에 이를 RHEL9 + chronyd로 교체하였습니다. 시간 동기화는 인증이나 로깅 등 시스템 운영 전반에 걸쳐 중요한 서비스이기 때문에 작업을 준비하면서 이것 저것 많이 찾아보고, 테스트도 선행했습니다. 이 내용을 정리하여 공유합니다.

시간 동기화 서비스

Linux: chrony

Red Hat 기준으로 6 이하에서는 ntpd가 사용되었고, 7부터는 chrony가 지원되며 8 이상은 chrony가 기본적으로 설치되어 있습니다. 이 글에서는 Rocky Linux 9 버전에서 chrony를 기준으로 사용법을 설명합니다.

서비스 확인

> dnf list --installed | grep chrony
chrony.x86_64   4.6.1-1.el9     @baseos
# 설치 안 되어 있으면 `dnf install chrony` 실행

> systemctl status chronyd
● chronyd.service - NTP client/server
     Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; preset: enabled)
     Active: active (running) since Thu 2025-08-28 20:57:45 KST; 2 days ago
       Docs: man:chronyd(8)
             man:chrony.conf(5)
   Main PID: 819 (chronyd)
      Tasks: 1 (limit: 100412)
     Memory: 1.1M
        CPU: 272ms
     CGroup: /system.slice/chronyd.service
             └─819 /usr/sbin/chronyd -F 2
# active, enabled 상태가 아니면 `systemctl enable chronyd`, `systemctl start chronyd` 실행
# ⚠️ 여기에서는 명령어가 chrony가 아니라 chronyd (daemon)

시간 서버 지정하여 동기화

클라이언트로 사용할 때는 시간 동기화 서버를 지정하는 것 외에 특별히 설정을 바꿔줄 것이 없는 것 같습니다.

시간 동기화 서버 지정은 pool 또는 server 설정으로 가능합니다. 사용가능한 서버는 다음과 같습니다. (2025.08.31 확인)

  • Rocky 9.6 버전 기본: pool 2.rocky.pool.ntp.org iburst
  • NTP Pool Project에 등록된 서버 사용
  • server ntp2.kornet.net iburst (KT)
  • server time.bora.net iburst (LG U+)
> vi /etc/chrony.conf
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (https://www.pool.ntp.org/join.html).
#pool 2.rocky.pool.ntp.org iburst
server ntp2.kornet.net iburst
server time.bora.net iburst

# ...

> systemctl restart chronyd
> chronyc sources -v

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
^+ time.bora.net                 2   6     7     1   +390us[  +40us] +/-   46ms
^* 220.73.142.66                 2   6     7     1    -53us[ -403us] +/- 8061us
  • 설정 파일에 원하는 시간 동기화 서버를 추가하고 서비스 재시작을 하면 지정한 시간 서버와 동기화를 시도합니다. chronyc sources만 해도 동기화 상태를 볼 수 있고, -v 옵션을 붙이면 위 예시와 같이 설명까지 볼 수 있습니다. 예시에서는 ntp2.kornet.net과 동기화가 더 잘 되어 이 서버가 최선의 동기화 상대로 선택된 것을 볼 수 있습니다.

  • 위에서 시간 서버를 지정할 때 iburst를 붙였는데, 이 옵션은 서비스가 시작할 때 짧은 시간에 4개 이상의 요청을 보내 첫 시간 동기화를 빠르게 하기 위한 옵션입니다1. 이 옵션을 설정하지 않았다면 첫 동기화도 주기에 맞춰 진행되므로 오래 기다려야 합니다.

  • burst를 첫 시간 동기화 뿐만 아니라 일회성으로도 실행할 수 있습니다. 이 때는 chronyc burst 2/10 처럼 사용합니다. 2번 이상 응답 성공이 오지 않으면 10번까지 요청을 보내보는 것입니다.

  • 그리고 만약 시간 동기화를 즉시 하고싶다면 chronyc makestep 명령어를 사용합니다. 현재 시간 오차를 기준으로 다시 오차 줄이기를 시작합니다. 다만, chrony의 동작 알고리즘상 오차를 조금씩 점진적으로 줄이는 방식으로 맞춰나가기 때문에 시간이 조금 걸립니다.

Windows: W32Time

Windows Server에서는 W32Time이라는 서비스가 있습니다. 이 서비스는 도메인에 속한 서버들이 도메인 컨트롤러와 시간을 동기화할 때 사용되는 서비스입니다. 도메인에 join되지 않은 윈도우 서버는 기본적으로 time.windows.com과 동기화 하도록 되어 있습니다2.

서비스 확인

w32time 서비스 시간 동기화 확인은 w32tm /query /status 명령어를 사용합니다. 이 예시에서는 서비스가 시작되어 있지 않은 상태입니다. 서비스를 실행하고 시간 동기화를 확인해봅시다.

서비스 실행은 서비스(services.msc)에서 GUI로 해도 되고, 명령어로 해도 됩니다. 저는 명령어로 시스템 실행 시 자동 시작 옵션을 추가하고 서비스를 시작했습니다.

  • sc config w32time start=auto
  • net start w32time

시간 서버 지정하여 동기화

윈도우 서버는 기본적으로 time.windows.com과 동기화 하도록 되어 있습니다. 이를 명령어로 리눅스 예시처럼 time.bora.net, ntp2.kornet.net과 시간 동기화를 하도록 만들 수 있습니다.

  • w32tm /config /manualpeerlist:"time.bora.net ntp2.kornet.net" /syncfromflags:manual /update
  • 확인: w32tm /dumpreg /subkey:Parameters 또는 reg query HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Parameters /v NtpServer

이제 새 시간 동기화 서버와 동기화가 되도록 해봅시다. W32Time 서비스를 재시작해도 되고, 단순히 resync만 해도 됩니다.

  • net stop w32time net start w32time
  • w32tm /resync
  • w32tm /query /status /verbose
  • w32tm /query /peers

내부망 NTP 서버 구축

외부 서버와의 통신은 길게는 수백ms에서 나쁘게는 초 단위까지 걸릴 수도 있지만, 내부 네트워크 간 통신은 수 ms이면 충분합니다. 때문에 이렇게 구성하면 내부 서버들 간의 시간 오차를 조금 더 줄일 수 있을 것입니다.

이 그림과 같이 내 Homelab 환경의 VM 또는 사내망 서버들을 위에서 소개한 외부 시간 서버가 아닌 내부망 시간 서버와 동기화하도록 설정해봅시다. 테스트 환경에서 내부 시간 서버는 Rocky Linux 9 버전과 chrony를 사용합니다.

내부 시간 서버 셋업

기본적으로는 이 글 상단의 Linux: chrony 내용을 바탕으로 설치 및 실행 확인을 합니다.

그리고 설정을 조금 다르게 해줍니다.

> vi /etc/chrony.conf
server time.bora.net iburst
server ntp2.kornet.net iburst
# ...
allow 192.168.100.0/24
# ...

다른 설정은 기본값으로 두고, server는 위에서 했던 것처럼 time.bora.netntp2.kornet.net을 사용했습니다. 추가로, allow 192.168.100.0/24 설정을 해줍니다. 해당 IP 대역에서는 이 서버로 시간 동기화를 허용합니다. (IP 대역은 현재 사용 중인 공유기의 내부망 대역을 사용하면 됩니다. 제 내부망 IP와는 다를 수 있습니다.)

그리고 방화벽을 사용한다면 다른 서버들이 이 시간 서버와 NTP 프로토콜로 시간 동기화를 할 수 있도록 포트를 허용해줍니다.

> firewall-cmd --add-port=123/udp --permanent
> firewall-cmd --reload

내부망 클라이언트 서버 설정 변경

이제 내부망 서버들은 외부 시간 서버가 아니라 방금 설정한 내부 시간 서버를 보도록 설정을 변경해줍니다. 그리고 chrony를 재시작해주어야 적용됩니다.

> vi /etc/chrony.conf
server 192.168.100.XXX iburst

> systemctl restart chrony

> chronyc sources

클라이언트 연결 확인

ntpd와는 달리 chrony에서는 연결된(시간 동기화를 하는) 클라이언트 목록을 명령어로 볼 수 있습니다.

> chronyc clients
Hostname                 NTP   Drop Int IntL Last     Cmd   Drop Int  Last
===========================================================================
192.168.100.113         3672      0   8   -   102       0      0   -     -
192.168.100.10            29      0   8   -    9d       0      0   -     -
utils-prd-lr-vm01          0      0   -   -     -       5      0   2    8d
192.168.100.121            4      0   1   -   50h       0      0   -     -
# ...

서버 교체 후 특이사항이 없다면 모든 클라이언트들이 붙을 때까지는 이 목록이 점점 증가할 것입니다. 저는 서버 교체 직후에는 chronyc clients | wc -l 명령어로 연결되는 서버 수량이 증가하는 것을 보고 문제가 없다고 판단했습니다. 그 후에는 동기화 주기가 매우 긴 서버가 있을 수도 있기 때문에 cron으로 2시간마다 명령어를 실행하도록 등록하고, 하루 정도 유지하여 한 번 더 확인했습니다.

Q&A

  1. ntpd, chrony, w32time이 섞여서 사용되어도 문제 없나요?
    • 세 서비스 모두 NTP 프로토콜을 사용하기 때문에 기본적인 시간 동기화에는 문제가 없습니다.
    • 다만, 리눅스에서는 ntpd와 chronyd는 둘 다 123/udp 포트를 사용하므로 반드시 둘 중 하나만 실행해야 합니다.
  2. 시간 서버를 교체하는 동안 시간 동기화가 끊어지지는 않나요?
    • 시간 동기화는 주기적으로 수행됩니다. 주기는 chrony 기본값 기준으로 6, 10으로 설정되어 있는데 이는 최소 262^6초(64초)로 시작하여 시간 동기화가 안정적으로 수행되는 경우에는 주기를 2102^{10}초(약 17분)까지 늘린다는 뜻입니다3. 그러므로 교체 중에 동기화에 실패하는 서버는 전체 서버 중 일부일 것이고, 실패하더라도 다음 주기에 다시 동기화를 시도할 것입니다.
    • 동기화에 한 번 실패한다 하여 시간 동기화가 극도로 틀어지지는 않는 것 같습니다. 제 테스트 환경 Proxmox에 있는 CentOS 7 VM에서 네트워크를 10일 정도 끊어뒀는데 10초 정도 차이가 나고 있었습니다. 환경마다 차이가 있을테니 이 수치가 절대적이지는 않겠지만, 동기화가 안 된다고 1일만에 수 분이 틀어지지는 않을 것 같다고 생각합니다.
  3. AD(Active Directory)에 Join 된 서버들은 시간 동기화가 어떻게 동작하나요?
    • AD Joined 서버들은 기본적으로 AD Controller와 동기화 합니다. NTP Type이 NTP가 아니라 NT5DS로 되어 있는지 확인 필요합니다. AD Controller만 외부 시간 서버와 동기화 해주면 됩니다.

Footnotes

  1. Richard Curnow, et al. "chrony.conf(5) Manual Page." chrony-project. https://chrony-project.org/doc/3.4/chrony.conf.html (accessed Aug. 31, 2025).

  2. "How the Windows Time Service works." Microsoft Learn. https://learn.microsoft.com/en-us/windows-server/networking/windows-time-service/how-the-windows-time-service-works (accessed Sep. 1, 2025).

  3. "How to change the NTP polling interval?" Red Hat Customer Portal. https://access.redhat.com/solutions/39194 (accessed Sep. 27, 2025).