☰
无外网环境搭建内网时间源:Chrony离线部署与配置全指南
2026/9/30 7:54:19 网站建设 项目流程

最近帮一家200人规模的企业做内网整理时,遇到了一个典型的“无安装包”场景:公司防火墙策略把服务器到公网的通道卡得很死,软件源完全不可用,但整个办公网的时钟同步问题已经不能再拖了——AD域控里Kerberos时间差告警刷了一屏,监控回放和考勤记录对不上,几台服务器各自漂移,最离谱的一台已经慢了快四十分钟。在这个前提下,我把Chrony时钟同步这套配置从离线取包、装包、配置到全网验证完整走了一遍,最后用一台低配虚拟机构建了内网时间源,把全网时间偏差稳定收敛到毫秒级。

这篇文章就把这套方案的每个关键环节拆开来讲:为什么选Chrony而不是老牌ntpd,无安装包环境下安装包到底从哪里来,chrony.conf里每行参数在定义什么,以及实际部署里那些不跑一遍根本发现不了的坑。内容适合正在做中小型办公网络改造、被“没网、没包、时间乱”困扰的运维同行参考,也适合刚接触时间同步、想搞清楚原理再动手的新人。

1. 200人企业为什么必须把时钟同步当成基础设施

先把这个容易被低估的问题说透:200人规模的办公网,看起来不大,但对时间同步的依赖一点不比大厂少。而且正因为规模小,往往没人认真管,问题反而更隐蔽。

1.1 时间不同步到底会坏什么事

先说域环境。只要是Windows域环境,客户端和域控之间的时间偏差一旦超过默认的Kerberos时钟偏移阈值(通常5分钟),就会报KDC认证失败,用户明明密码没错却登不进域内电脑。更微妙的是,即便没触发硬性阈值,几百毫秒级别的偏差也会让Kerberos票据的有效期计算偏离,出现各种偶发的“间歇性认证失败”。我见过最典型的案例,就是一家公司一两百台机器里总有零星几台隔一段时间就登不进域,IT排查了很久,最后发现是这些机器时间漂了,大家才想起来NTP这回事。

再看运维基础设施。日志审计和故障排查高度依赖统一时间戳:安全事件发生时,如果防火墙日志、服务器日志、终端日志各差几分钟,还原攻击路径基本靠猜。备份系统如果时间不一致,计划窗口可能和业务高峰期撞在一起。定时任务依赖系统时间触发,时间错了,凌晨的批处理可能提前或滞后,连锁影响数据同步。监控系统也一样——监控端和被监控主机的时差一旦超过阈值,报警判定就会错位,该告的不告、不该告的乱告。

终端侧容易被忽略的是门禁、考勤、监控这些IoT设备。很多考勤机没有NTP客户端,只有简单时钟,需要定期人工校准;监控录像如果和门禁记录时间对不上,事后查证基本没法用。这类型设备通常不算“IT资产”,恰恰是出了事最麻烦、也最容易被指责的地方。

1.2 200人规模的特殊性:不上不下的档位

大型企业有条件做独立的时间源集群,甚至采购北斗/GPS授时设备;几十人的小公司可能靠路由器或者某台常开的电脑凑合。200人的办公网正好卡在中间——时间同步已经成了刚需,但又不能把这件事做成一个需要专门团队运维的大项目。

我的经验是,这个规模做到“一台到两台低配虚拟机做时间源+全网统一指向”就够了,重点不在规模而在收敛速度和稳定性。所以下面所有设计都围绕一个原则:用最小代价,把全网时间偏差稳定收进几十毫秒以内。这也是我常说的一句话:200人企业做网络部署,设备的配置方案一定要为“可维护”服务,而不是为“看起来很高级”服务。

1.3 为什么选Chrony而不是老NTP

传统的时间同步工具是ntpd/ntpdate,但放到今天的场景里,我优先用Chrony,理由比较实在:

  • Chrony是RHEL/CentOS 7开始内置的默认NTP实现,也是Ubuntu 18.04之后的默认方案,系统层面支持最充分;
  • 比ntpd轻量,收敛速度明显更快,尤其适合虚拟机、容器这类漂移率不稳定的环境;
  • 时钟调整策略更灵活:既能快速同步,也能在业务敏感的服务器上做平滑渐变而非突然跳变;
  • chronyc这个命令行工具的设计比ntpq直观,看状态、手动触发调整都更顺手。

换句话说,选Chrony不是因为它“新”,而是因为它能解决老NTP在虚拟化和现代工作负载里表现不佳的问题。哪怕在无安装包的环境里需要多花点心思把包找到,也值得。

2. 没有外网也没有安装包,Chrony从哪来

这一节是不少同行卡住的地方。系统里没有可用的yum/apt源,也没有现成的安装包,怎么把Chrony装上去?我梳理了四条可行路径,按推荐程度排序。

2.1 最优先:从系统安装ISO里找

一个容易忽略的事实:主流Linux发行版的安装ISO里本来就带chrony的rpm包。服务器装系统用的还是当初那版ISO的话,这就是最可靠的离线包来源,版本和系统完全匹配,依赖处理起来也最简单。

操作流程如下(以RHEL/CentOS系为例):

mkdir -p /mnt/iso mount -o loop /data/iso/CentOS-7-x86_64-Minimal-2009.iso /mnt/iso find /mnt/iso -iname 'chrony*.rpm'

找到rpm后复制出来,直接安装:

rpm -ivh chrony-*.rpm

如果提示依赖缺失(常见的有libedit、libcap这类基础库),同样在ISO的Packages目录里找对应rpm一起装。注意有些发行版ISO内部会区分BaseOS和AppStream等仓库目录(比如RHEL 8/9),chrony可能放在AppStream里,依赖在BaseOS里,两个目录都要翻。

一个关键原则:版本必须匹配系统大版本。el7的chrony包不能装到el8机器上,反之也不行。判断系统版本用cat /etc/os-release,对照着找同一大版本的ISO。如果手头没有现成的ISO,从公司软件档案库或者之前装机的归档里调一份出来就行——这本身就是“无安装包”场景下最该有的企业级习惯。

2.2 备选:在可联网的同版本机器上拉包

如果手边有一台能联网、且发行版版本与离线目标机一致的机器,用yumdownloader可以把chrony及其全部依赖一次拉下来,再拷贝进去。这个方法在中央仓库里没有所需包时很实用。

联网机器上执行:

yum install -y yum-utils mkdir -p /tmp/chrony_pkgs yumdownloader --resolve --destdir=/tmp/chrony_pkgs chrony

--resolve参数会把需要的依赖一起下载,省去手动逐个找依赖的麻烦。之后打包:

tar czf /tmp/chrony_pkgs.tar.gz /tmp/chrony_pkgs

把压缩包传到内网机器,解压后:

rpm -ivh *.rpm

重复的rpm不会重复安装,缺依赖会直接报错,按报错名继续找即可。

有一点必须提醒:拉包用的联网机器在拉完包后,建议立即把临时repo配置撤掉,不要留着一条通向外网的yum源,避免安全风险。如果公司安全要求严格,最好在一个独立的一次性容器或快照环境里执行,不要碰生产环境。

2.3 Debian/Ubuntu系的deb包获取

Debian/Ubuntu环境的离线安装逻辑类似,但稍有差异。在联网机器上可以这样做:

apt-get update mkdir -p /tmp/chrony_debs cd /tmp/chrony_debs apt-get download chrony

依赖获取比rpm繁琐一些,更实用的方法是直接在一台联网机器上执行:

apt-get install -y --download-only chrony ls /var/cache/apt/archives/*.deb

把deb拷贝进离线机器后:

dpkg -i chrony*.deb

依赖确实缺失时,从系统ISO镜像的pool目录里找对应deb,路径一般是pool/main/下面按字母排序的目录。

2.4 源码编译:能不用就别用

理论上也可以拿chrony源码包到目标机器上编译安装,但我不推荐,原因不是技术难度,而是后续维护成本。源码编译需要工具链和一堆库,编译出来的版本没有进入系统的软件包管理数据库,以后升级、卸载、查依赖都是灾难;systemd服务文件和/var/lib/chrony目录权限还得自己手工处理。除非目标机器架构特殊、实在找不到任何现成包,否则优先走前面三条路。

下表把四种方式做个横向对比,方便按自己场景选择:

获取方式适用场景依赖处理推荐度
系统安装ISO内的rpm手头有和目标机版本匹配的系统镜像依赖也大多在ISO里,较容易最推荐
联网同版本机器 yumdownloader有一台可临时联网的同版本机器--resolve自动带全依赖很推荐
apt download / 缓存目录Debian/Ubuntu系列依赖从pool或apt缓存找常用
源码编译架构特殊,无任何现成包手工处理,最折腾不推荐

3. chrony.conf逐行拆解:每一行参数都是在定义“怎么对表”

安装好之后,真正决定时间同步成败的是配置。我这里把chrony.conf里和企业场景最相关的几个参数逐行讲清楚,不光是给配置,更重要的是说明为什么要这么配。

3.1 server与pool:上游源怎么选、怎么写

配置NTP源的基本语法是:

server ntp.aliyun.com iburst server ntp.tencent.com iburst

如果上游域名背后有多台服务器,也可以用pool:

pool ntp.aliyun.com iburst

企业内网实践里,server和pool的差别不大,关键点是:

  • 服务端向外网同步时,至少写2~3个上游源,单点源不可靠;
  • 客户端向内网自建源同步时,直接写IP,别写域名——离线内网DNS经常不完整,域名解析失败就等于没有源;
  • iburst一定要加。它让首次同步时连续发送8个NTP包,几秒钟内就能完成初步对齐;不带iburst时首次同步可能要几十秒甚至几分钟。

minpoll和maxpoll控制轮询间隔:默认minpoll 6(64秒)、maxpoll 10(约1024秒,即17分钟)。对200人企业来说这个节奏足够了,不建议把maxpoll增大去追求“省流量”——内网带宽根本不缺这点NTP报文,反而会拖慢发现源异常的速度。

3.2 driftfile和makestep:两个容易被忽略的“时钟性格”参数

driftfile记录本机时钟的频率漂移值:

driftfile /var/lib/chrony/drift

作用在于:服务器重启后,chrony可以带着之前的漂移数据直接启动,不用再从零学习一遍本地时钟的“体质”,收敛速度快很多。前提是/var/lib/chrony目录对chrony用户可写——这一点在排错部分还会再提。

makestep是最值得理解透彻的参数。它决定当本机时间和源偏差较大时,是“大步跳一下”(step)还是“慢慢调过去”(slew):

makestep 1 3

含义是:在前3次时钟更新中,只要偏差超过1秒,就允许直接大步跳表;超过3次之后,偏差即使超过阈值也只会用slew渐变的方式慢慢修正。为什么默认要限制次数?因为大步跳表对运行中的业务有影响——数据库事务的时间戳会突然前移或后退,定时任务可能被跳过或重复执行,所以生产系统宁可慢慢收敛,也不希望频繁跳变。

实际部署中常碰到的情况是:一台老服务器已经几个月没同步,时间偏差几十分钟甚至更大。默认的makestep 1 3里,“前3次更新”的机会可能早已耗尽,时间就会一直走渐变,看起来永远在收敛但收敛速度极慢。这时候两个处理办法:

chronyc makestep

手动触发一次大步调整;或者临时把配置改成makestep 1 -1(允许无限次大步跳)后重启chrony,等时间基本对齐再改回默认。这个“先大步拉齐、再渐进微调”的顺序,处理存量设备时几乎可以说是标准动作。

3.3 local stratum与allow/deny:无外网环境靠它撑起权威

这是无安装包、无外网场景里最关键的配置:

local stratum 10

意思很直白:这台chrony即使同步不到任何上游,也对外宣告自己是第10层时间源。stratum是层次标识,0是原子钟,1是与原子钟直连的服务器,数字越大离权威越远,15是无效。为什么需要这一行?因为纯内网环境下服务端永远联系不到公网NTP源,如果不用local,客户端请求它时会发现源不可用,自然拒绝同步。

设成stratum 10是为了给客户端一个“可用但不高傲”的身份:用它同步可以,但如果有更上游的源,客户端会优先选stratum更小的。如果服务端将来打通了外网能正常同步到公网源,它会以真实的较低stratum对外服务,local并不会覆盖真实层数;但我依然建议打通外网后重新审视配置,把local去掉或调高,避免兜底源意外成为主源。

配合网段授权:

allow 192.168.0.0/16 deny 192.168.113.0/24

allow声明允许哪些网段来请求本机时间服务,deny在allow之前可以精确排除某个子网。不写allow的网段默认拒绝。企业里我建议再加一行:

bindaddress 192.168.0.10

让chronyd只监听内网IP。多网卡服务器上这行能防止NTP服务意外暴露到管理网或公网——别小看它,不少安全扫描发现的问题就是服务监听范围太广。

客户端比较简单,指向内网源:

server 192.168.0.10 iburst

3.4 一套可以直接抄的配置文件模板

服务端(内网时间源,双网卡或纯内网均可):

# 上游公网NTP源,有外网权限才保留 server ntp.aliyun.com iburst server ntp.tencent.com iburst # 纯离线环境没有上游,就用下面这行撑起权威 local stratum 10 # 漂移记录文件 driftfile /var/lib/chrony/drift # 前3次更新中偏差超过1秒允许大步跳 makestep 1 3 # 授权内网网段 allow 192.168.0.0/16 # 只监听内网IP bindaddress 192.168.0.10

客户端(办公终端/服务器):

# 指向内网时间源,写IP不要写域名 server 192.168.0.10 iburst server 192.168.0.11 iburst # 客户端不需要local stratum driftfile /var/lib/chrony/drift makestep 1 3

如果服务端完全没有外网权限,就把最上面两个server行注释掉,只保留local stratum 10和allow。这样一台权威时间源就算立起来了。

4. 从服务端到200台终端的落地上手操作

理论说完了,这一节是真正动手的过程。我从部署拓扑、服务端操作、客户端配置、批量验证四个环节讲,覆盖200人企业网络部署方案最常见的完整链路。

4.1 最简部署拓扑:一主一备加全网指向

200人规模不建议搞复杂的NTP集群。我的推荐是两台低配虚拟机:

  • 主源:2核2G,从公网NTP源同步(有外网权限时),对内提供服务;
  • 备源:配置基本一致,local stratum设成11(比主源高一层),主源不可用时客户端自动切到它。

为什么备源stratum要设成11?客户端同时面对两个源时,会优先选择stratum更小的那一个,所以11能让主源优先被选中;主源挂掉后10层不可达,客户端才会转向11。这个优先级机制不需要额外软件,纯靠配置就实现了。

能力方面完全不用担心:Chrony单机处理NTP请求的能力以每秒千次为单位,200台终端每17分钟同步一次,流量几乎可以忽略。真正要关注的是配置正确性和链路可用性。

4.2 服务端操作:四步搭起来

第一步是安装(见第二节,不再重复)。

第二步编辑配置,参考3.4的服务端模板。如果目标机器时间偏差本身就很大(比如慢了几十分钟),建议先在配置里临时让makestep允许大步跳,或者启动后手动执行chronyc makestep。

第三步启动服务。注意服务名的发行版差异:

# RHEL/CentOS 7/8/9 systemctl enable --now chronyd # Debian/Ubuntu systemctl enable --now chrony

顺手确认端口监听:

ss -ulnp | grep 123

输出里看到chronyd/chrony监听123端口,服务就绪。

第四步验证。最常用的两个命令:

chronyc sources -v chronyc tracking

chronyc sources -v输出中,^*表示当前锁定且正在使用的源,^+表示可用的候选源,^-表示被排除的源,^?表示源不可达。chronyc tracking里的关键字段有:System time(系统时钟相对源的偏差)、RMS offset(均方根偏差值)、Last offset(最近一次调整值)。企业环境下,等系统运行十几分钟后RMS offset稳定在个位数到几十毫秒,时间同步就基本达标了。

物理服务器记得把时间写回硬件时钟,防止断电后RTC继续漂移:

hwclock --systohc

虚拟化平台环境这一步通常不需要,虚拟机的RTC由宿主机统一管理。

4.3 客户端配置:Linux和Windows一个都不能少

Linux终端/服务器的配置最简单,安装chrony后(离线场景参考第二节),在/etc/chrony.conf里写:

server 192.168.0.10 iburst server 192.168.0.11 iburst

然后enable服务即可。有一点容易忽略:域内Windows终端其实不需要手动配置NTP,它们自动跟随域控的时间服务;需要手工配置的是不在域里的Windows设备、物理服务器和各类Linux主机。

Windows设备用系统自带的w32tm:

w32tm /config /manualpeerlist:"192.168.0.10,192.168.0.11" /syncfromflags:manual /reliable:yes /update Restart-Service w32time w32tm /resync w32tm /query /status

没有域环境的纯办公网,可以用这条命令配合批处理推下去。如果公司用了AD域,建议把域控时间同步到内网chrony源,让域内机器全部通过域控间接对齐,避免域控和终端各自指向不同的源,造成二次漂移。

4.4 批量验证:别只看服务端,要跑完200台

服务端sources输出正常只能证明服务端本身在工作,不能证明终端都指对了。200台设备逐台手动看显然不现实,我习惯用一个简单的脚本批量探查。前提是目标Linux终端装了chrony客户端,或者用ntpdate做一次查询:

#!/bin/bash TARGET=192.168.0.10 SUBNET="192.168.0. 192.168.10. 192.168.20." for ip in ${SUBNET[@]}; do for host in $(seq 1 254); do addr="${ip}${host}" if ping -c1 -W1 $addr &>/dev/null; then result=$(timeout 5 chronyc -h $TARGET -n sources 2>/dev/null | grep -E '^\^\*' || echo "no-sync") echo "$addr -> $result" fi done done

这个脚本只是演示批量探查的思路,实际跑的时候按公司子网和终端数量调整即可。更规范的做法是用Ansible等配置管理工具批量下发chrony.conf并启动服务,一次操作200台不是问题。工具选型上,200人规模用Ansible都算轻量方案,关键是避免手动一台台改的脏活。

5. 实际部署中踩过的坑:防火墙、SELinux、虚拟机时间覆盖

最后这部分是我认为本文最有价值的地方——配置照抄大家都行,但很多问题只有在真实环境里跑过才会知道。我按踩坑频率从高到低讲。

5.1 防火墙是“同不同步”最大的分水岭

现象:配置写了allow,服务也起来了,但客户端chronyc sources时一直显示^?,停留在不可达状态。

排查链路:先在服务端看123端口是否在监听(ss -ulnp | grep 123),再确认防火墙策略(firewall-cmd --list-all)。RHEL系默认firewalld只放行ssh,UDP 123没放行,外面自然访问不到。

解决:

firewall-cmd --permanent --add-service=ntp firewall-cmd --reload

ntp这个预定义服务对应的就是UDP 123。如果是在云环境,云安全组也要放行UDP 123;办公网内部的话,上级防火墙一般不限制出方向UDP 123,但服务端入方向必须放行。

千万不要为了调试方便直接systemctl stop firewalld或者把123端口对全网段开放——小企业环境安全审计一样会盯这个,正规做法是只放行内网网段。

5.2 SELinux标签问题:restorecon能救一半

现象:rpm正常装完,systemctl start chronyd却失败,journalctl -u chronyd看到permission denied,指向/var/lib/chrony目录。

原因:SELinux Enforcing模式下,chronyd对/var/lib/chrony目录的上下文有要求。如果这个目录是后来手动创建的,或者rpm安装时没有正确设置标签,就会出权限问题。

解决:

restorecon -Rv /var/lib/chrony /var/log/chrony systemctl restart chronyd

这条命令我每次部署时都会先执行一遍,成本极低,能省掉不少莫名其妙的启动失败排查时间。

5.3 服务名不一致和ntpd残留:两个经典混乱源

RHEL系服务名是chronyd,Debian/Ubuntu是chrony。写文档、做脚本时如果混用,部署就会挂。我的习惯是部署脚本里先判断发行版,再决定服务名。

另一个大坑是系统里残留的ntpd/ntpdate服务。老机器上可能还装过传统的ntpd,它和chrony抢同一个UDP 123端口,两个一起启就会有一个起不来。还有ntpdate服务或cron里的ntpdate定时任务,会不定期把时钟强制拉到某台源上去,把chrony的渐变调整逻辑完全打乱。

处理办法:

systemctl disable --now ntpd ntpdate ss -ulnp | grep 123

确保123端口只被chrony占用。

5.4 虚拟机时间同步覆盖:配置再对也白搭

现象:chrony配置一切正常,也能连上源,但是虚拟机时间每隔一段时间就跳一下,或者长期偏慢,chrony日志里频繁出现step事件。

原因:VMware Tools默认的Time Sync功能会定期把宿主机时间同步给客户机,这个动作是直接修改客户机系统时间,完全绕过chrony。如果宿主机时间本身有漂移,客户机就会被反复带偏。

解决:

vmware-toolbox-cmd timesync disable

在ESXi虚拟机配置里把“Time Synchronization”的勾选去掉。这个坑在物理机验证时完全不存在,一旦迁移到虚拟化环境就冒出来,很多同行排查了半天找不到原因,最后发现是宿主机在“捣乱”。Hyper-V、KVM/QEMU也有类似的机制,部署到这些平台时同样要检查。

5.5 大偏差存量设备的makestep策略

现象:一台老服务器从没被纳管过,时间慢了半小时。配置好chrony指向内网源之后,tracking显示offset确实在一点点变小,但收敛速度极慢,看起来永远追不上。

原因:默认makestep 1 3对“前三次更新”的限制已经耗尽,之后时间只会走slew渐变方式微调。对半小时的偏差来说,slew的收敛速度可能是每分钟几毫秒级别,等于要跑很久才能对齐。

解决:直接手动步进:

chronyc makestep

这条命令会立刻把本机时间调整到与源一致,风险是业务可能看到一次时间跳变。对已经乱了几十分钟的机器来说,这次跳变是完全值得的。处理完大偏差后,把配置恢复成makestep 1 3,让日常运行走渐变即可。

这件事给我的教训是:处理“历史欠账”时间偏差大的机器,第一反应应该是先手动makestep拉齐,再让Chrony做后续微调,而不是让它自己慢慢收敛。

5.6 域名解析:离线环境的隐形杀手

chrony.conf里如果写的源是hostname而不是IP,离线内网DNS解析不到,服务端就会永远没有可用源。离线网络最常见的现象就是配置文件看起来没问题,chronyc sources -v却一直显示^?,最后发现是域名解析失败。内网自建时间源,配置里直接写IP,或者确保DNS服务里能解析到内网NTP源的主机名。


把这套方案完整跑下来之后,我对“无安装包”这个前提反而有了新的体会。对很多企业内部网络来说,离线不是什么意外状况,而是日常常态。与其每次遇到问题临时找包,不如平时就把系统ISO、常用软件包按版本归档起来,放到内网软件仓库里。我现在的习惯是每次装完一个新环境就把用到的rpm/deb顺手备份一份,十分钟的事,等哪天真的需要离线部署时,就会知道这些积累有多值钱。部署Chrony只是这类场景里很典型的一个切面——包能搞定,配置能落地,剩下的就是耐心和排查经验。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询