网络时间协议守护进程
网络时间协议 (NTP) 是最常用的方法,用于将 GNU/Linux 系统的 软件时钟 与互联网时间服务器同步。它旨在减轻网络延迟变化的影响,通常可以在公共互联网上将时间精度保持在几十毫秒以内。在局域网上的精度甚至更高,可达一毫秒。
NTP 项目 提供了一个名为 NTP 的协议的参考实现。本文将进一步介绍如何设置和运行 NTP 守护程序,作为客户端和服务器。
有关其他 NTP 实现,请参阅 System time#Time synchronization。
安装
安装 ntp 软件包。默认情况下,ntpd 在没有进一步配置的情况下以客户端模式运行。如果您想使用 Arch Linux 的默认配置文件,可以直接跳到 #Usage。有关服务器配置,请参阅 #NTP server mode。
配置
主守护程序是 ntpd,它在 /etc/ntp.conf 中进行配置。有关详细信息,请参阅 ntp.conf(5)。
连接到 NTP 服务器
NTP 服务器被分为一个包含许多级别的分层系统,称为 strata(层级):被视为独立时间源的设备被归类为 stratum 0 源;直接连接到 stratum 0 设备的服务器被归类为 stratum 1 源;连接到 stratum 1 源的服务器然后被归类为 stratum 2 源,依此类推。
需要理解的是,服务器的层级不能作为其精度或可靠性的指标。通常,stratum 2 服务器用于一般的同步目的:如果您不知道将要连接的服务器,应该从 pool.ntp.org 服务器池中选择一个离您位置较近的服务器(备用链接)。
自 ntp 版本 4.2.7.p465-2 以来,Arch Linux 使用由 NTP Pool 项目提供的自有默认 NTP 服务器池(请参阅 FS#41700)。根据您的需求修改它们,例如,如果您想使用您所在国家/地区的服务器,可以添加一个选项
/etc/ntp.conf
server 0.fr.pool.ntp.org iburst server 1.fr.pool.ntp.org iburst server 2.fr.pool.ntp.org iburst server 3.fr.pool.ntp.org iburst
推荐使用 iburst 选项,它只在第一次尝试无法建立连接时发送一个数据包突发。burst 选项无论如何都会这样做,即使在第一次尝试时,并且在未获得明确许可的情况下不应使用,否则可能导致被列入黑名单。
闰秒文件
为了使系统能够向请求它的应用程序提供 国际原子时间,必须加载闰秒列表。该列表是 tzdata 软件包的一部分,可以通过将以下行添加到 NTP 配置文件来加载
leapfile /usr/share/zoneinfo/leap-seconds.list
NTP 服务器模式
如果您正在设置 NTP 服务器,请检查是否已启用 孤儿模式 (orphan mode),这样即使它失去互联网连接,它也能继续为网络提供时间;通过 tos 配置参数启用孤儿模式(您可以设置高达 stratum 15),这样除非互联网连接丢失,否则它永远不会被使用。
tos orphan 15
接下来,使用 restrict 命令定义允许客户端连接到您的服务的规则(localhost 也被视为客户端);您的文件中应该已经有一行像这样
restrict default nomodify nopeer noquery
这会阻止所有人修改任何内容,并阻止所有人查询您的时间服务器的状态:nomodify 可阻止重配置 ntpd(使用 ntpq 或 ntpdc),而 noquery 对于 防止 从 ntpd(同样使用 ntpq 或 ntpdc)转储状态数据非常重要。
您还可以添加其他选项
restrict default kod limited nomodify notrap nopeer noquery
noserve 来停止提供时间。它还会阻止时间同步,因为它会阻止除 ntpq 和 ntpdc 查询之外的所有数据包。如果您想更改其中任何一个,请参阅 ntp.conf(5) 中关于 "restrict" 选项的完整文档,以及详细的 NTP 说明 和 #Usage。
在此行之后,您需要告诉 ntpd 允许哪些流量进入您的服务器;如果您不配置 NTP 服务器,以下行就足够了
restrict 127.0.0.1
如果您想强制 DNS 解析到 IPv6 命名空间,请在 IP 地址或主机名之前写上 -6(-4 则强制 IPv4),例如
restrict -6 default kod limited nomodify notrap nopeer noquery restrict -6 ::1 # ::1 is the IPv6 equivalent for 127.0.0.1
最后,指定漂移文件(drift file,用于跟踪您的时钟时间偏差)以及可选的日志文件位置
driftfile /var/lib/ntp/ntp.drift logfile /var/log/ntp.log
一个非常基础的配置文件将如下所示
/etc/ntp.conf
server 0.arch.pool.ntp.org iburst server 1.arch.pool.ntp.org iburst server 2.arch.pool.ntp.org iburst server 3.arch.pool.ntp.org iburst tos orphan 15 restrict default kod limited nomodify notrap nopeer noquery restrict -6 default kod limited nomodify notrap nopeer noquery restrict 127.0.0.1 restrict -6 ::1 driftfile /var/lib/ntp/ntp.drift logfile /var/log/ntp.log
用法
该软件包有一个默认的客户端模式配置,以及它自己的用户和组,以便在启动后放弃 root 权限。如果您从控制台启动它,应始终使用 -u 选项
# ntpd -u ntp:ntp
-u 选项被包含的两个 systemd 服务使用。这些服务还使用 -g 选项,该选项禁用了一个阈值(所谓的 panic-gate)。因此,即使 ntp-server 的时间超过了系统时钟的阈值偏差,它们也会同步时间。
这两个服务都与系统的解析器绑定,并在检测到活动网络连接时开始同步。
启动 ntpd 守护进程
启用 ntpd.service 守护程序。另请参阅 #Running in a chroot。
timedatectl set-ntp 1 会无意中停止正在运行的 ntpd.service。[1]使用 ntpq 查看已配置的对等节点列表和同步状态
$ ntpq -p
delay、offset 和 jitter 列应非零。ntpd 正在同步的服务器前面会有一个星号。ntpd 选择一个服务器进行同步可能需要几分钟时间;尝试在 17 分钟(1024 秒)后检查。
每次启动时同步一次时间
或者,启用 ntpdate.service 以在每次启动时同步一次时间(选项 -q)并且不fork(选项 -n),而不是在后台运行守护程序。此方法不推荐用于服务器,以及在不重启的情况下运行超过几天的机器。
如果同步的时间也应该写入硬件时钟,请在启动之前,按照 systemd#Editing provided units 中的描述配置提供的单元。
/etc/systemd/system/ntpdate.service.d/hwclock.conf
[Service] ExecStart=/usr/bin/hwclock -w
技巧与提示
网络连接时启动 ntpd
ntpd 可以由您的网络管理器启动,这样守护程序只在计算机在线时运行。
Netctl
将以下行追加到您的 netctl 配置文件中
ExecUpPost="systemctl start ntpd.service" ExecDownPre="systemctl stop ntpd.service"
NetworkManager
可以通过 NetworkManager 的 调度器 脚本,将 ntpd 守护程序随网络连接一起启动/停止。AUR 软件包 networkmanager-dispatcher-ntpd 安装了一个预先配置好的脚本,用于在连接时启动和停止 ntpd 服务。
KDE
KDE 可以使用 NTP(必须安装 ntp),方法是右键单击时钟并选择 调整日期/时间。但是,这要求在配置 KDE 使用 NTP 之前 禁用 ntp 守护程序。[2]
使用 ntpd 和 GPS
网上关于配置 ntpd 从 GPS 接收时间的文章大部分建议使用 SHM(共享内存)方法。然而,至少自 ntpd 版本 4.2.8 起,提供了一种 好得多的 方法。它直接连接到 gpsd,因此需要安装 gpsd。
将这些行添加到您的 /etc/ntp.conf
/etc/ntp.conf
#========================================================= # GPSD native ntpd driver #========================================================= # This driver exists from at least ntp version 4.2.8 # Details at # https://www.eecis.udel.edu/~mills/ntp/html/drivers/driver46.html server 127.127.46.0 fudge 127.127.46.0 time1 0.0 time2 0.0 refid GPS
只要 gpsd 正常工作,这就会奏效。它通过本地套接字连接到 gpsd 并查询返回的 "gpsd_json" 对象。
要测试设置,首先通过运行以下命令确保 gpsd 正常工作
$ cgps -s
然后等待几分钟并运行 ntpq -p。这将显示 ntpd 是否正在与 gpsd 通信
$ ntpq -p
remote refid st t when poll reach delay offset jitter ================================================================================== *GPSD_JSON(0) .GPS. 0 l 55 64 377 0.000 2.556 14.109
- 如果 reach 列为 0,则表示 ntpd 未能与 gpsd 通信。等待几分钟后重试。有时 ntpd 需要一些时间。
- GPS 设备必须具备 PPS 功能。您可以通过运行
ppscheck /dev/gps0来测试您的设备是否具备此能力。
/dev/gps0。如果您的 GPS 设备通过 USB 连接,它可能显示为 /dev/ttyUSB0,您可能需要创建一个符号链接 ln -s /dev/ttyUSB0 /dev/gps0,并在该链接的 /dev/gps0 上运行 gpsd,以便 GPSD_JSON 行按预期出现。gpsd 应该在 /etc/default/gpsd 配置文件中的 GPSD_OPTIONS 行上使用 -n 标志运行,并在 DEVICES 行上使用 /dev/gps0。在 chroot 中运行
如果 /etc/systemd/system/ntpd.service.d/ 目录不存在,则创建它,并在其中创建一个名为 customexec.conf 的文件,内容如下
[Service] ExecStart= ExecStart=/usr/bin/ntpd -g -u ntp:ntp -i /var/lib/ntp
然后,编辑 /etc/ntp.conf 以更改 driftfile 路径,使其相对于 chroot 目录,而不是实际的系统根目录。更改
driftfile /var/lib/ntp/ntp.drift
更改为
driftfile /ntp.drift
通过创建相关目录和文件(以 root 身份)来创建合适的 chroot 环境,以便 getaddrinfo() 能够工作
# mkdir /var/lib/ntp/etc /var/lib/ntp/lib /var/lib/ntp/proc # mkdir /var/lib/ntp/usr /var/lib/ntp/usr/lib # touch /var/lib/ntp/etc/resolv.conf /var/lib/ntp/etc/services
并通过绑定挂载上述文件
/etc/fstab
... #ntpd chroot mounts /etc/resolv.conf /var/lib/ntp/etc/resolv.conf none bind 0 0 /etc/services /var/lib/ntp/etc/services none bind 0 0 /lib /var/lib/ntp/lib none bind 0 0 /usr/lib /var/lib/ntp/usr/lib none bind 0 0 /proc /var/lib/ntp/proc none bind 0 0
# mount -a
最后,重新启动 ntpd 守护程序。重新启动后,您可以检查守护进程是否被 chroot,方法是查看 /proc/{PID}/root 符号链接指向哪里
# ps -C ntpd | awk '{print $1}' | sed 1d | while read -r PID; do ls -l /proc/$PID/root; done
现在应该指向 /var/lib/ntp 而不是 /。
在等待一段时间之前,相对难以确定您的 driftfile 配置是否真正有效,因为 ntpd 不会非常频繁地读取或写入它。如果配置错误,它会记录一个错误;如果配置正确,它会更新时间戳。如果在运行一整天后没有看到任何关于它的错误,并且时间戳已更新,您应该确信已成功。
限制监听套接字
您可以使用 interface 选项来限制 ntpd 正在监听的套接字
interface [listen | ignore | drop] [all | ipv4 | ipv6 | wildcard | name | address[/prefixlen]]
例如
/etc/ntp.conf
interface listen lo interface listen enp3s0 interface ignore enp5s0