时钟每天快 7 秒的云主机:证书校验失败前的排查顺序

举报
逍遥渝枫 发表于 2026/11/05 09:15:57 2026/11/05
【摘要】 云主机的硬件时钟本身走得不准,一旦时间同步停摆,偏差会悄悄积累,直到某天 apt、curl、git 同时报证书错误才发现问题。本文以一台 Ubuntu 22.04 云主机为例,解释 83 ppm 漂移意味着每天快 7 秒,给出从 timedatectl 到 chronyc 的诊断顺序、常见报错对照表,以及手动步进、监控偏差的防复发做法,全部命令可直接复制执行。

接到过一个典型场景:一台云主机上午还好好的,下午跑 apt update 开始报证书错误,curl 拉镜像源也挂,git push 被拒,而这些服务前一天都正常。 SSH 登上去第一件事不是去查证书,而是看时间。证书校验的本质是把系统当前时间和证书的 notBefore / notAfter 做绝对时间比较,系统时钟只要偏离真实时间足够多,校验就必然失败——哪怕证书本身完全正常。

先搞清楚这台机器的时钟有多不准

不是所有机器的时间都一样不准。拿我这台 1.7G 内存的 Ubuntu 22.04 云主机来说,chrony 报告的频率补偿值是 83.656 ppm(fast):

timedatectl
chronyc tracking

关键输出:

System clock synchronized: yes
NTP service: active
Reference ID    : 647D01FB (100.125.1.251)
Stratum         : 4
System time     : 0.000033261 seconds fast of NTP time
Frequency       : 83.656 ppm fast

ppm 是百万分之一。83.656 ppm 意味着:如果没有时间同步在兜底,这块主机的时钟每天会走快约 7.2 秒(83.656 × 86400 ÷ 1000000 ≈ 7.2),一个月约 3.6 分钟,一年约 44 分钟。虚拟化环境里这种量级的漂移很常见,guest 看到的时钟中断本来就不如物理机均匀。

这个 83.656 不是 chrony 凭空算的,它记录在漂移文件里,代表 chrony 对这块时钟"天生走多快"的长期估计:

cat /var/lib/chrony/drift
83.654334             0.023009

chrony 正是靠持续按这个频率做微调(而不是反复大步跳时间),把 System time 压在微秒级。理解这一点很重要:正常情况下 chrony 在干活时机器不漂;出现漂移事故,几乎都是同步链路断了之后漂移开始裸奔。

诊断顺序:四步定位

遇到疑似时间问题,按下面的顺序查,每一步都有明确的分叉结论。

第一步,看同步总开关状态:

timedatectl

重点看两行:System clock synchronized: no 说明 NTP 从未成功或已失效;NTP service: inactive 说明同步服务压根没在跑。Ubuntu 22.04 上 chrony 和 systemd-timesyncd 都能提供 NTP 服务,两者只能留一个,systemctl is-active chrony systemd-timesyncd 可以确认现在是谁在管。装了 chrony 但没停用 timesyncd 的情况下,两者抢一个系统时间控制权,是"配了却不生效"的常见原因。

第二步,看 chrony 自己认为对得多准:

chronyc tracking

System time 这一行就是当前偏差。偏差在毫秒级说明一切正常;偏差到秒级以上,说明同步很久没成功了,看下一步。

第三步,看上游源通不通:

chronyc sources -v
chronyc sourcestats

正常时最优源前面是 ^*,Reach 列是 377(二进制全 1)。如果源显示 ? 且 Reach 是 0,说明 UDP 123 出方向根本出不去——云主机上第一嫌疑是安全组把出方向 UDP 123 拦了,其次是本机 ufw。华为云内网 NTP(我这台同步到的上游是 100.125.1.251)只在内网可达,主机若换了 VPC 或 DNS 配置被改,解析不到内网 NTP 也会卡死在这里。

第四步,用第三方视角验证本机时间有没有真偏差:

date -u
SITE='你的站点地址'            # 填完整地址,含协议头
curl -sI "$SITE" | grep -i '^date:'

拿本机 UTC 时间和 HTTPS 响应头里的 Date 比对(响应头只精确到秒,且含网络延迟,量级判断足够用)。两边差超过 30 秒,时钟问题实锤。

常见报错对照表

报错信息 真实原因 处理
apt:Certificate verification failed: The certificate is NOT trusted 时钟偏差过大,证书 notBefore/notAfter 校验失败 chronyc makestep 步进对时后重试
curl:SSL certificate problem: certificate is not yet valid 系统时间慢于证书生效时间 同上,先对时再排查证书本身
openssl s_client 输出 verify error:num=9:certificate is not yet valid 时间偏慢的经典信号 对时后用同一命令复验
git:SSL certificate problem: unable to get local issuer certificate 多为 CA 包问题,但时钟偏差也会以类似形式报出 先确认 date 正确,再查 ca-certificates
timedatectl 显示 NTP service: inactive chrony 未安装或服务停了 apt install chrony && systemctl enable --now chrony
chronyc sources 源为 ? 且 Reach 0 UDP 123 出方向被拦 查云安全组出方向规则与本机 ufw

这张表的用法是"先对时、再复验、后排查":绝大多数证书类报错在对时后会直接消失;对时后仍复现的,才轮到查证书链和 CA 包。

顺手说明一个容易误判的点:时钟偏慢和偏快触发的是不同分支。偏慢时撞上 notBefore,报 “certificate is not yet valid”;偏快时越过 notAfter,报 “certificate has expired”。TLS 校验里 notBefore 的检查恰恰是最容易踩的,因为你自己的证书通常早就生效了,但中途证书链上任何一个中间证书的生效时间晚于你的系统时间,链条就断了。想看完整校验过程,可以用:

SITE=你的站点域名
openssl s_client -connect "$SITE:443" -servername "$SITE" 2>&1 | grep -E 'Verify return code|verify error'

正常返回 Verify return code: 0 (ok);时钟有问题时这里会直接给出 num=9(not yet valid)或 num=10(has expired),比 curl 的报错精确得多。

修复:手动步进与配置确认

确认偏差很大后,别等 chrony 慢慢摊平(它默认对大偏差会拒绝调整),直接步进:

sudo chronyc makestep
chronyc tracking

makestep 立即把系统时间对到源时间,执行后 System time 应回到微秒级。注意:生产环境里时间倒退(从快调慢)会影响依赖单调时间的程序,能看到日志里的时间戳出现回跳,这是预期行为,不是新故障。

之后核对配置。这台机器 /etc/chrony/chrony.conf 的有效配置是:

grep -v '^#' /etc/chrony/chrony.conf | grep -v '^$'
server 100.125.1.251 minpoll 4 maxpoll 10 iburst
stratumweight 0.05
driftfile /var/lib/chrony/drift
rtcsync
makestep 10 3
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
noclientlog
logchange 0.5
logdir /var/log/chrony

两个参数值得展开:makestep 10 3 表示开机后前 3 次更新里,偏差超过 10 秒就直接步进——专治重启后时钟落后一大截的场景,这个默认配置不要删;rtcsync 让内核定期把系统时间写回硬件时钟,关机再开也不至于偏差太离谱。改过配置后 sudo systemctl restart chrony 生效。

防复发:把偏差变成可观测的数字

时间漂移最大的麻烦是它安静。等证书报错才发现,往往已经漂了很久。最小成本的做法是用 cron 每小时把偏差记一笔,超过阈值就往系统日志里写告警:

sudo tee /usr/local/bin/clock-drift-check.sh > /dev/null <<'EOF'
#!/bin/bash
# 记录并告警时钟偏差(threshold 单位秒)
THRESHOLD=1
OFFSET=$(chronyc tracking | awk '/^System time/ {for(i=1;i<=NF;i++) if($i ~ /^[0-9.]+$/){print $i; exit}}')
UNIT=$(chronyc tracking | awk '/^System time/ {print $(NF-1)}')
case "$UNIT" in
  ms) OFFSET=$(awk "BEGIN{print $OFFSET/1000}") ;;
  us) OFFSET=$(awk "BEGIN{print $OFFSET/1000000}") ;;
esac
logger -t clock-drift "offset=${OFFSET}s"
awk "BEGIN{exit !($OFFSET > $THRESHOLD)}" && \
  logger -p user.warning -t clock-drift "ALERT: clock offset ${OFFSET}s > ${THRESHOLD}s, check chronyc sources"
EOF
sudo chmod +x /usr/local/bin/clock-drift-check.sh
echo '0 * * * * root /usr/local/bin/clock-drift-check.sh' | sudo tee /etc/cron.d/clock-drift-check

之后 journalctl -t clock-drift -f 就能随时看到偏差曲线。阈值设 1 秒比较合适:正常机器偏差在微秒到毫秒级,一旦逼近 1 秒,说明同步链路已经断了几个小时以上,正是动手排查的时机——远早于证书开始报错。

边界说明

本文所有命令和配置在 Ubuntu 22.04 + chrony 4.x 上验证,chrony 3.x 参数兼容但输出格式略有差异;CentOS/RHEL 系的配置文件路径是 /etc/chrony.conf,其余结论可参考。100.125.1.251 是华为云内网 NTP 的上游地址,只在华为云内网可达,跨云环境请换对应厂商的内网源或公共 NTP。另外 chrony 与 systemd-timesyncd 只保留一个,两套并存导致的"看似在同步实际没同步"比完全没配更难发现。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。