我需要将设备的时钟同步到 LXC 内运行的 CentOS-7 服务器。在服务器上,我尝试ntpd
从ntp
包中使用,但对其他产品开放。这个问题是关于ntpd
在服务器上设置或等效的。
到目前为止我尝试过这个/etc/ntp.conf
driftfile /var/lib/ntp/drift
restrict default nomodify notrap nopeer noquery
restrict 127.0.0.1
restrict ::1
server 127.127.1.1 iburst
fudge 127.127.1.1 stratum 8
disable monitor
这里有两个问题。
ntpd
记录后终止cap_set_proc() failed to drop root privileges: Operation not permitted
ntpd
正在尝试调整当地时间。它失败了,但它尝试了。如果这是唯一的问题并且我在日志中有错误消息,我可以接受。
/var/log/messages
尝试启动 ntpd 导致的完整输出:
systemd: Starting Network Time Service...
ntpd[20154]: ntpd [email protected] Wed Apr 12 21:24:06 UTC 2017 (1)
ntpd[20155]: proto: precision = 0.120 usec
ntpd[20155]: ntp_adjtime() failed: Operation not permitted
systemd: Started Network Time Service.
ntpd[20155]: 0.0.0.0 c01d 0d kern kernel time sync enabled
ntpd[20155]: Listen and drop on 0 v4wildcard 0.0.0.0 UDP 123
ntpd[20155]: Listen and drop on 1 v6wildcard :: UDP 123
ntpd[20155]: Listen normally on 2 lo 127.0.0.1 UDP 123
ntpd[20155]: Listen normally on 3 eth0 hidden:A.B.C.D UDP 123
ntpd[20155]: Listen normally on 4 tun0 hidden:E.F.G.H UDP 123
ntpd[20155]: Listening on routing socket on fd #21 for interface updates
ntpd[20155]: 0.0.0.0 c016 06 restart
ntpd[20155]: ntp_adjtime() failed: Operation not permitted
ntpd[20155]: 0.0.0.0 c012 02 freq_set kernel 0.000 PPM
ntpd[20155]: 0.0.0.0 c011 01 freq_not_set
ntpd[20155]: cap_set_proc() failed to drop root privileges: Operation not permitted
systemd: ntpd.service: main process exited, code=exited, status=255/n/a
systemd: Unit ntpd.service entered failed state.
systemd: ntpd.service failed.
答案1
正如评论中所讨论的,慢性的最近收到了一个新选项-x
,不尝试更改系统时钟,使其特别适合容器操作。可惜的是,接收此选项的第一个版本(3.2)并不彻底,并且仍然请求 Linux 功能,因此仍然失败。
施展CentOS7 LXC 容器(带有非 CentOS 主机)中的 chronyd 包 chrony 版本 3.2-2.el7 带有选项-x
,实际上错误修复不在这里:
# strace /usr/sbin/chronyd -x -d
[...]
[pid 571] capget({_LINUX_CAPABILITY_VERSION_3, 0}, NULL) = 0
[pid 571] capset({_LINUX_CAPABILITY_VERSION_3, 0}, {1<<CAP_NET_BIND_SERVICE|1<<CAP_SYS_TIME, 1<<CAP_NET_BIND_SERVICE|1<<CAP_SYS_TIME, 0}) = -1 EPERM (Operation not permitted)
因此,如果您可以阻止不可修改的二进制 chronyd 请求禁止的功能,它就会运行(这就是 3.3 错误修复的内容)。好消息,可以使用LD_PRELOAD
/dlsym()
包装纸。
在其他地方的其他 Linux 系统上编译(编译实际上是在 Debian 9 主机上进行的,并且按原样在 CentOS7 容器上运行没有遇到任何麻烦)此代码名为capsetwrapper.c
,找到了结构定义那里例如(这在内核 3.10 中也没有改变)。
#define _GNU_SOURCE 1
#include <dlfcn.h>
#include <sys/capability.h>
int capset(cap_user_header_t hdrp, const cap_user_data_t datap) {
int (*orig_capset)(cap_user_header_t,const cap_user_data_t)=dlsym(RTLD_NEXT,"capset");
datap->effective &= ~ (1<<CAP_SYS_TIME);
datap->permitted &= ~ (1<<CAP_SYS_TIME);
return orig_capset(hdrp, datap);
}
使用这种特定的方式(使库适合LD_PRELOAD
使用):
gcc -shared -fPIC -o libcapsetwrapper.so capsetwrapper.c -ldl
它的工作原理如下所示:
[root@centos7-amd64bis ~]# LD_PRELOAD=/root/libcapsetwrapper.so /usr/sbin/chronyd -x -d
2019-03-24T10:09:58Z chronyd version 3.2 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SECHASH +SIGND +ASYNCDNS +IPV6 +DEBUG)
2019-03-24T10:09:58Z Disabled control of system clock
2019-03-24T10:09:58Z Frequency 0.000 +/- 1000000.000 ppm read from /var/lib/chrony/drift
运行时检查其功能:
# egrep '^Cap(Prm|Eff)' /proc/$(pidof chronyd)/status
CapPrm: 0000000000000400
CapEff: 0000000000000400
显示 0x400,这是上面看到的剩余部分1<<CAP_NET_BIND_SERVICE
。
要将其集成到系统中:
将包装纸放置
libcapsetwrapper.so
为/usr/local/lib/libcapsetwrapper.so
使用
systemctl edit chronyd
,覆盖CAP_SYS_TIME
检查,可执行文件以此开头:[Unit] ConditionCapability= [Service] ExecStart= ExecStart=/bin/sh -c 'export LD_PRELOAD=/usr/local/lib/libcapsetwrapper.so; exec /usr/sbin/chronyd -x'
抱歉,我无法重用该
$OPTIONS
参数(该参数是空的,应该-x
从 加载该选项/etc/sysconfig/chronyd
),但有了更多的 systemd 知识,这应该是可能的。
工作结果:
# systemctl status chronyd
● chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/chronyd.service.d
`-override.conf
Active: active (running) since Sun 2019-03-24 10:24:26 UTC; 13min ago
Docs: man:chronyd(8)
man:chrony.conf(5)
Process: 843 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
Process: 839 ExecStart=/bin/sh -c export LD_PRELOAD=/usr/local/lib/libcapsetwrapper.so; exec /usr/sbin/chronyd -x (code=exited, status=0/SUCCESS)
Main PID: 841 (chronyd)
CGroup: /system.slice/chronyd.service
`-841 /usr/sbin/chronyd -x
没有测试的是默认 SELinux 环境(此处不可用)是否允许预加载操作,或者是否应该执行更多操作/usr/local/lib/libcapsetwrapper.so
(请务必使用restorecon
它)。
答案2
自版本以来1908年7月7日CentOS有chrony
版本3.4它-x
正确支持该标志,并且可以在 LXC 下运行,只需进行一些小的配置调整。
- 默认情况
/usr/lib/systemd/system/chronyd.service
下,在 LXC 下ConditionCapability=CAP_SYS_TIME
运行时不应该存在-x
,因此通过在文件中添加此删除项来删除它/etc/systemd/system/chronyd.service.d/lxc.conf
[Unit]
# Default service has:
# ConditionCapability=CAP_SYS_TIME
# which does not work under LXC and causes service to refuse to start
# Clear it.
ConditionCapability=
编辑
/etc/sysconfig/chronyd
并添加-x
到OPTIONS
最后OPTIONS="-x"
更改
/etc/chrony.conf
为不同步到任何 NTP 服务器,而是从本地时钟提供时间。删除/禁用所有其他server
条目,并添加:
# Comment out default/other server entries
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
#
# Add these as per https://www.thegeekdiary.com/centos-rhel-7-chrony-how-to-sync-to-local-clock/
server 127.127.1.0
local stratum 10
allow all
请查看allow
指令以满足您的需求,因为allow all
示例中的内容可能不适合您。
- 重新加载并重新启动服务
systemctl daemon-reload
systemctl restart chronyd
应该是这样。
答案3
我找到了一种让它工作的方法,但我对我的解决方案不满意,所以我仍在寻找更好的答案。
第 1 部分:我阻止ntpd
尝试放弃 root 权限。
其中/usr/lib/systemd/system/ntpd.service
默认有:
[Service]
EnvironmentFile=-/etc/sysconfig/ntpd
ExecStart=/usr/sbin/ntpd -u ntp:ntp $OPTIONS
-u ntp:ntp
所以我通过放置“删除”/etc/systemd/system/ntpd.service.d/local.conf
[Service]
ExecStart=
ExecStart=/usr/sbin/ntpd $OPTIONS
这允许ntpd
继续以 root 身份运行。它有效,但我对这种方法不满意。
第2部分.不更新当地时间部分
添加/etc/ntp.conf
行disable kernel
会导致ntpd
服务启动时ntp_adjtime() failed: Operation not permitted
仅记录一次错误,而不是在没有设置的情况下记录 3 次错误。由于它不能改变时钟,这是可以接受的。理想情况下,它甚至不会尝试改变时钟。