本文提供了 非root权限下 Cronicle 的现代化单主机群部署方案。通过 pnpm 独立版(Standalone),实现 Node 运行时与应用依赖的完全解耦,打造绿色、便携、可复现的调度系统环境。
🛠️ 技术特点
环境隔离:采用
pnpm env use lts -g方式,无需 nvm/fnm。源码构建:通过 Tarball 方式安装最新版 Cronicle,利用 pnpm 内置 Node 编译资源,摆脱系统环境依赖。
数据生命周期:配置
job_data_expire_days: 15自动清理历史记录,配合log_archive_path实现日志归档分离,兼顾存储成本与审计需求。基于IP通信:Master和Worker之间通过IP地址通信,禁止通过主机名;
🏗️ 部署架构
Master 节点:执行
control.sh setup初始化存储,负责调度与 Web 管理。Worker 节点:通过复制 Master 配置并直接
start,由 UDP 机制自动注册加入集群。运维管理:提供完整的 Systemd User Mode 配置,实现非 root 用户下的开机自启与进程守护。
🎯 适用人群
追求环境纯净、拒绝污染系统库的运维工程师。
需要在离线环境或受限服务器部署 Node 应用的开发者。
希望构建高可用 Cronicle 集群但受限于网络环境(跨 VPC/云服务器)的技术团队。
一、安装部署脚本
流程:安装独立 pnpm → 利用其内置 Node 安装依赖 → 构建 Cronicle → 通过Systemd User Mode实现非 root 用户下的开机自启。
1. 创建cronicle安装目录并赋予普通用户权限
sudo mkdir -p /opt/cronicle
sudo chown -R [username]:[usergroup] /opt/cronicle
cd /opt/cronicle2. 保存为 deploy_cronicle_tarball.sh,直接运行
#!/bin/bash
set -e
# ========== 配置区 ==========
BASE_DIR="/opt/cronicle"
CONFIG_FILE="$BASE_DIR/conf/config.json"
CRONICLE_VERSION="master" # 或指定如 "v0.9.117"
BASE_APP_URL="http://192.168.1.100:13012" # 请把ip地址改为所在设备的局域网IP
SECRET_KEY="512a4c43fd3d680ea25bd87658bb5cc2"
# ============================
# 进入Cronicle安装目录
cd "$BASE_DIR"
echo "[INFO] 部署目录: $BASE_DIR"
echo "[INFO] 配置文件: $CONFIG_FILE"
echo "[INFO] 安装版本: $CRONICLE_VERSION"
echo "[INFO] 访问地址: $BASE_APP_URL"
# 阶段 1:安装独立版 pnpm (自带 Node 运行时)
echo -e "\n[1] 安装独立版 pnpm..."
wget https://get.pnpm.io/install.sh -O "$BASE_DIR/install_pnpm.sh"
sed -i 's|https://github.com/|https://ghfast.top/github.com/|g' "$BASE_DIR/install_pnpm.sh"
chmod +x "$BASE_DIR/install_pnpm.sh"
sh "$BASE_DIR/install_pnpm.sh"
source ~/.bashrc # 如果使用zsh,则应 source ~/.zshrc
export PNPM_HOME="$HOME/.local/share/pnpm"
export PATH="$PNPM_HOME/bin:$PATH"
pnpm config set registry https://registry.npmmirror.com
pnpm config set @pnpm:registry https://registry.npmmirror.com
# 安装 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
# 强制pnpm使用包的版本
echo -e "解决Tools.normalizeTime is not a function问题"
echo -e "overrides:\n pixl-tools: \"2.0.3\"" > /opt/cronicle/pnpm-workspace.yaml
# 阶段 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"
# 设置密钥
sed -i 's#"secret_key"[[:space:]]*:[^,]*#"secret_key": "'"${SECRET_KEY}"'"#' "$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广播端口 13014(udp_broadcast_port)用于局域网内的自动发现。在跨网段或云环境等无法进行 UDP 广播时设置为0。
sed -i 's#"udp_broadcast_port"[[:space:]]*:[^,]*#"udp_broadcast_port": 13014#' "$CONFIG_FILE"
# 设置为关闭,优先使用 IP 地址通信;若开启则使用主机名(hostname)通信,
sed -i 's#"server_comm_use_hostnames"[[:space:]]*:[^,]*#"server_comm_use_hostnames": false#' "$CONFIG_FILE"
# Web UI 只会连接 URL 中的 hostname/port,适合单服务器架构
sed -i 's#"web_direct_connect"[[:space:]]*:[^,]*#"web_direct_connect": false#' "$CONFIG_FILE"
# 设置为关闭,优先使用 IP 地址通信;若开启则使用主机名(hostname)通信,
sed -i 's#"web_socket_use_hostnames"[[:space:]]*:[^,]*#"web_socket_use_hostnames": false#' "$CONFIG_FILE"
# 禁用单个 Job 的最大内存限制, 默认值为 1073741824(1GB)(单位:字节),超过会被强制终止
sed -i 's#"job_memory_max"[[:space:]]*:[^,]*#"job_memory_max": 0#' "$CONFIG_FILE"
grep -E '"base_app_url"|"secret_key"|"job_data_expire_days"|"log_archive_path"|"http_port"|"udp_broadcast_port"|"server_comm_use_hostnames"|"web_direct_connect"|"web_socket_use_hostnames"|"job_memory_max"' "$CONFIG_FILE"
echo -e "\n[SUCCESS] Cronicle 安装完成!"
echo -e "\n运行以下脚本初始化存储系统。只需在主服务器(Master)上执行一次。不要在任何工作服务器(Worker)上运行:"
echo "${BASE_DIR}/bin/control.sh setup"二、Systemd 用户自启动配置
创建
~/.config/systemd/user/cronicle.service:mkdir -p ~/.config/systemd/user && cat > ~/.config/systemd/user/cronicle.service << EOF [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 Environment=PATH=$HOME/.local/share/pnpm/bin:/usr/local/bin:/usr/bin:/bin WorkingDirectory=/opt/cronicle Restart=always RestartSec=10 [Install] WantedBy=default.target EOF启动服务
systemctl --user daemon-reload systemctl --user enable --now cronicle # 启用并立即启动停止/重启服务
systemctl --user stop cronicle systemctl --user restart cronicle卸载服务
systemctl --user stop cronicle systemctl --user disable cronicle rm -f ~/.config/systemd/user/cronicle.service systemctl --user daemon-reload
三、Worker 部署步骤
按上述第二步已部署有一个运行正常的 Master(TCP 端口 13012, UDP 端口 13014),现在要部署 Worker:
1. 准备配置文件(关键步骤)
Worker 的 config.json必须与 Master 完全一致(除了个别网络参数),否则无法加入集群。
必须保持一致的参数:
secret_key:必须相同,这是集群的“密码”,不同则无法连接udp_broadcast_port:必须相同(13014)base_app_url:通常指向 Master 的地址(用于 Web 界面跳转)
2. 启动 Worker 的绝对禁忌⚠️
Worker 节点严禁执行 /opt/cronicle/bin/control.sh setup。setup命令会初始化新的存储库/数据库,导致它与 Master 数据不一致。
正确的启动命令:
# 执行
systemctl -user start cronicle