非root权限下部署 Cronicle 单主集群实战

本文提供了 非root权限下 Cronicle 的现代化单主机群部署方案。通过 pnpm 独立版(Standalone),实现 Node 运行时与应用依赖的完全解耦,打造绿色、便携、可复现的调度系统环境。

🛠️ 技术特点

  1. 环境隔离:采用 pnpm env use lts -g方式,无需 nvm/fnm。

  2. 源码构建:通过 Tarball 方式安装最新版 Cronicle,利用 pnpm 内置 Node 编译资源,摆脱系统环境依赖。

  3. 集群通信:禁用 UDP 广播,采用 udp_broadcast_port: 0+ web_direct_connect: true强制 TCP 直连,适配跨主机与云原生环境。

  4. 数据生命周期:配置 job_data_expire_days: 15自动清理历史记录,配合 log_archive_path实现日志归档分离,兼顾存储成本与审计需求。

🏗️ 部署架构

  • Master 节点:执行 control.sh setup初始化存储,负责调度与 Web 管理。

  • Worker 节点:通过复制 Master 配置并直接 start,由 TCP 机制自动注册加入集群。

  • 运维管理:提供完整的 Systemd User Mode 配置,实现非 root 用户下的开机自启与进程守护。

🎯 适用人群

  • 追求环境纯净、拒绝污染系统库的运维工程师。

  • 需要在离线环境受限服务器部署 Node 应用的开发者。

  • 希望构建高可用 Cronicle 集群但受限于网络环境(跨 VPC/云服务器)的技术团队。


一、完整部署脚本

流程:安装独立 pnpm → 利用其内置 Node 安装依赖 → 构建 Cronicle → 通过Systemd User Mode实现非 root 用户下的开机自启。

保存为 deploy_cronicle_tarball.sh,直接运行即可:

#!/bin/bash
set -e

# ========== 配置区 ==========
BASE_DIR="/opt/cronicle"
CONFIG_FILE="$BASE_DIR/conf/config.json"
CRONICLE_VERSION="master"  # 或指定如 "v0.9.116"
BASE_APP_URL="http://localhost:13012"
# ============================

echo "[INFO] 部署目录: $BASE_DIR"
echo "[INFO] 配置文件: $CONFIG_FILE"
echo "[INFO] 安装版本: $CRONICLE_VERSION"
echo "[INFO] 访问地址: $BASE_APP_URL"

mkdir -p "$BASE_DIR"
cd "$BASE_DIR"

# 阶段 1:安装独立版 pnpm (自带 Node 运行时)
echo -e "\n[1] 安装独立版 pnpm..."
wget -qO- https://get.pnpm.io/install.sh | sh -
source ~/.bashrc
export PNPM_HOME="$HOME/.local/share/pnpm"
export PATH="$PNPM_HOME/bin:$PATH"

# 安装 Node.js 的 LTS 版本
pnpm runtime set node lts -g
echo "[OK] pnpm 版本: $(pnpm -v) | NodeJS 版本: $(node -v)"

# 阶段 2:下载 Cronicle 源码 Tarball
echo -e "\n[2] 下载 Cronicle 源码包 (版本: $CRONICLE_VERSION)..."
TARBALL_URL="https://ghfast.top/github.com/jhuckaby/Cronicle/archive/${CRONICLE_VERSION}.tar.gz"
curl -L "$TARBALL_URL" | tar zxvf - --strip-components 1

# 阶段 3:使用 pnpm 安装依赖并构建
echo -e "\n[3] 安装依赖(使用独立版 pnpm)..."
pnpm install

# 构建前端资源(关键:使用 pnpm 自带的 Node 运行时)
echo -e "\n[4] 构建前端资源..."
node bin/build.js dist

echo -e "\n[5] 修改 Cronicle 配置..."
cp "$CONFIG_FILE" "${CONFIG_FILE}.bak.$(date +%F_%T)"
# 设置访问和通信地址
sed -i 's#"base_app_url"[[:space:]]*:[^,]*#"base_app_url": "'"${BASE_APP_URL}"'"#' "$CONFIG_FILE"
# 设置自动清理已完成 Job 的运行数据和日志的时间阈值
sed -i 's#"job_data_expire_days"[[:space:]]*:[^,]*#"job_data_expire_days": 15#' "$CONFIG_FILE"
# 设置日志归档路径
sed -i 's#"log_archive_path"[[:space:]]*:[^,]*#"log_archive_path": "logs/archives/[yyyy]-[mm]-[dd]/[filename]-[yyyy]-[mm]-[dd].log.gz"#' "$CONFIG_FILE"
# 设置http访问端口,必须大于8000
sed -i 's#"http_port"[[:space:]]*:[^,]*#"http_port": 13012#' "$CONFIG_FILE"
# UDP 广播(udp_broadcast_port)仅用于局域网内的自动发现。在跨网段或云环境等无法进行 UDP 广播的场景下,可完全禁用 UDP,改用手动指定 Master​ 的方式建立连接。
# 设为 0 禁用 UDP 广播
sed -i 's#"udp_broadcast_port"[[:space:]]*:[^,]*#"udp_broadcast_port": 0#' "$CONFIG_FILE"
# 开启后:使用主机名(hostname)通信​,关闭时:优先使用 IP 地址通信
sed -i 's#"server_comm_use_hostnames"[[:space:]]*:[^,]*#"server_comm_use_hostnames": false#' "$CONFIG_FILE"
# 强制直连(不走广播)
sed -i 's#"web_direct_connect"[[:space:]]*:[^,]*#"web_direct_connect": true#' "$CONFIG_FILE"

grep -E '"base_app_url"|"job_data_expire_days"|"log_archive_path"|"http_port"|"udp_broadcast_port"|"server_comm_use_hostnames"|"web_direct_connect"' "$CONFIG_FILE"
echo -e "\n[SUCCESS] Cronicle 安装完成!"

echo -e "\n运行以下脚本初始化存储系统。只需在主服务器(Master)上执行一次。不要在任何工作服务器(Worker)上运行:"
echo "${BASE_DIR}/bin/control.sh setup"

二、Systemd 用户自启动配置

  1. 创建 ~/.config/systemd/user/cronicle.service

    [Unit]
    Description=Cronicle Scheduler (User Mode)
    After=network.target
    
    [Service]
    Type=forking
    PIDFile=/opt/cronicle/logs/cronicled.pid
    
    ExecStart=/opt/cronicle/bin/control.sh start
    ExecStop=/opt/cronicle/bin/control.sh stop
    ExecReload=/opt/cronicle/bin/control.sh restart
    
    # 注意把 /home/rpa/.local/share/pnpm/bin 修改你的 node 所在目录
    Environment=PATH=/home/rpa/.local/share/pnpm/bin:/usr/local/bin:/usr/bin:/bin
    WorkingDirectory=/opt/cronicle
    Restart=always
    RestartSec=10
    
    [Install]
    WantedBy=default.target
  2. 启动服务

    systemctl --user daemon-reload
    systemctl --user enable --now cronicle  # 启用并立即启动
  3. 停止/重启服务

    systemctl --user stop cronicle
    systemctl --user restart cronicle
  4. 卸载服务

    systemctl --user stop cronicle
    systemctl --user disable cronicle
    rm -f ~/.config/systemd/user/cronicle.service
    systemctl --user daemon-reload

三、Worker 和 Master 的两种通信方式

在 Cronicle 中,Worker 与 Master 的通信方式只有两种,且互斥(二选一)

1. 两种通信方式总览

通信方式

核心机制

默认状态

适用场景

UDP 广播发现​

局域网广播 + 自动注册

✅ 默认开启

同网段物理机

TCP / HTTP 直连​

基于 base_app_url的主动注册

❌ 默认关闭

Docker / 跨主机 / 云环境​

2. 方式一:UDP 广播发现

🔧 工作原理

  1. Worker 启动后,向 UDP 广播地址(如 255.255.255.255)发送发现包。

  2. Master 监听 udp_broadcast_port(默认 3014)。

  3. Master 收到广播后,通过反向连接将 Worker 加入集群。

⚙️ 所需配置(双方一致)

"base_app_url": "http://master:13012"    // ✅ Master 访问地址
"udp_broadcast_port": 3014,
"server_comm_use_hostnames": false,
"web_direct_connect": false

3. 方式二:TCP / HTTP 直连

🔧 工作原理

  1. Worker 启动后,直接读取自己的 config.json

  2. 使用 base_app_url作为 Master 地址。

  3. 通过 HTTP / WebSocket​ 主动向 Master 注册。

  4. 后续所有心跳、任务分发均通过 TCP 进行。

⚙️所需配置(双方一致)

"base_app_url": "http://master:13012"    // ✅ Master 访问地址
"udp_broadcast_port": 0,                 // ✅ 禁用 UDP
"server_comm_use_hostnames": false,       // ✅ 使用IP进行通信,为true时使用主机名hostname进行通信
"web_direct_connect": true,              // ✅ 强制 TCP 直连

✅ 网络要求

端口

方向

用途

13012/tcp

Worker → Master

HTTP / WebSocket 注册与心跳

4. 两种方式的关键差异对照表

维度

UDP 广播

TCP 直连

是否依赖广播

✅ 是

❌ 否

是否可跨网段

❌ 否

✅ 是

Docker 友好度

❌ 差

✅ 极佳

云环境支持

❌ 基本不可用

✅ 标准

是否需要 Master IP

❌ 自动发现

✅ base_app_url

5. Worker 连接 Master 的完整数据流(TCP 模式)

[Worker 启动]
      ↓
读取 config.json
      ↓
检测到 udp_broadcast_port = 0
      ↓
启用 web_direct_connect = true
      ↓
向 base_app_url 发起 HTTP 注册
      ↓
Master 验证 secret_key
      ↓
建立 WebSocket 长连接
      ↓
开始接收调度任务

四、Worker 部署步骤

按上述第二步已部署有一个运行正常的 Master(端口 13012),现在要部署 Worker:

1. 准备配置文件(关键步骤)

Worker 的 config.json必须与 Master 完全一致(除了个别网络参数),否则无法加入集群。

必须保持一致的参数:

  • secret_key必须相同,这是集群的“密码”,不同则无法连接。

  • udp_broadcast_port:必须相同(默认 3014), 基于TCP应设置为 0。

  • base_app_url:通常指向 Master 的地址(用于 Web 界面跳转)。

Worker 独有的配置(可选):

  • 如果 Worker 位于 NAT 或负载均衡后,需设置 hostnameip为对外可见的地址。

2. 启动 Worker 的绝对禁忌⚠️

Worker 节点严禁执行 /opt/cronicle/bin/control.sh setupsetup命令会初始化新的存储库/数据库,导致它与 Master 数据不一致。

正确的启动命令:

# 执行
/opt/cronicle/bin/control.sh start
# 或者执行
systemctl -user start cronicle

Linux系统配置优化 2026-05-06