chrony / chronyc —— NTP 时间同步
一句话定义
chrony 是现代 Linux 上最推荐的 NTP 客户端 / 服务端,比传统的 ntpd 收敛更快、网络断后恢复更快、虚拟机里更稳。chronyc 是它的命令行控制工具——tracking 看同步状态、sources 看上游服务器。
典型场景
- 装机:所有 K8s 节点装 chrony 同步时间
- 排查"节点时间漂移导致 etcd raft 抖动"
- 看时间和 NTP 服务器差多少:
chronyc tracking - 看用了哪些上游:
chronyc sources -v - 内网部署:用一两台节点做 chrony server,其它节点指向它
为什么 K8s 集群对时间敏感
K8s 几乎所有组件对时钟漂移都敏感:
| 组件 | 敏感点 |
|---|---|
| etcd raft | leader election / heartbeat 用时间,漂移 > 500ms → 频繁换 leader |
| TLS 证书 | Not Before / Not After 字段,节点时间错 → 证书"未生效"或"过期" |
| ServiceAccount token | issued-at / expiry,漂移大被 apiserver 拒 |
| HPA / metrics | 按时间窗口算 rate,漂移影响决策 |
| 日志关联 | 跨节点排错全靠时间对齐 |
集群里所有节点的时间漂移要 < 50ms。chrony 默认能做到 < 10ms。
Day0 装机必装 chrony,且和 ssh / 容器运行时同等优先级。
装
apt install -y chrony # Ubuntu / Debian
yum install -y chrony # CentOS / RHEL
装完通常默认 enabled。看:
systemctl status chrony # Ubuntu / Debian
systemctl status chronyd # CentOS / RHEL
服务名 Ubuntu 叫
chrony、CentOS 叫chronyd。
和 systemd-timesyncd 不能共存
systemd 自带一个轻量 NTP 客户端 systemd-timesyncd。装 chrony 之前必须禁掉,否则两者打架:
timedatectl set-ntp false # 关 timesyncd
systemctl disable --now systemd-timesyncd # 双保险
systemctl enable --now chrony # 起 chrony
确认只有 chrony 在跑:
timedatectl
# NTP service: active ← chrony 跑着也是 active
chronyc tracking # chrony 自己的状态
chronyc tracking —— 最常用一条命令
$ chronyc tracking
Reference ID : 1A2B3C4D (ntp.example.com)
Stratum : 3
Ref time (UTC) : Mon May 27 14:30:00 2026
System time : 0.000123456 seconds slow of NTP time
Last offset : +0.000234567 seconds
RMS offset : 0.000345678 seconds
Frequency : 1.234 ppm slow
Residual freq : +0.000 ppm
Skew : 0.123 ppm
Root delay : 0.012345 seconds
Root dispersion : 0.000567 seconds
Update interval : 64.1 seconds
Leap status : Normal
最关键三行:
System time—— 本机和 NTP 服务器的差距。< 10ms 是好的、> 100ms 要查Stratum—— 离权威时间源几跳。1 = 直接连原子钟,2 = 连 stratum 1,3 = 连 stratum 2,... 16 = 没同步Leap status—— Normal / Insert / Delete / Not synchronised
如果 Leap status: Not synchronised 或 Stratum: 16 —— chrony 没成功同步上任何 NTP 服务器,问题在上游 / 网络。
chronyc sources —— 看上游
$ 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
===============================================================================
^* time1.google.com 1 6 377 23 -123us[-145us] +/- 12ms
^+ time2.google.com 1 6 377 21 -156us[-178us] +/- 15ms
^- time.cloudflare.com 3 6 377 25 +234us[+212us] +/- 20ms
读法(第二列字符是状态):
| 字符 | 含义 |
|---|---|
* | 当前选用的主源 |
+ | 候选源(被组合用) |
- | 未被组合 |
x | 可能有错(被踢出) |
~ | 抖动太大 |
? | 不可达 |
健康的 chrony 应该至少有一个 ^*。
Reach 是过去 8 次轮询的成功记录(八进制):
377= 二进制 11111111 = 全成功377之外的(376374)= 最近有失败0= 完全连不上
chrony 配置文件 /etc/chrony/chrony.conf
主要内容(精简版):
# 上游 NTP 服务器
pool 2.pool.ntp.org iburst maxsources 4
server time.google.com iburst
server time.cloudflare.com iburst
# 数据存储
driftfile /var/lib/chrony/drift
# 大幅校正容忍(启动后 3 次校正,差距 ≤ 1 秒)
makestep 1.0 3
# 允许的 ntp 客户端(如果本机做 server)
# allow 10.0.0.0/8
# 同步状态写入硬件时钟
rtcsync
# 最大日志
logdir /var/log/chrony
关键指令
| 指令 | 作用 |
|---|---|
server <host> | 单个 NTP server |
pool <host> | 用 DNS 拿一组 server(DNS 返回多 IP) |
iburst | 启动时连续 4 个快速包,加速首次同步 |
maxsources N | 一个 pool 最多用几个 server |
makestep <threshold> <limit> | 启动后允许的大幅跳变 |
driftfile <path> | 存储时钟频率偏移 |
allow <network> | 允许哪些客户端用本机做 NTP server |
rtcsync | 把同步状态写硬件时钟 |
local stratum 10 | 即使没上游也对外充当 stratum 10 |
改完 systemctl restart chrony。
内网 NTP 部署(生产推荐)
集群有 5 个节点,但出口到外网慢 / 不稳。做法:1-2 个节点当 NTP server,其它节点同步它。
Server 节点(如 m1)
# /etc/chrony/chrony.conf
# 用公网作上游
pool 2.pool.ntp.org iburst
server time.google.com iburst
# 允许 m2-m5 用我做 NTP server
allow 10.0.24.0/24
# 即使我没同步上公网,也对内提供时间(stratum 10)
local stratum 10
Client 节点(m2-m5)
# /etc/chrony/chrony.conf
# 只用 m1 / m2 做上游(不直连公网)
server 10.0.24.28 iburst # m1
server 10.0.24.29 iburst # m2
makestep 1.0 3
rtcsync
好处:
- 节点之间时间高度一致(即使公网 NTP 不稳)
- 出网流量小
- m1 / m2 单点 → 用两个互为备份
常用命令速查
# 看同步状态
chronyc tracking
chronyc sources
chronyc sources -v
# 看活动统计
chronyc activity
# 200 sources online (synced)
# 0 sources offline
# 0 sources doing burst (return to online)
# 0 sources doing burst (return to offline)
# 0 sources with unknown address
# 强制立刻校时(不等下次轮询)
chronyc makestep
# 或者:
chronyc -a makestep
# 看 server / client 端的连接
chronyc clients # 连我的客户端
chronyc serverstats # server 统计
# 重启 / reload
systemctl restart chrony # 改完配置重启
chronyc reload sources # 重新读 sources(部分场景免重启)
# 看日志
journalctl -u chrony -f
排查"chrony 显示没同步"
1. 看状态
chronyc tracking
# Leap status : Not synchronised ← 没同步
# Stratum : 16 ← 没上游
2. 看上游可达性
chronyc sources -v
# Reach LastRx
# 0 - ← 完全不可达
3. 测网络
# UDP 123 端口能不能通
nc -zvu time.google.com 123 # UDP
# 或者
chronyc -a 'burst 4/4' # 强制连续 4 次探测
chronyc -a 'online' # 标记上游可用(如果之前 offline)
4. 看 firewall
# UDP 123 出向被防火墙挡了?
iptables -L OUTPUT -n -v | grep udp
ip route get time.google.com
云上有些 VPC 只放行 TCP,UDP 出网被挡 → NTP 不通。
5. DNS
dig +short time.google.com
# 没结果 → DNS 不通,先修 DNS
实战:Day0 chrony 标准配置
ssh root@$ip 'bash -s' <<'EOF'
# 1. 装
apt install -y chrony
# 2. 关 timesyncd
timedatectl set-ntp false 2>/dev/null || true
systemctl disable --now systemd-timesyncd 2>/dev/null || true
# 3. 改配置 —— 用 google / cloudflare(国外)或者 aliyun(国内)
cat > /etc/chrony/chrony.conf <<'CONF'
# 上游
pool ntp.aliyun.com iburst maxsources 4
server time.google.com iburst
server time.cloudflare.com iburst
# 配置
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
logdir /var/log/chrony
CONF
# 4. 启动
systemctl enable --now chrony
# 5. 等几秒后看状态
sleep 5
chronyc tracking
chronyc sources -v
EOF
常见踩坑
坑 1:chrony 和 timesyncd 同时跑
systemctl status chrony # active
systemctl status systemd-timesyncd # active
# 两个 NTP 客户端打架
systemctl disable --now systemd-timesyncd
坑 2:iburst 之后还是慢
iburst 启动时快 4 次包让首次同步 < 10 秒。但如果 chrony 不接受大跳变就会拒:
chrony[1234]: System clock wrong by 12345 seconds, ignored
修:makestep 1.0 3 —— 启动后 3 次允许任意大小校正。
坑 3:NTP 端口(UDP 123)被云挡
chronyc sources -v
# Reach 0
UDP 出向不通。两种选择:
- 联系云厂商打开 UDP 123
- 用云厂商提供的 NTP 服务(AWS 169.254.169.123、阿里云 ntp.aliyun.com、腾讯云 ntp.tencent.com)
# /etc/chrony/chrony.conf
server ntp.aliyun.com iburst # 阿里云
# 或
server 169.254.169.123 iburst # AWS Time Sync Service
坑 4:虚拟机时间漂移
KVM / Hyper-V 虚拟机时钟容易漂。chrony 比 ntpd 处理虚拟化更好。
VMware 用户加:
# /etc/chrony/chrony.conf
maxupdateskew 100.0
容忍更大的频率漂移。
坑 5:容器里 chrony 不工作
docker run -d chrony
# 容器里 chrony 改不了宿主时间
K8s pod 默认没 CAP_SYS_TIME,改不了时钟。容器里不应该跑 NTP——容器跟节点共享时钟。
→ 在节点上跑 chrony,容器自然获得正确时间。
坑 6:chronyc makestep 没权限
$ chronyc makestep
501 Not authorised
chrony 默认只接受 unix socket 上的本地命令、且要 root:
sudo chronyc makestep # OK
sudo chronyc -a 'makestep' # -a 用 socket(默认)
或者改 chrony.conf:
cmdallow 127.0.0.1
坑 7:忘了 systemctl enable
systemctl start chrony
# 重启之后 chrony 没自启
systemctl enable --now chrony
坑 8:用 date -s 手动改时间
date -s "2026-05-27 10:00:00"
# chrony 监测到大跳变可能拒后续校正
不要手动 set 时间。让 chrony 处理。需要应急:
chronyc -a makestep
坑 9:硬件时钟(RTC)走本地时间
timedatectl
# RTC in local TZ: yes
双系统(Windows)会让 RTC 走本地时间。修:
timedatectl set-local-rtc 0 # RTC 走 UTC
否则每次重启系统时间偏几小时。
ntp / ntpd / systemd-timesyncd 对照
| 工具 | 状态 | 推荐场景 |
|---|---|---|
| chrony | 现役主流 | 所有生产 |
| ntpd | 老 / 仍可用 | 老系统迁移过来的存量 |
| systemd-timesyncd | 简单 / 内置 | 桌面机、小型测试 |
| openntpd | OpenBSD 系 | 极少 |
K8s 集群一律用 chrony。
关联命令
- hostnamectl / timedatectl —— 时区设置
- systemctl ——
systemctl status chrony - journalctl ——
journalctl -u chrony -f date—— 看当前时间(不要用date -s改)hwclock—— 看硬件时钟- etcdctl —— etcd 是 chrony 漂移的最大受害者