feat: 添加时间同步配置功能至安装脚本
- 在 install.sh 中新增 sync_time 函数,配置系统时间同步,设置时区为 Asia/Shanghai,并安装 chrony。 - 配置 NTP 服务器为阿里云和腾讯云,确保时间同步的准确性。 - 更新主函数以调用时间同步配置,优化安装流程。
This commit is contained in:
@@ -13,7 +13,6 @@ import (
|
||||
"linkmaster-node/internal/heartbeat"
|
||||
"linkmaster-node/internal/recovery"
|
||||
"linkmaster-node/internal/server"
|
||||
"linkmaster-node/internal/timesync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
@@ -55,17 +54,6 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// 启动时间同步服务(每30分钟同步一次)
|
||||
var timeSync *timesync.TimeSync
|
||||
timeSync, err = timesync.NewTimeSync(logger)
|
||||
if err != nil {
|
||||
logger.Warn("创建时间同步器失败", zap.Error(err))
|
||||
timeSync = nil
|
||||
} else {
|
||||
go timeSync.Start(context.Background(), 30*time.Minute)
|
||||
logger.Info("时间同步服务已启动")
|
||||
}
|
||||
|
||||
// 启动心跳上报
|
||||
heartbeatReporter := heartbeat.NewReporter(cfg)
|
||||
go heartbeatReporter.Start(context.Background())
|
||||
@@ -91,9 +79,6 @@ func main() {
|
||||
|
||||
httpServer.Shutdown(ctx)
|
||||
heartbeatReporter.Stop()
|
||||
if timeSync != nil {
|
||||
timeSync.Stop()
|
||||
}
|
||||
|
||||
logger.Info("服务已关闭")
|
||||
}
|
||||
|
||||
138
install.sh
138
install.sh
@@ -410,6 +410,119 @@ install_dependencies() {
|
||||
echo -e "${GREEN}✓ 系统依赖安装完成${NC}"
|
||||
}
|
||||
|
||||
# 配置时间同步
|
||||
sync_time() {
|
||||
echo -e "${BLUE}配置时间同步...${NC}"
|
||||
|
||||
# 1. 设置时区为 Asia/Shanghai
|
||||
echo -e "${BLUE}[1/6] 设置时区为 Asia/Shanghai${NC}"
|
||||
if command -v timedatectl > /dev/null 2>&1; then
|
||||
sudo timedatectl set-timezone Asia/Shanghai 2>/dev/null || {
|
||||
echo -e "${YELLOW}⚠ timedatectl 设置时区失败,尝试其他方法${NC}"
|
||||
# 尝试创建时区链接(适用于较老的系统)
|
||||
if [ -f /usr/share/zoneinfo/Asia/Shanghai ]; then
|
||||
sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
elif [ -f /usr/share/zoneinfo/Asia/Shanghai ]; then
|
||||
sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# 2. 安装 chrony
|
||||
echo -e "${BLUE}[2/6] 安装 chrony${NC}"
|
||||
if [ "$OS" = "ubuntu" ] || [ "$OS" = "debian" ]; then
|
||||
if ! dpkg -l 2>/dev/null | grep -q "^ii.*chrony"; then
|
||||
sudo apt-get install -y chrony
|
||||
else
|
||||
echo -e "${BLUE}chrony 已安装,跳过${NC}"
|
||||
fi
|
||||
elif [ "$OS" = "centos" ] || [ "$OS" = "rhel" ] || [ "$OS" = "rocky" ] || [ "$OS" = "almalinux" ]; then
|
||||
if ! rpm -q chrony &>/dev/null; then
|
||||
sudo yum install -y chrony
|
||||
else
|
||||
echo -e "${BLUE}chrony 已安装,跳过${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}⚠ 未知系统类型,跳过 chrony 安装${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 3. 配置 NTP 服务器
|
||||
echo -e "${BLUE}[3/6] 配置 NTP 服务器${NC}"
|
||||
CONF="/etc/chrony.conf"
|
||||
|
||||
if [ -f "$CONF" ]; then
|
||||
# 备份配置文件
|
||||
if [ ! -f "${CONF}.backup.$(date +%Y%m%d)" ]; then
|
||||
sudo cp "$CONF" "${CONF}.backup.$(date +%Y%m%d)" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# 注释掉原有的 server 行
|
||||
sudo sed -i 's/^server /#server /g' "$CONF" 2>/dev/null || true
|
||||
|
||||
# 添加中国 NTP 服务器(如果还没有)
|
||||
if ! grep -q "ntp.aliyun.com" "$CONF"; then
|
||||
sudo tee -a "$CONF" > /dev/null <<EOF
|
||||
|
||||
# China NTP servers (added by LinkMaster Node installer)
|
||||
server ntp.aliyun.com iburst
|
||||
server ntp.tencent.com iburst
|
||||
server ntp1.aliyun.com iburst
|
||||
EOF
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}⚠ chrony.conf 不存在,跳过配置${NC}"
|
||||
fi
|
||||
|
||||
# 4. 启动并启用 chronyd
|
||||
echo -e "${BLUE}[4/6] 启动 chronyd${NC}"
|
||||
if command -v systemctl > /dev/null 2>&1; then
|
||||
sudo systemctl enable chronyd --now 2>/dev/null || {
|
||||
# 如果 systemctl 失败,尝试使用 service 命令
|
||||
if command -v service > /dev/null 2>&1; then
|
||||
sudo service chronyd start 2>/dev/null || true
|
||||
sudo chkconfig chronyd on 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
elif command -v service > /dev/null 2>&1; then
|
||||
sudo service chronyd start 2>/dev/null || true
|
||||
sudo chkconfig chronyd on 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# 等待服务启动
|
||||
sleep 2
|
||||
|
||||
# 5. 立即强制同步
|
||||
echo -e "${BLUE}[5/6] 强制同步系统时间${NC}"
|
||||
if command -v chronyc > /dev/null 2>&1; then
|
||||
sudo chronyc -a makestep 2>/dev/null || {
|
||||
# 如果 makestep 失败,尝试使用 sources 和 sourcestats
|
||||
sudo chronyc sources 2>/dev/null || true
|
||||
sudo chronyc sourcestats 2>/dev/null || true
|
||||
}
|
||||
fi
|
||||
|
||||
# 6. 写入硬件时间
|
||||
echo -e "${BLUE}[6/6] 写入硬件时钟${NC}"
|
||||
if command -v hwclock > /dev/null 2>&1; then
|
||||
sudo hwclock --systohc 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# 显示时间状态
|
||||
echo -e "${BLUE}当前时间状态:${NC}"
|
||||
if command -v timedatectl > /dev/null 2>&1; then
|
||||
sudo timedatectl status 2>/dev/null || true
|
||||
else
|
||||
date
|
||||
if command -v hwclock > /dev/null 2>&1; then
|
||||
echo -e "${BLUE}硬件时钟:${NC}"
|
||||
sudo hwclock 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓ 时间同步配置完成${NC}"
|
||||
}
|
||||
|
||||
# 从官网下载安装 Go
|
||||
install_go_from_official() {
|
||||
echo -e "${BLUE}从 Go 官网下载安装...${NC}"
|
||||
@@ -1515,26 +1628,29 @@ main() {
|
||||
echo -e "${BLUE}后端地址: ${BACKEND_URL}${NC}"
|
||||
echo ""
|
||||
|
||||
echo -e "${BLUE}[1/8] 检测系统类型...${NC}"
|
||||
echo -e "${BLUE}[1/11] 检测系统类型...${NC}"
|
||||
detect_system
|
||||
|
||||
# 检查是否已安装,如果已安装则先卸载
|
||||
if check_installed; then
|
||||
echo -e "${BLUE}[2/8] 卸载已存在的服务...${NC}"
|
||||
echo -e "${BLUE}[2/11] 卸载已存在的服务...${NC}"
|
||||
uninstall_service
|
||||
else
|
||||
echo -e "${BLUE}[2/8] 检查已安装服务...${NC}"
|
||||
echo -e "${BLUE}[2/11] 检查已安装服务...${NC}"
|
||||
echo -e "${GREEN}✓ 未检测到已安装的服务${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}[3/8] 检测并配置镜像源...${NC}"
|
||||
echo -e "${BLUE}[3/11] 检测并配置镜像源...${NC}"
|
||||
detect_fastest_mirror
|
||||
|
||||
echo -e "${BLUE}[4/8] 安装系统依赖...${NC}"
|
||||
echo -e "${BLUE}[4/11] 安装系统依赖...${NC}"
|
||||
install_dependencies
|
||||
|
||||
echo -e "${BLUE}[5/11] 配置时间同步...${NC}"
|
||||
sync_time
|
||||
|
||||
# 优先尝试从 Releases 下载二进制文件
|
||||
echo -e "${BLUE}[5/8] 下载或编译二进制文件...${NC}"
|
||||
echo -e "${BLUE}[6/11] 下载或编译二进制文件...${NC}"
|
||||
if ! download_binary_from_releases; then
|
||||
echo -e "${BLUE}从 Releases 下载失败,开始从源码编译...${NC}"
|
||||
build_from_source
|
||||
@@ -1542,19 +1658,19 @@ main() {
|
||||
echo -e "${GREEN}✓ 使用预编译二进制文件,跳过编译步骤${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}[6/8] 创建 systemd 服务...${NC}"
|
||||
echo -e "${BLUE}[7/11] 创建 systemd 服务...${NC}"
|
||||
create_service
|
||||
|
||||
echo -e "${BLUE}[7/8] 配置防火墙规则...${NC}"
|
||||
echo -e "${BLUE}[8/11] 配置防火墙规则...${NC}"
|
||||
configure_firewall
|
||||
|
||||
echo -e "${BLUE}[8/8] 登记节点到后端服务器...${NC}"
|
||||
echo -e "${BLUE}[9/11] 登记节点到后端服务器...${NC}"
|
||||
register_node
|
||||
|
||||
echo -e "${BLUE}[9/9] 启动服务...${NC}"
|
||||
echo -e "${BLUE}[10/11] 启动服务...${NC}"
|
||||
start_service
|
||||
|
||||
echo -e "${BLUE}[10/10] 验证安装...${NC}"
|
||||
echo -e "${BLUE}[11/11] 验证安装...${NC}"
|
||||
verify_installation
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -67,11 +67,10 @@ func GetNodeLocation() (country, province, city, isp string) {
|
||||
}
|
||||
|
||||
type Reporter struct {
|
||||
cfg *config.Config
|
||||
client *http.Client
|
||||
logger *zap.Logger
|
||||
stopCh chan struct{}
|
||||
beijingTZ *time.Location
|
||||
cfg *config.Config
|
||||
client *http.Client
|
||||
logger *zap.Logger
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
func NewReporter(cfg *config.Config) *Reporter {
|
||||
@@ -80,22 +79,13 @@ func NewReporter(cfg *config.Config) *Reporter {
|
||||
// 初始化节点信息(从配置文件读取)
|
||||
InitNodeInfo(cfg)
|
||||
|
||||
// 加载北京时间时区
|
||||
beijingTZ, err := time.LoadLocation("Asia/Shanghai")
|
||||
if err != nil {
|
||||
// 如果加载失败,使用UTC+8手动创建
|
||||
beijingTZ = time.FixedZone("CST", 8*60*60)
|
||||
logger.Warn("加载时区失败,使用UTC+8", zap.Error(err))
|
||||
}
|
||||
|
||||
return &Reporter{
|
||||
cfg: cfg,
|
||||
client: &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
},
|
||||
logger: logger,
|
||||
stopCh: make(chan struct{}),
|
||||
beijingTZ: beijingTZ,
|
||||
logger: logger,
|
||||
stopCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +94,8 @@ func (r *Reporter) Start(ctx context.Context) {
|
||||
r.sendHeartbeat()
|
||||
|
||||
for {
|
||||
// 获取当前北京时间
|
||||
now := time.Now().In(r.beijingTZ)
|
||||
// 计算到下一分钟第1秒的时间(基于北京时间)
|
||||
// 计算到下一分钟第1秒的时间
|
||||
now := time.Now()
|
||||
nextMinute := now.Truncate(time.Minute).Add(time.Minute)
|
||||
nextHeartbeatTime := nextMinute.Add(1 * time.Second)
|
||||
durationUntilNext := nextHeartbeatTime.Sub(now)
|
||||
@@ -122,7 +111,7 @@ func (r *Reporter) Start(ctx context.Context) {
|
||||
timer.Stop()
|
||||
return
|
||||
case <-timer.C:
|
||||
// 在每分钟的第1秒发送心跳(北京时间)
|
||||
// 在每分钟的第1秒发送心跳
|
||||
r.sendHeartbeat()
|
||||
}
|
||||
timer.Stop()
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
package timesync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// TimeSync 时间同步器
|
||||
type TimeSync struct {
|
||||
logger *zap.Logger
|
||||
stopCh chan struct{}
|
||||
beijingTZ *time.Location
|
||||
lastSyncTime time.Time
|
||||
lastSyncError error
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// K780TimeAPIResponse K780时间API响应结构
|
||||
type K780TimeAPIResponse struct {
|
||||
Success string `json:"success"`
|
||||
Msgid string `json:"msgid"`
|
||||
Msg string `json:"msg"`
|
||||
Result struct {
|
||||
Timestamp string `json:"timestamp"` // 时间戳(秒)
|
||||
TimestampMs string `json:"timestamp_ms"` // 时间戳(毫秒)
|
||||
Datetime1 string `json:"datetime_1"` // 日期时间格式1
|
||||
Datetime2 string `json:"datetime_2"` // 日期时间格式2
|
||||
} `json:"result"`
|
||||
}
|
||||
|
||||
// NewTimeSync 创建时间同步器
|
||||
func NewTimeSync(logger *zap.Logger) (*TimeSync, error) {
|
||||
// 加载北京时间时区
|
||||
beijingTZ, err := time.LoadLocation("Asia/Shanghai")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加载时区失败: %w", err)
|
||||
}
|
||||
|
||||
return &TimeSync{
|
||||
logger: logger,
|
||||
stopCh: make(chan struct{}),
|
||||
beijingTZ: beijingTZ,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// syncTime 同步时间(从HTTP API获取北京时间)
|
||||
func (ts *TimeSync) syncTime() error {
|
||||
// 使用K780时间API
|
||||
apiURL := "https://sapi.k780.com/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json"
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
// 创建请求,添加浏览器请求头
|
||||
req, err := http.NewRequest("GET", apiURL, nil)
|
||||
if err != nil {
|
||||
ts.mu.Lock()
|
||||
ts.lastSyncError = err
|
||||
ts.mu.Unlock()
|
||||
return fmt.Errorf("创建请求失败: %w", err)
|
||||
}
|
||||
|
||||
// 添加浏览器请求头,模拟浏览器访问
|
||||
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
|
||||
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
|
||||
req.Header.Set("Cache-Control", "max-age=0")
|
||||
req.Header.Set("Connection", "keep-alive")
|
||||
req.Header.Set("Referer", "https://www.nowapi.com/")
|
||||
req.Header.Set("Sec-Fetch-Dest", "document")
|
||||
req.Header.Set("Sec-Fetch-Mode", "navigate")
|
||||
req.Header.Set("Sec-Fetch-Site", "cross-site")
|
||||
req.Header.Set("Sec-Fetch-User", "?1")
|
||||
req.Header.Set("Upgrade-Insecure-Requests", "1")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36")
|
||||
req.Header.Set("sec-ch-ua", `"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"`)
|
||||
req.Header.Set("sec-ch-ua-mobile", "?0")
|
||||
req.Header.Set("sec-ch-ua-platform", `"macOS"`)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
ts.mu.Lock()
|
||||
ts.lastSyncError = err
|
||||
ts.mu.Unlock()
|
||||
return fmt.Errorf("API请求失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err := fmt.Errorf("API返回状态码: %d", resp.StatusCode)
|
||||
ts.mu.Lock()
|
||||
ts.lastSyncError = err
|
||||
ts.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
var result K780TimeAPIResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
ts.mu.Lock()
|
||||
ts.lastSyncError = err
|
||||
ts.mu.Unlock()
|
||||
return fmt.Errorf("解析API响应失败: %w", err)
|
||||
}
|
||||
|
||||
// 检查返回状态
|
||||
if result.Success != "1" {
|
||||
errMsg := fmt.Sprintf("API返回失败状态: success=%s", result.Success)
|
||||
if result.Msg != "" {
|
||||
errMsg += fmt.Sprintf(", msg=%s", result.Msg)
|
||||
}
|
||||
if result.Msgid != "" {
|
||||
errMsg += fmt.Sprintf(", msgid=%s", result.Msgid)
|
||||
}
|
||||
err := fmt.Errorf(errMsg)
|
||||
ts.mu.Lock()
|
||||
ts.lastSyncError = err
|
||||
ts.mu.Unlock()
|
||||
ts.logger.Warn("时间API返回失败", zap.String("success", result.Success), zap.String("msgid", result.Msgid), zap.String("msg", result.Msg))
|
||||
return err
|
||||
}
|
||||
|
||||
// 从result.timestamp字段解析时间戳字符串
|
||||
if result.Result.Timestamp == "" {
|
||||
err := fmt.Errorf("API返回的时间戳为空")
|
||||
ts.mu.Lock()
|
||||
ts.lastSyncError = err
|
||||
ts.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析时间戳字符串为int64
|
||||
var timestamp int64
|
||||
if _, err := fmt.Sscanf(result.Result.Timestamp, "%d", ×tamp); err != nil {
|
||||
err := fmt.Errorf("解析时间戳失败: %w", err)
|
||||
ts.mu.Lock()
|
||||
ts.lastSyncError = err
|
||||
ts.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// 使用时间戳转换为北京时间
|
||||
beijingTime := time.Unix(timestamp, 0).In(ts.beijingTZ)
|
||||
|
||||
// 计算时间差
|
||||
localTime := time.Now()
|
||||
timeDiff := beijingTime.Sub(localTime)
|
||||
|
||||
ts.mu.Lock()
|
||||
ts.lastSyncTime = beijingTime
|
||||
ts.lastSyncError = nil
|
||||
ts.mu.Unlock()
|
||||
|
||||
ts.logger.Info("时间同步成功",
|
||||
zap.String("api", apiURL),
|
||||
zap.String("remote_time", beijingTime.Format("2006-01-02 15:04:05")),
|
||||
zap.String("local_time", localTime.Format("2006-01-02 15:04:05")),
|
||||
zap.Duration("time_diff", timeDiff),
|
||||
zap.Int64("timestamp", timestamp))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start 启动定期时间同步
|
||||
func (ts *TimeSync) Start(ctx context.Context, interval time.Duration) {
|
||||
// 立即同步一次
|
||||
if err := ts.syncTime(); err != nil {
|
||||
ts.logger.Warn("初始时间同步失败", zap.Error(err))
|
||||
}
|
||||
|
||||
// 定期同步
|
||||
ticker := time.NewTicker(interval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ts.stopCh:
|
||||
return
|
||||
case <-ticker.C:
|
||||
if err := ts.syncTime(); err != nil {
|
||||
ts.logger.Warn("时间同步失败", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop 停止时间同步
|
||||
func (ts *TimeSync) Stop() {
|
||||
close(ts.stopCh)
|
||||
}
|
||||
|
||||
// GetBeijingTime 获取当前北京时间
|
||||
func (ts *TimeSync) GetBeijingTime() time.Time {
|
||||
return time.Now().In(ts.beijingTZ)
|
||||
}
|
||||
|
||||
// GetLocation 获取北京时区
|
||||
func (ts *TimeSync) GetLocation() *time.Location {
|
||||
return ts.beijingTZ
|
||||
}
|
||||
|
||||
// GetLastSyncTime 获取最后一次同步的时间
|
||||
func (ts *TimeSync) GetLastSyncTime() time.Time {
|
||||
ts.mu.RLock()
|
||||
defer ts.mu.RUnlock()
|
||||
return ts.lastSyncTime
|
||||
}
|
||||
|
||||
// GetLastSyncError 获取最后一次同步的错误
|
||||
func (ts *TimeSync) GetLastSyncError() error {
|
||||
ts.mu.RLock()
|
||||
defer ts.mu.RUnlock()
|
||||
return ts.lastSyncError
|
||||
}
|
||||
53
time.sh
Normal file
53
time.sh
Normal file
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== CentOS 7 时间同步脚本开始 ==="
|
||||
|
||||
# 1. 检查是否 root
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "请使用 root 用户执行"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. 设置时区
|
||||
echo "[1/6] 设置时区为 Asia/Shanghai"
|
||||
timedatectl set-timezone Asia/Shanghai
|
||||
|
||||
# 3. 安装 chrony
|
||||
echo "[2/6] 安装 chrony"
|
||||
if ! rpm -q chrony &>/dev/null; then
|
||||
yum install -y chrony
|
||||
else
|
||||
echo "chrony 已安装,跳过"
|
||||
fi
|
||||
|
||||
# 4. 配置 NTP 服务器
|
||||
echo "[3/6] 配置 NTP 服务器"
|
||||
CONF="/etc/chrony.conf"
|
||||
|
||||
sed -i 's/^server /#server /g' "$CONF"
|
||||
|
||||
grep -q "ntp.aliyun.com" "$CONF" || cat >> "$CONF" <<EOF
|
||||
|
||||
# China NTP servers
|
||||
server ntp.aliyun.com iburst
|
||||
server ntp.tencent.com iburst
|
||||
server ntp1.aliyun.com iburst
|
||||
EOF
|
||||
|
||||
# 5. 启动并启用 chronyd
|
||||
echo "[4/6] 启动 chronyd"
|
||||
systemctl enable chronyd --now
|
||||
|
||||
# 6. 立即强制同步
|
||||
echo "[5/6] 强制同步系统时间"
|
||||
chronyc -a makestep
|
||||
|
||||
# 7. 写入硬件时间
|
||||
echo "[6/6] 写入硬件时钟"
|
||||
hwclock --systohc
|
||||
|
||||
echo "=== 时间同步完成 ==="
|
||||
echo
|
||||
timedatectl status
|
||||
Reference in New Issue
Block a user