Ubuntu는 sudo와 coreutils에 이어 시간 동기화 데몬도 Rust 구현으로 바꾸려 한다. 대상은 Trifecta Tech Foundation의 ntpd-rs다. Canonical은 27.04에서 ntpd-rs를 기본값으로 만드는 것을 목표로 한다. chrony, linuxptp, gpsd를 단계적으로 대체하는 계획이다. 26.10에는 ntpd-rs 1.9.0이 이미 main 컴포넌트에 들어 있다.
이 글에서는 26.10에서 chrony를 ntpd-rs로 바꾸고, NTS 설정과 상태 확인 방법을 정리한다. 실험은 26.10 클라우드 이미지를 QEMU(TCG)로 띄워 진행했다. KVM 없이 에뮬레이션한 VM이라 시간 정밀도 수치는 실제 하드웨어와 다르다.
릴리스별 패키지와 전환 계획
릴리스별 컨테이너에서 apt-cache policy로 확인한 값이다.
| 릴리스 | ntpd-rs | chrony | 기본 시간 데몬 |
|---|---|---|---|
| 24.04 LTS | 1.1.2-1 (universe) | 4.5-1ubuntu4.2 (main) | systemd-timesyncd |
| 26.04 LTS | 1.7.1-1 (universe) | 4.8-2ubuntu1 (main) | chrony |
| 26.10 | 1.9.0-0ubuntu2 (main) | 4.8-4ubuntu2 (main) | chrony |
| 27.04 (목표) | NTP, NTS, PTP 통합 바이너리 | 대체 대상 | ntpd-rs |
27.04 기본값 전환은 확정이 아니다. Canonical은 chrony와 CPU, 메모리, 동기화 정확도를 비교한 뒤 결정한다고 밝혔다. 작업 기간은 2026년 7월부터 2027년 1월까지다.
26.10의 기본 상태: chrony와 NTS
26.10의 chrony는 Ubuntu NTS 서버를 기본으로 쓴다.
$ grep -hvE '^\s*(#|$)' /etc/chrony/sources.d/ubuntu-ntp-pools.sources
pool 1.ntp.ubuntu.com iburst maxsources 1 nts prefer
pool 2.ntp.ubuntu.com iburst maxsources 1 nts prefer
pool 3.ntp.ubuntu.com iburst maxsources 1 nts prefer
pool 4.ntp.ubuntu.com iburst maxsources 1 nts prefer
pool ntp-bootstrap.ubuntu.com iburst maxsources 1 nts certset 1
$ sudo chronyc -N authdata
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
=========================================================================
1.ntp.ubuntu.com NTS 1 30 128 41 0 0 8 64
2.ntp.ubuntu.com NTS 1 30 128 40 0 0 8 64
3.ntp.ubuntu.com NTS 1 30 128 41 0 0 8 64
4.ntp.ubuntu.com NTS 1 30 128 41 0 0 8 64
ntp-bootstrap.ubuntu.com NTS 1 30 128 40 0 0 8 64
ubuntu-minimal은 chrony나 가상 패키지 time-daemon 중 하나에 의존한다. ntpd-rs는 time-daemon을 제공하므로 chrony를 대신할 수 있다.
$ apt-cache depends ubuntu-minimal | grep -A6 '|Depends: chrony'
|Depends: chrony
Depends: <time-daemon>
ntpd-rs
ntpsec
openntpd
ptpd
systemd-timesyncd
$ apt-cache show ntpd-rs | grep -E '^(Version|Provides|Conflicts|Replaces)'
Version: 1.9.0-0ubuntu2
Replaces: time-daemon
Provides: time-daemon
Conflicts: time-daemon
ntpd-rs로 전환하기
ntpd-rs를 설치하면 APT가 chrony를 자동으로 제거한다.
$ sudo apt-get install -y ntpd-rs 2>&1 | grep -E "REMOVED|NEW packages|^ [a-z]|upgraded,|Removing|Created symlink"
The following packages will be REMOVED:
chrony
The following NEW packages will be installed:
ntpd-rs
0 upgraded, 1 newly installed, 1 to remove and 5 not upgraded.
Removing chrony (4.8-4ubuntu2) ...
Created symlink '/etc/systemd/system/multi-user.target.wants/ntpd-rs.service' → '/usr/lib/systemd/system/ntpd-rs.service'.
$ systemctl is-active ntpd-rs chrony
active
inactive
패키지가 설치하는 파일과 기본 설정은 다음과 같다.
$ dpkg -L ntpd-rs | grep -E 'bin/|etc/|\.service|toml'
/etc/apparmor.d
/etc/apparmor.d/usr.bin.ntp-daemon
/etc/ntpd-rs
/etc/ntpd-rs/ntp.toml
/usr/bin/ntp-ctl
/usr/bin/ntp-daemon
/usr/lib/systemd/system/ntpd-rs.service
/usr/share/man/man5/ntp.toml.5.gz
$ grep -v '^\s*#' /etc/ntpd-rs/ntp.toml | grep .
[observability]
log-level = "info"
observation-path = "/var/run/ntpd-rs/observe"
[[source]]
mode = "pool"
address = "ntp.ubuntu.com"
count = 4
[synchronization]
single-step-panic-threshold = 1800
startup-step-panic-threshold = { forward="inf", backward = 86400 }
기본 설정은 NTS가 아닌 일반 NTP 풀이다. 그래서 전환 직후에는 chrony보다 보안 수준이 낮다.
$ grep -E 'Conflicts|Condition|Ambient|User=' /usr/lib/systemd/system/ntpd-rs.service
Conflicts=systemd-timesyncd.service ntp.service chrony.service
ConditionVirtualization=!container
User=ntpd-rs
AmbientCapabilities=CAP_SYS_TIME CAP_NET_BIND_SERVICE
유닛은 컨테이너에서 시작하지 않는다. rootless 컨테이너에서 데몬을 직접 실행해도 시계를 조정할 권한이 없어 바로 종료된다.
$ ntp-daemon -c /etc/ntpd-rs/nts.toml
2026-11-14T15:45:33.315758Z ERROR ntpd::daemon::system: Could not control clock: Insufficient permissions to interact with the clock.
ntp-ctl로 상태 확인
ntp-ctl status는 observation-path의 소켓으로 데몬 상태를 읽는다. 시작 2분 뒤의 출력이다.
$ ntp-ctl status
Synchronization status:
Dispersion: 0.000000s
Delay: 0.000000s
Stratum: 16
Sources:
ntp.ubuntu.com:123 185.125.190.57:123 (4)
Offset: +0.288039
Uncertainty: ±0.300657
Delay: ±0.266466
Poll interval: 16s
Missing polls: 0
Root dispersion: 0.000702s
Root delay: 0.006531s
Stratum: 16은 아직 동기화되지 않았다는 뜻이다. 저널에는 소스끼리 합의하지 못했다는 로그가 반복됐다.
$ sudo journalctl -u ntpd-rs -o short-monotonic | tail -1 | cut -c1-120
[ 370.655236] ntprs ntp-daemon[1162]: 2026-11-14T16:09:50.020948Z INFO ntp_proto::algorithm::kalman: No consensus on current time
$ sudo journalctl -u ntpd-rs -o cat | grep -E 'Started|Jumped|Offset:' | head -3 | cut -c1-130
Started ntpd-rs.service - Network Time Service (ntpd-rs).
2026-11-14T16:10:21.362648Z INFO ntp_proto::algorithm::kalman: Offset: 782.8251261101905+-2.3681045827284852ms, frequency: 59.681
2026-11-14T16:10:22.150634Z WARN ntp_proto::algorithm::kalman: Jumped offset by 780.457021527462ms. This may cause problems for o
서비스 시작(16:07:20)부터 첫 동기화(16:10:21)까지 약 3분 걸렸다. 그 전에는 No consensus 로그만 반복됐다. 소스별 불확실성이 ±0.3초 수준이었기 때문이다. 이 값은 TCG 에뮬레이션의 시계 흔들림에서 나온 것이다.
NTS 소스로 바꾸기
chrony와 같은 Ubuntu NTS 서버 4개를 mode = "nts"로 지정한다.
[observability]
log-level = "info"
observation-path = "/var/run/ntpd-rs/observe"
[[source]]
mode = "nts"
address = "1.ntp.ubuntu.com"
[[source]]
mode = "nts"
address = "2.ntp.ubuntu.com"
[[source]]
mode = "nts"
address = "3.ntp.ubuntu.com"
[[source]]
mode = "nts"
address = "4.ntp.ubuntu.com"
[synchronization]
single-step-panic-threshold = 1800
startup-step-panic-threshold = { forward="inf", backward = 86400 }$ ntp-ctl validate
2026-11-14T16:20:05.289280Z INFO ntpd::daemon::config: using config file at default location `"/etc/ntpd-rs/ntp.toml"`
Config looks good
$ sudo systemctl restart ntpd-rs
12분 뒤에도 동기화되지 않았다. 4개 중 2개가 NTS-KE(포트 4460)로 쿠키는 받았지만, NTP 응답을 한 번도 돌려주지 않았다.
$ ntp-ctl status | grep -E 'Stratum|NTS\]|Missing|cookies|Uncertainty'
Stratum: 16
1.ntp.ubuntu.com:4460 185.125.190.122:123 [NTS] (3)
Uncertainty: ±0.006137
Missing polls: 0
NTS cookies: 8/8 available
2.ntp.ubuntu.com:4460 185.125.190.123:123 [NTS] (4)
Uncertainty: ±0.003900
Missing polls: 0
NTS cookies: 8/8 available
3.ntp.ubuntu.com:4460 91.189.91.112:123 [NTS] (31)
Uncertainty: ±2147483648.500000
Missing polls: 8
NTS cookies: 6/8 available
4.ntp.ubuntu.com:4460 91.189.91.113:123 [NTS] (32)
Uncertainty: ±2147483648.500000
Missing polls: 8
NTS cookies: 6/8 available
ntpd-rs는 minimum-agreeing-sources의 기본값이 3이다. 응답하는 소스가 2개뿐이면 시계를 맞추지 않는다. chrony의 minsources 기본값은 1이다. 같은 VM의 chrony는 91.189.91.112, .113에도 NTS로 정상 접속했다.
NTS 소스 두 개를 더 넣어 6개로 늘렸다.
[[source]]
mode = "nts"
address = "time.cloudflare.com"
[[source]]
mode = "nts"
address = "nts.netnod.se"$ ntp-ctl status | grep -E 'Stratum|NTS\]|Missing|Uncertainty'
Stratum: 4
1.ntp.ubuntu.com:4460 185.125.190.122:123 [NTS] (5)
Uncertainty: ±0.005880
Missing polls: 0
2.ntp.ubuntu.com:4460 185.125.190.123:123 [NTS] (4)
Uncertainty: ±0.715650
Missing polls: 2
3.ntp.ubuntu.com:4460 91.189.91.112:123 [NTS] (13)
Uncertainty: ±2147483648.500000
Missing polls: 8
4.ntp.ubuntu.com:4460 91.189.91.113:123 [NTS] (14)
Uncertainty: ±2147483648.500000
Missing polls: 8
nts.netnod.se:4460 194.58.205.196:4123 [NTS] (6)
Uncertainty: ±0.003496
Missing polls: 0
time.cloudflare.com:4460 162.159.200.123:123 [NTS] (1)
Uncertainty: ±0.000735
Missing polls: 0
재시작 약 3분 30초 뒤 Stratum: 4로 동기화됐다. Netnod는 NTS-KE로 NTP 포트를 4123으로 알려 준다.
chrony와 비교
리소스 값은 같은 TCG VM에서 systemd가 기록한 값이다. 에뮬레이션 환경이라 절대값보다 크기 차이만 참고한다.
$ date -u +%T; systemctl show ntpd-rs -p ActiveEnterTimestamp -p CPUUsageNSec -p MemoryCurrent -p MemoryPeak
16:37:02
ActiveEnterTimestamp=Sat 2026-11-14 16:32:44 UTC
MemoryCurrent=3559424
MemoryPeak=4362240
CPUUsageNSec=3335499000
$ date -u +%T; systemctl show chrony -p ActiveEnterTimestamp -p CPUUsageNSec -p MemoryCurrent -p MemoryPeak
16:42:41
ActiveEnterTimestamp=Sat 2026-11-14 16:38:09 UTC
MemoryCurrent=4968448
MemoryPeak=5324800
CPUUsageNSec=1885433000
| 항목 | chrony 4.8 | ntpd-rs 1.9.0 |
|---|---|---|
| 설정 파일 | /etc/chrony/chrony.conf, sources.d/ | /etc/ntpd-rs/ntp.toml (TOML) |
| 26.10 기본 소스 | Ubuntu NTS 서버 | 일반 NTP 풀 ntp.ubuntu.com |
| 동기화 최소 소스 수 | minsources 1 | minimum-agreeing-sources 3 |
| AppArmor 프로필 | enforce | complain |
| 상태 확인 | chronyc sources, chronyc authdata | ntp-ctl status (Prometheus 형식 지원) |
| 실측 CPU 시간 | 1.89초 / 4분 32초 | 3.34초 / 4분 18초 |
| 실측 메모리 최댓값 | 5.1 MiB | 4.2 MiB |
| 미지원 기능 | – | 로컬 참조 시계(refclock), 대칭(symmetric) 모드, burst/iburst, 소스별 poll 설정 |
ntpd-rs의 CPU 시간에는 응답하지 않는 소스 2개를 반복해서 다시 만든 비용이 들어 있다. AppArmor 모드는 aa-status로 확인했다.
$ grep flags /etc/apparmor.d/usr.bin.ntp-daemon /etc/apparmor.d/usr.sbin.chronyd
/etc/apparmor.d/usr.bin.ntp-daemon:/usr/bin/ntp-daemon flags=(complain, attach_disconnected) {
/etc/apparmor.d/usr.sbin.chronyd:/usr/sbin/chronyd flags=(attach_disconnected) {
chrony로 되돌리기
chrony를 다시 설치하면 ntpd-rs가 제거된다. chrony 설정은 rc 상태로 남아 있었으므로 그대로 복원된다.
$ sudo apt-get install -y chrony 2>&1 | grep -E "REMOVED|NEW packages|^ [a-z]|upgraded,|Removing|Setting up chrony"
networkd-dispatcher
dnsutils gpsd iw | wireless-tools
The following packages will be REMOVED:
ntpd-rs
The following NEW packages will be installed:
chrony networkd-dispatcher
0 upgraded, 2 newly installed, 1 to remove and 5 not upgraded.
Removing ntpd-rs (1.9.0-0ubuntu2) ...
Setting up chrony (4.8-4ubuntu2) ...
$ dpkg -l chrony ntpd-rs | tail -2 | cut -c1-50
ii chrony 4.8-4ubuntu2 amd64 Ver
rc ntpd-rs 1.9.0-0ubuntu2 amd64 Rus
주의사항
- 전환 직후
ntp.toml을 NTS 소스로 바꿀 것. 26.10 패키지의 기본 설정은 인증 없는 NTP 풀을 쓴다. - 응답하는 소스를 3개 이상 확보할 것. 그보다 적으면 ntpd-rs는 시계를 맞추지 않는다. 소스를 늘리거나
minimum-agreeing-sources를 낮춘다. - AppArmor 프로필이 complain 모드라는 점을 고려할 것. 위반은 기록만 되고 차단되지 않는다. chrony는 enforce 모드다.
- 컨테이너에서는 ntpd-rs를 돌리지 말 것. 유닛에
ConditionVirtualization=!container가 있고, 시계 조정 권한도 없다. 시간은 호스트가 맞춘다. - refclock이나 대칭 모드를 쓰는 서버는 chrony를 유지할 것. ntpd-rs는 아직 이 기능을 지원하지 않는다.
- 되돌릴 계획이 있으면
purge하지 말 것.remove로 지워진 chrony는 설정 파일과 NTS 쿠키를 유지한다.
마무리
26.10에서 ntpd-rs로 바꾸는 작업은 패키지 하나를 설치하는 것으로 끝난다. 하지만 기본 설정, 최소 소스 수, AppArmor 모드가 chrony와 다르다. 27.04에서 기본값이 바뀌기 전에 이 차이부터 확인해 두는 것이 좋다.