目录

chrony 静态编译及跨 Linux 发行版安装 systemd service

文章简介:chrony 静态编译及跨操作系统安装 systemd service

更新

基于 ubuntu 的镜像编译出的 chronyc 在 centos7.9 下执行 chronyc sources -vSegmentation fault, 初步断定是由于 glibc 静态编译时有部分动态依赖的 wake link 被使用到导致的。替换成基于 alpine 的 musl 即可解决问题.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
FROM alpine:edge as build
ARG branch=4.2
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
WORKDIR /opt

# COPY chrony . # 二选一
RUN apk add build-base libcap-dev texinfo nettle-dev gnutls-dev bash wget tar gcc make \
    && wget https://download.tuxfamily.org/chrony/chrony-${branch}.tar.gz \
    && tar zxf chrony-${branch}.tar.gz \
    && mv chrony-${branch} chrony \
    && rm -f chrony-${branch}.tar.gz

RUN cd chrony; \
    CFLAGS='-static -g' LDFLAGS='-static -lm'  \
      ./configure \
      --enable-scfilter \
      --enable-ntp-signd \
    && make; echo $?; \
    mkdir -p /install_root; \
    make DESTDIR=/install_root install \
    && find /install_root

RUN rm -rf /install_root/usr/local/share \
    && rmdir /install_root/var/lib/chrony/ /install_root/etc

FROM scratch AS bin
COPY --from=build /install_root /

正文

最近一段时间做的需求主要是适配 kylinsec 国产化操作系统. 因为产品是 tob 私有化部署 k8s 集群,并且多机器需要同步时间。经过调研后发现 chrony 已经作为 redhat 8 等多种发行版的默认选项,决定统一使用 chrony 作为我们的时间同步 daemon.

应用的自动化部署方案使用了 ansible,不同 Linux 发行版软件包不相同,所以适配一种 Linux 发行版,就需要为这种 Linux 发行版下载对应软件包。比如 chrony 在 centos 7/8/9, ubuntu 20.04/18.04, kylinsec … 等都需要单独下载一遍 chrony 安装包,整体总共适配了 6 遍,十分麻烦。当需要适配的软件包更多后,成本就凸显出来了. 可以选择静态编译,抹平各发行版的差异,一次搞定。

还好,静态编译的工作已经有大佬做过了静态编译 chrony,

dockerfile 如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# docker buildx build -f Dockerfile.chrony --platform linux/amd64 --target bin --output installer
FROM ubuntu:20.04 as build
ARG branch=4.2
ENV DEBIAN_FRONTEND noninteractive
RUN sed -ri 's/(ports|deb|security|archive).(debian.org|ubuntu.com)/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list \
    && apt-get update
WORKDIR /opt

# COPY chrony . # 二选一
#RUN apt-get install -y git && git clone --branch ${branch} https://git.tuxfamily.org/chrony/chrony.git
RUN apt-get install -y wget && wget https://download.tuxfamily.org/chrony/chrony-${branch}.tar.gz \
    && tar zxf chrony-${branch}.tar.gz \
    && mv chrony-${branch} chrony \
    && rm -f chrony-${branch}.tar.gz

RUN apt-get install -y \
    bison asciidoctor \
    gcc \
    make \
    pkg-config \
    libcap-dev \
    pps-tools \
    libedit-dev \
    nettle-dev \
    libnss3-dev \
    libtomcrypt-dev \
    libgnutls28-dev \
    libseccomp-dev

RUN cd chrony; \
    CFLAGS='-static -s' LDFLAGS='-static -lm'  \
      ./configure \
      --enable-scfilter \
      --enable-ntp-signd \
    && make; echo $?; \
    mkdir -p /install_root; \
    make DESTDIR=/install_root install \
    && find /install_root

RUN rm -rf /install_root/usr/local/share \
    && rmdir /install_root/var/lib/chrony/ /install_root/etc

FROM scratch AS bin
COPY --from=build /install_root /

buildx 一步编译出软件包

1
2
3
4
5
6
7
8
docker buildx build -f Dockerfile.chrony --platform linux/amd64 --target bin --output installer

file installer/{usr/local/bin/chronyc,usr/local/sbin/chronyd}
installer/usr/local/bin/chronyc:  ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=a8851c783b1074f3414d8b38bb337cb10a8b016d, for GNU/Linux 3.2.0, stripped
installer/usr/local/sbin/chronyd: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=a7ed52ca561252969d5e0f29b8894380b70bd8c5, for GNU/Linux 3.2.0, stripped

# 多平台编译
docker buildx build  . --platform linux/amd64,linux/arm64  --target bin --output installer

有了二进制文件该如何部署服务呢?

如下是写好的 systemd service 文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
cat <<EOF >/etc/chrony.conf
# Generated by TODO
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).

server pool.ntp.org iburst

driftfile /var/lib/chrony/drift
makestep 1.0 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync
allow 0.0.0.0/0
local stratum 10
logdir /var/log/chrony
log measurements statistics tracking
EOF

cat <<EOF >/etc/chrony.keys
# This file is solely used for NTP authentication with symmetric keys
# as defined by RFC 1305 and RFC 5905.
#
# It can contain ID/key pairs which can be generated using the “keygen” option
# from “chronyc”; for example:
# chronyc keygen 1 SHA256 256 >> /etc/chrony/chrony.keys
# would generate a 256-bit SHA-256 key using ID 1.
#
# A list of supported hash functions and output encoding is available by
# consulting the "keyfile" directive in the chrony.conf(5) man page.
EOF

cat <<EOF >/etc/systemd/system/chrony.service
[Unit]
Description=chrony, an NTP client/server
Documentation=man:chronyd(8) man:chronyc(1) man:chrony.conf(5)
Conflicts=openntpd.service ntp.service ntpsec.service systemd-timesyncd.service
Wants=time-sync.target
Before=time-sync.target
After=network.target
# ConditionCapability=CAP_SYS_TIME

[Service]
# Type=forking
# PIDFile=/run/chronyd.pid
# EnvironmentFile=-/etc/default/chrony
# Starter takes care of special cases mostly for containers
ExecStart=/usr/sbin/chronyd -F -0 -d -f /etc/chrony.conf
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full

[Install]
Alias=chronyd.service
WantedBy=multi-user.target
EOF

systemctl enable --now chrony

到这里就可以了吗?

当我们执行 timedatectl set-ntp off 后, chronyd 服务并没有按照预期停止时间同步。根据文档 timedated , 命令 timedatectl set-ntp off 会启动或停止 systemd-timedated.service; 文档 systemd-timedated.service 描述, systemd-timedated.service 会从 /usr/lib/systemd/ntp-units.d/50-chronyd.list 文件中启停系统时间同步服务。当前使用的时间服务是 chrony,需要覆盖文件/usr/lib/systemd/ntp-units.d/50-chronyd.list中的值,使得 timedatectl set-ntp off 能够按照预期启停时间同步.

1
echo 'chrony.service' >/usr/lib/systemd/ntp-units.d/50-chronyd.list

到这里,chrony 正式工作了.

安装 chrony service 的完整脚本

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env bash

set -o errtrace
set -o errexit
set -o nounset
set -o pipefail
set -o xtrace

cd $(dirname "$0")

if [[ $EUID -ne 0 ]]; then
    echo "This script must be run as root"
    exit 1
fi

DIR=$(dirname $(realpath $0))

install_chrony() {
    systemctl stop chrony || true
    systemctl disable chrony || true # 向前兼容 ubuntu 20.04 中可能会安装有 chrony
    systemctl stop chronyd || true
    systemctl disable chronyd || true

    # ubuntu 20.04 中会有此服务
    systemctl stop systemd-timesyncd || true
    systemctl disable systemd-timesyncd || true

    chown root:root /var/run/chrony || true

    # for chrony logdir on ubuntu
    rm -rf /var/log/chrony
    mkdir -p /var/log/chrony

    mkdir -p /var/lib/chrony/
    mkdir -p /etc/chrony/

    # ubuntu 默认的配置文件位置是 /etc/chrony/chrony.conf
    # centos7 默认的配置文件位置是 /etc/chrony.conf
    test -f "/etc/chrony/chrony.conf" && mv /etc/chrony/chrony.conf /etc/chrony/chrony.conf.$(date "+%Y-%m-%d_%H%M%S").bak
    test -f /etc/chrony.conf && mv /etc/chrony.conf /etc/chrony.conf.$(date "+%Y-%m-%d_%H%M%S").bak
    ln -s -f /etc/chrony.conf /etc/chrony/chrony.conf

    cat <<EOF >/etc/chrony.conf
# Generated by TODO
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).

server pool.ntp.org iburst

driftfile /var/lib/chrony/drift
makestep 1.0 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync
allow 0.0.0.0/0
local stratum 10
logdir /var/log/chrony
log measurements statistics tracking
EOF

    cat <<EOF >/etc/chrony.keys
# This file is solely used for NTP authentication with symmetric keys
# as defined by RFC 1305 and RFC 5905.
#
# It can contain ID/key pairs which can be generated using the “keygen” option
# from “chronyc”; for example:
# chronyc keygen 1 SHA256 256 >> /etc/chrony/chrony.keys
# would generate a 256-bit SHA-256 key using ID 1.
#
# A list of supported hash functions and output encoding is available by
# consulting the "keyfile" directive in the chrony.conf(5) man page.
EOF

    cat <<EOF >/etc/systemd/system/chrony.service
[Unit]
Description=chrony, an NTP client/server
Documentation=man:chronyd(8) man:chronyc(1) man:chrony.conf(5)
Conflicts=openntpd.service ntp.service ntpsec.service systemd-timesyncd.service
Wants=time-sync.target
Before=time-sync.target
After=network.target
# ConditionCapability=CAP_SYS_TIME

[Service]
# Type=forking
# PIDFile=/run/chronyd.pid
# EnvironmentFile=-/etc/default/chrony
# Starter takes care of special cases mostly for containers
ExecStart=/usr/sbin/chronyd -F -1 -d -f /etc/chrony.conf
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full

[Install]
Alias=chronyd.service
WantedBy=multi-user.target
EOF

    cp usr/local/sbin/chronyd /usr/sbin/chronyd
    cp usr/local/bin/chronyc /usr/bin/chronyc

    # timedatectl set-ntp off 会触发
    # http://www.freedesktop.org/wiki/Software/systemd/timedated
    # systemctl status systemd-timedated
    # https://www.freedesktop.org/software/systemd/man/systemd-timedated.service.html#
    # STEP: centos7.9
    ls /usr/lib/systemd/ntp-units.d/
    echo 'chrony.service' >/usr/lib/systemd/ntp-units.d/50-chronyd.list || true

    # /usr/sbin/chronyd -f /etc/chrony/chrony.conf -d -R
    systemctl enable --now chrony || true
    systemctl restart chrony
}

install_chrony

参考