切换主题
执行机、部署节点与集群
本文档介绍 CICD 自动打包部署平台的执行端接入模型、选机规则、部署节点(免 SSH)链路与管理端多实例集群。构建与部署流程本身见 构建与部署,环境资源见 环境资源,多实例集群的选主与派发见 系统与集群。
平台不引入 Kubernetes / 消息中间件,执行端只需能出站访问管理端即可接入,全部协调都落在 MySQL:
| 角色 | 进程 | 部署位置 | 职责 |
|---|---|---|---|
| 管理端 | cicd_server | 中心服务器 | 配置、派发、日志、产物归档、通知、Webhook、集群协调 |
| 执行机 | cicd_agent | 构建机器 | 取码、打包、上传产物、SSH 部署(mode=ssh) |
| 部署节点 | cicd_node | 目标服务器 | 在本机落地产物并启停服务(mode=node,目标机免 SSH) |
执行机与部署节点共用同一套接入链路(同一张表、同一套注册 / 心跳 / 长轮询 / 日志上报),靠字段 kind ∈ {agent, node} 区分角色。
执行机(agent)
主动连接与令牌鉴权
执行机不监听任何端口,启动后主动向管理端发起连接:
| 项 | 说明 |
|---|---|
| 鉴权头 | X-Agent-Token: <明文令牌> |
| 双重校验 | 除请求头外,报文体 / 查询参数中的 agentId 必须与令牌对应记录一致,否则 403 令牌与执行机不匹配(令牌泄露也无法冒用其它执行机身份) |
| 令牌存储 | 管理端新建 / 重置时返回一次性明文,库中 agent.token_hash 只存 SHA-256,泄露库文件也无法反推 |
| 重置令牌 | POST /api/agents/:id/token,旧令牌立即失效;执行端需同步修改 agent/config.yaml 的 server.token 并重启 |
| 禁用 | 管理端禁用后,该令牌的所有执行端接口返回 403 执行机已被禁用 |
注册、心跳与在线判定
| 项 | 说明 |
|---|---|
| 注册 | POST /api/agent/register,每次启动(含重启)都会刷新主机名、IP、OS、架构、版本、标签、并发上限与本机配置 |
| 上报配置 | workspaceRoot / gitKeyRoot(作为顶层字段)以及 workDir、workspaceTtlDays、gitKeyType、gitPath、gitCloneDepth、javaHome、mavenPath、nodePath、npmPath、dockerPath(config 对象,供管理端只读展示) |
| IP 取值 | 优先 agent.ip(配置项),缺失时管理端退回请求来源地址 |
| 注册响应 | {agentId, heartbeatSeconds, commandWaitSeconds, offlineTimeoutSeconds, serverTime},执行端按此调整心跳与长轮询节奏 |
| 重启中断 | 注册时上报 runningTasks;不在该列表中的历史「运行中」任务会被置为失败,原因「执行端重启中断」 |
| 心跳 | POST /api/agent/heartbeat,间隔 agent.heartbeatSeconds(默认 10s),上报当前运行中的任务 ID;响应下发需要取消的任务列表(canceled) |
| 在线判定 | 最后心跳在 agent.heartbeatTimeoutSeconds(默认 30s)内视为在线,超过即离线;该值同时通过注册响应下发给执行端 |
| 离线收敛 | 后台巡检每 5s 扫描一次,把超时未心跳的执行机状态置为离线 |
执行机离线不会让排队任务失败:候选机全部离线时任务留在队列并记 queue_reason=agent_offline,该机恢复心跳后自动派发;其它在线候选机可先行取走任务。
指令下行:长轮询
指令(任务派发、探测、密钥轮换、清理工作目录等)统一下行,执行端无 WebSocket 依赖:
| 项 | 说明 |
|---|---|
| 接口 | GET /api/agent/commands?agentId=<id> |
| 挂起时长 | agent.commandWaitSeconds(默认 25s);可用查询参数 wait 临时覆盖(1–60s) |
| 无指令 | 返回 204,执行端视为空结果(非错误),立即重新发起下一次长轮询 |
| 单次上限 | 一次最多领取 10 条指令(commandClaimBatch) |
| 内部重查 | 即使管理端内存唤醒未命中,也会每 5s 重查一次数据库(commandPollSlice),保证多实例下不丢指令 |
| 指令确认 | 执行端处理后调 POST /api/agent/commands/:id/ack 上报 acked / rejected |
| 指令超时 | 未处理指令超过 agent.commandExpireMinutes(默认 10 分钟)由巡检回收 |
容量 capacity 与并发
agent.capacity是单机可同时执行的任务数(默认 1,管理端新建表单限制 1–50)。- 派发时要求
已派发任务数 < capacity,超出则该机不参与本次选机。 - 该值以执行端配置为准:每次注册都会用上报值刷新管理端记录,因此在管理端列表里临时调整的并发上限会在执行端下次注册时被覆盖。
- 部署节点(
kind=node)的容量固定为 1——同一时刻只处理一个落地方案。
Git 密钥:自建与公钥
执行机在首次注册前调用 ensureGitKey 自建密钥对,私钥永不上报、永不入库:
| 项 | 说明 |
|---|---|
| 算法 | ssh-ed25519(默认)或 ssh-rsa(RSA 4096),由 agent.gitKeyType 决定 |
| 文件权限 | 私钥 0600、密钥目录 0700;文件名 id_ed25519 / id_rsa |
| 存放位置 | 密钥根 agent.gitKeyRoot;执行机级 {gitKeyRoot}/agent,项目级 {gitKeyRoot}/projects/{项目ID} |
| 上报内容 | 仅公钥、指纹、算法、密钥备注、本机路径 |
| 首次缺密钥 | 若未提前配置,取码阶段会自动生成并上报,任务以「请先配置公钥」的明确原因失败 |
| 轮换 | 「轮换密钥」下发 rotate_key 指令,执行端生成新密钥对覆盖本地并上报新公钥;旧公钥需到 Git 平台手动删除(系统无法代删) |
| 吊销 | 把记录置 revoked,之后该范围的取码立即拒绝使用 |
取码命令(HTTPS 凭据不写入命令行与日志,必要时通过临时 GIT_ASKPASS 脚本提供):
bash
GIT_SSH_COMMAND='ssh -i {keyPath} -o IdentitiesOnly=yes \
-o StrictHostKeyChecking=accept-new -o UserKnownHostsFile={gitKeyRoot}/known_hosts'1
2
2
构建环境探测
管理端「探测」按钮下发 probe 指令(kind=env)并同步等待结果(默认 45s 超时,agent.probeTimeoutSeconds):
| 探测项 | 命令 | 说明 |
|---|---|---|
jdk | java -version | Java 构建 |
go | go version | Go 构建 |
node / npm | node -v / npm -v | 前端构建 |
docker | docker version | 镜像构建 / 交付 |
hbuilderx | cli ver | App 云打包(路径取 hbuilderxPath,命中安装目录下的 cli / cli.exe) |
git | git version | 取码 |
- 执行端单项探测超时 30s;路径类配置(
javaHome/mavenPath等)为文件时直接用、为目录时在其下查找、为命令名时走PATH。 - 结论文案:全部通过为「环境已就绪」;否则提示「部分环境未就绪,请在项目配置中选择对应的环境资源」。
- 另有
git_probe(git ls-remote --heads --tags,用于项目「测试连接 / 获取分支」)、ssh、ls等探测类型。
工作目录与缓存
| 层级 | 取值 |
|---|---|
| 工作目录根 | 执行端 agent.workspaceRoot(可绝对 / 相对路径,相对路径按 config.yaml 所在目录解析) |
| 项目仓库目录 | {workspaceRoot}/{项目ID}——目录名固定为项目 ID,不取项目名,天然避免同名冲突 |
| 步骤构建目录 | {repoDir}/{步骤.subDir}(subDir 为空即仓库根,用于 monorepo) |
缓存策略由项目配置 git.cache 控制:
git.cache | 任务开始前 | 任务结束后 | 适用场景 |
|---|---|---|---|
true(默认) | 目录存在 → fetch + checkout + reset(增量);不存在 → clone | 保留 repoDir | 复用 node_modules、target/ 等依赖缓存 |
false | 存在残留目录 → 先整体删除,再 clone | 删除 repoDir | 磁盘紧张、要求每次全新环境 |
工作目录清理
| 方式 | 触发 | 说明 |
|---|---|---|
| 手动清理 | 执行机列表「清理目录」→ POST /api/agents/:id/workspaces/clean,{projectId} 指定项目或 {all:true} 全部 | 下发 clean_workspace 指令,执行端回报释放的字节数与目录数;清理后依赖与构建产物需重新拉取 |
| 兜底清理 | agent.workspaceTtlDays > 0 | 执行端启动后每天扫描 workspaceRoot,删除超过该天数未被任何任务使用的项目目录;默认 0 表示不自动清理 |
清理范围仅限 {workspaceRoot}/{项目ID},不影响 ~/.m2、npm 全局缓存、Docker 镜像层等执行机级缓存。
执行机管理
页面路径 /agents(执行机,仅 admin),同页下方含「部署节点」区。列表展示状态、名称、运行信息(主机名 / IP / OS / 架构 / 版本)、标签、工作目录、并发(runningTasks / capacity)、最后心跳,行内操作:Git 密钥、探测、清理目录、重置令牌、编辑、删除(页面每 5s 自动刷新状态)。
| 接口 | 说明 |
|---|---|
GET /api/agents | 列表(含当前任务数) |
POST /api/agents | 新建并返回一次性 Token |
PUT /api/agents/:id | 改名、标签、并发上限、启用/禁用(重新启用后先置离线,等心跳恢复在线) |
POST /api/agents/:id/token | 重置令牌 |
DELETE /api/agents/:id | 存在排队 / 运行中任务或被环境资源关联时返回 409 |
POST /api/agents/:id/probe | 环境探测(同步等待) |
GET /api/agents/:id/keys | Git 公钥列表 |
POST /api/agents/:id/keys/rotate | 轮换密钥 {scope: agent|project, projectId?} |
POST /api/agents/:id/keys/:keyId/revoke | 吊销公钥 |
POST /api/agents/:id/workspaces/clean | 清理工作目录 |
标签不参与调度
执行机标签仅作标识用途(便于人工识别与筛选),不参与任务调度——执行机由项目引用的环境资源自动匹配,见下文。
执行机与项目的匹配规则
项目不绑定执行机,只由各构建步骤引用环境资源(如 steps[].jdkId / steps[].nodeId / steps[].dockerId),一套资源可关联多台执行机。派发时的选机规则:
| 规则 | 说明 |
|---|---|
| 候选交集 | 依次取项目引用资源各自关联的执行机集合,求交集;未引用任何资源时不做限制(全部执行机) |
| 交集为空 | 说明没有任何执行机能同时满足所有资源要求,任务直接失败并给出明确原因 |
| 最闲优先 | 在「在线且已派发任务数 < capacity」的候选机中,选已派发任务数最少者,相同则 ID 最小 |
| 同项目串行 | 同一项目同时只允许一个未结束任务(工作目录是独占资源),已有则本次排队并记 project_running |
| 并发上限 | 单项目排队任务数受 agent.queueLimit(默认 50)约束,超出返回 409 |
| 排队依据 | 队列以 task.status='queued' 为唯一依据,按 priority DESC, queue_seq ASC 出队 |
排队原因(queue_reason):agent_busy(候选机均满载)、project_running(同项目在跑)、agent_offline(候选机全部离线)。
部署节点(node)
定位
部分目标服务器不允许开放 SSH,或不希望平台持有 SSH 凭据。此时在目标机上安装常驻服务 cicd_node,由它主动注册到管理端并长轮询取指令;执行机只负责打包并把产物上传到管理端,落地与启停交给节点在本机完成。
| 维度 | 说明 |
|---|---|
| 数据模型 | 与执行机同表(kind=node),注册 / 心跳 / 长轮询 / 日志上报链路完全复用,令牌与重置逻辑一致 |
| 目标机连接方式 | target_server.mode ∈ {ssh, node}(默认 ssh);mode=node 时 node_id 必填并指向 kind=node 的记录,SSH 凭据字段被清空 |
| 绑定关系 | 一个节点可被多台目标机绑定 |
| 兼容性 | mode=ssh 链路完全不变,两套模式并存 |
注册与令牌
- 管理端「执行机 → 部署节点」区新建节点,得到一次性 Token;
- 在目标服务器放置
cicd_node与node/config.yaml,把 Token 填入server.token; - 启动节点服务,它以
kind=node注册(上报主机名 / IP / OS / 架构 / 版本 / 标签与workDir/tempDir),此后与执行机一样心跳与长轮询; - 目标服务器的「连接方式」选为「部署节点」并绑定该节点。
| 项 | 说明 |
|---|---|
| 指令支持 | 仅 run_deploy;收到其它指令一律回 rejected(「部署节点不支持该指令」) |
| 容量 | 固定为 1,同一时刻只处理一个落地方案 |
| IP | node.ip,留空由节点探测本机对外 IPv4 |
| 结果上报 | POST /api/agent/deploy/result,携带 {taskId, commandId, phase, ok, message, artifacts, durationMs} |
| 删除节点 | 仍被目标机绑定时返回 409,必须先解除目标机绑定再删除 |
| 重置令牌 | POST /api/nodes/:id/token,旧令牌立即失效,需同步更新目标机 node/config.yaml 的 server.token 并重启节点服务 |
node/config.yaml 关键项
yaml
server:
url: "http://127.0.0.1:9866" # 管理端地址
token: "" # 管理端「部署节点」新建后复制的一次性令牌
insecureSkipVerify: false # 管理端 HTTPS 自签证书时置 true
timeoutSeconds: 30
node:
name: "app-01" # 节点名称,建议与管理端一致
ip: "" # 本机对外 IP,留空自动探测
labels: [] # 仅作标识
heartbeatSeconds: 10 # 心跳间隔
workDir: "work" # 落地根目录
tempDir: "" # 临时目录,留空取 {workDir}/tmp1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
免 SSH 的中转部署链路
链路的核心是执行端编排 + 管理端中转:节点不直连执行机,两端都不监听端口。
| 要点 | 说明 |
|---|---|
| 编排方 | 执行端编排:执行机在 upload / deploy / start 阶段分别发起阻塞中转,节点只执行被点名的那一个阶段;任务状态机、进度与产物明细统一由执行机上报 |
| 中转序号 | 镜像归档固定占 0(RelayImageSeq),部署条目从 1 开始按解析顺序递增(RelayEntrySeq(i) = i+1) |
| 产物传输 | 执行机 → 管理端 → 节点按 URL 拉取;下载响应跳过 gzip 中间件 |
| 暂存目录对齐 | 两侧都用 {stage}/{seq}-{条目名} 生成暂存目录,节点解包到同一相对结构,从而复用同一套落地逻辑 |
| 归档与暂存隔离 | 下载的 tar.gz 落在暂存目录之外(download-{seq}.tar.gz),避免被误当产物再次上传 |
| 日志序号连续 | 节点日志 seq 由管理端按任务当前最大序号分配(取「已落库最大序号」与「执行机上报的当前计数」较大者),节点从该值 +1 起计数,执行机收到结果后抬升自身计数;写入用 INSERT IGNORE 兜底。节点在上报结果前先冲掉缓冲日志,避免结果返回后仍有日志后到而撞号 |
| 进度反馈 | 上传阶段由执行机逐条目回报字节进度,折算到任务进度条的 upload 区间(25–45),详情「说明」形如「正在上传「app.jar」(12.34 MB / 17.22 MB,71%,1.18 MB/s)」,并按约 3 秒节流写入任务日志;节点拉取阶段由节点按同样文案写入任务日志(节点不参与任务进度百分比上报,进度条仍由执行机按阶段区间控制) |
| 阻塞超时 | 执行机等待节点完成单个阶段的超时 agent.relayTimeoutSeconds(默认 600s) |
| 中转清理 | 中转产物按 agent.relayRetentionMinutes(默认 180 分钟)由巡检删除,任务结束也会触发清理 |
| 落盘位置 | agent.relayDir(默认 work/relay);storage.relay=s3 时改存对象存储,节点按 URL 拉取 |
管理端集群(多实例)
管理端支持多实例部署(水平扩容 + 滚动发布不中断),协调全部借助 MySQL 自身能力(租约表 + 命名锁),不引入 Redis / etcd。
前提
- 各实例共享同一 MySQL;
auth.jwtSecret与auth.encryptKey各实例完全一致(建议用CICD_JWT_SECRET/CICD_ENCRYPT_KEY注入),否则 A 实例签发的 Token 在 B 实例校验失败、凭据无法解密;- 产物存储改为对象存储(
storage.artifact/storage.relay=s3),否则跨实例下载会 404; - 无需会话粘滞——登录态是无状态 JWT,长轮询与 SSE 均走数据库。
负载均衡的健康检查请用 GET /api/ready(就绪探针,DB 不可用或正在退出时 503),不要用 /api/health(存活探针恒 200)。停服会先摘流等待 5s 再关闭。
领导者选举(MySQL 租约)
cluster_leader 单行租约表(name 主键固定 cicd-manager、holder 实例标识、expire_at 到期时间):
- 竞选:
INSERT IGNORE建行(holder=''且已过期视为无人持有)→ 条件UPDATE ... WHERE name=? AND (expire_at < NOW() OR holder=?)抢占或续期 → 回读holder判定归属; - 续期:后台协程按租约 1/3 周期续期(
cluster.leaseSeconds,默认 30s),进程异常退出到其它实例接管的空窗不超过一个租约时长; - 让位:
Stop()时释放租约,滚动发布可立即接管; - 角色变化打印日志(获得 / 失去租约 / 降级);
- 降级容错:
cluster_leader表缺失(MySQL 1146)时退化为单实例模式(本实例永久自认为领导者)并打警告,而非启动失败;其它 DB 错误(如瞬断)保持当前角色不变,避免脑裂。
单写者
「任务派发 + 后台巡检」全局只有一份在执行:dispatcher 的派发循环与巡检循环在非领导者实例上空转跳过,入队后的立即派发交由领导者周期(约 1s)接管。
单写者解决的问题:派发判定「先读项目 / 执行机计数,再抢占任务」不是原子的,多实例并行会突破「同项目串行」与执行机 capacity;巡检多实例各跑一遍会重复下发指令与重复通知。
同步指令结果落库 + 等待方轮询
同步指令(探测、密钥轮换、工作目录清理、部署中转)与执行端上报结果是两个独立 HTTP 请求,负载均衡可能分到不同实例:
- 管理端下发指令(落库
agent_command)→ 轮询GetCommandResult(commandID)(间隔 250ms)直到有结果或超时; - 执行端上报结果 → 写回同一行的
result/result_at。
结果以原始 JSON 通透存放,各调用方自行解析为对应协议结构。
天然集群安全项
以下本就以 MySQL 为唯一真相,多实例安全,无需改动:任务队列(task.status='queued' + 条件 UPDATE 抢占)、指令领取(SELECT ... FOR UPDATE)、SSE(DB 轮询推送)、登录态(无状态 JWT)、前端资源(go:embed)、审计与投递记录(纯落库)。
而「先查后写」类判定(登录失败计数、队列上限、Webhook 限流 / 防抖 / 队列策略 skip)已在存储层用事务行锁 / MySQL 命名锁修复:
| 场景 | 处理 | 命名锁 |
|---|---|---|
| 队列上限 TOCTOU | CreateTaskWithQueueLimit:判断 + 入队整体在命名锁内完成,超限返回 ErrQueueFull(HTTP 409) | cicd:queue_limit |
| Webhook 限流 / 防抖 / 队列策略 skip | 判定与建任务、留痕整段放进项目级命名锁,锁等待超时返回 429 | cicd:hook:<projectId> |
| 登录失败计数 | 事务内 SELECT ... FOR UPDATE 读改写,避免并发丢更新绕过账号锁定 | 行锁 |
命名锁约定:GET_LOCK(name, 5) 获取、必须在持有连接上显式 RELEASE_LOCK 释放(释放用独立 context)。
已知降级项
| 项 | 多实例下的表现 | 兜底 |
|---|---|---|
hub.Hub 唤醒仅本进程 | 指令落库后的即时唤醒只作用于写入所在实例 | 执行端长轮询自带 5s 重查,仅增加下发时延 |
| 数据权限本地缓存(默认关闭) | 仅当显式配置 auth.scopeCacheSeconds > 0 时存在:授权变更后最长该秒数其它实例才生效 | 默认 0 不缓存,撤权即时生效 |
queue_seq 用 MAX()+1 | 同项目并发入队可能撞号 | 仅影响排序稳定性,不影响正确性 |
| 日志输出本机文件 | 排障需逐实例查看 | 日志 serviceName 携带端口 + 进程号便于区分实例 |
| 无配置热加载 | 改配置需重启实例 | 滚动发布 |
cluster 配置
yaml
cluster:
leaseSeconds: 30 # 领导者租约时长(秒),本实例按 1/3 续期;<=0 按 30s
instanceId: '' # 实例标识(租约 holder 与实例注册用);留空用「主机名-IP-端口」派生,重启不变
ip: '' # 本实例对外 IP(注册展示 + 参与标识派生);留空自动探测本机对外 IPv41
2
3
4
2
3
4
- 实例标识必须全局唯一;留空时由**「主机名-IP-端口」**派生(IP 取
cluster.ip,未配置时自动探测)。标识里带 IP 是为了让「主机名相同的不同机器」也能区分开——同名同端口会共用同一个 holder,导致多实例都自认为领导者。 - IP 变化(DHCP 续租、容器重建、弹性 IP 漂移)等同于换了一个实例:旧记录残留为「离线实例」(5 分钟后清理)、租约 holder 漂移。K8s / DHCP 等 IP 不稳定的环境请用
cluster.instanceId显式指定稳定标识(如node-1)。 - 集群告警渠道不在配置文件里,属于运行期运维设置,在「系统 → 集群」页维护,改完即时生效、无需重启。
系统 → 集群
页面路径 /cluster(仅 admin),后端 GET /api/cluster,每 5s 自动刷新。数据来自实例心跳与租约表:
- 各实例每 10s 注册一次心跳(标识、主机名、IP、端口、版本、角色);
- 在线:最后心跳在 30s 内;离线:超 30s,记录保留 5 分钟后由心跳协程清理(每 1 分钟检查一次);
- 领导者:实例标识等于租约
holder且租约未过期(以租约实时校正,不受心跳快照滞后影响)。
页面展示:部署模式(单实例 / 集群 / 单实例降级)、在线实例数、本实例标识与是否为领导者、领导者实例与租约剩余秒数、实例表格(标识、主机名、IP:端口、版本、角色、在线状态、启动时间、最后心跳)。租约表缺失(降级)时页顶给出警告并说明后果。
集群告警渠道在页面下半部分维护(多选通知渠道 + 保存,落 cluster_setting.alert_channel_ids,接口 PUT /api/cluster/settings,仅 admin):领导者切换(接任 / 失去租约 / 降级)与实例掉线(仅领导者判定,同一离线片段只告警一次)时向所选渠道发送告警;不选渠道则只写日志。通用 Webhook 渠道不可选——集群告警正文是纯文本,而 Webhook 渠道要求请求体是合法 JSON,前端下拉已过滤、后端保存时同样拒绝。渠道在 通知 页维护。
管理端相关配置
管理端 config.yaml 的 agent 段决定执行端交互节奏(server.baseUrl 见 配置说明):
| 配置项 | 默认 | 说明 |
|---|---|---|
agent.heartbeatTimeoutSeconds | 30 | 心跳超时,超过视为离线;通过注册响应下发 |
agent.commandWaitSeconds | 25 | 长轮询挂起时长 |
agent.commandExpireMinutes | 10 | 未确认指令的过期时间 |
agent.probeTimeoutSeconds | 45 | 管理端同步等待探测 / 轮换 / 清理结果的超时 |
agent.dispatchIntervalSeconds | 1 | 派发扫描间隔 |
agent.dispatchBatchSize | 50 | 单轮派发上限 |
agent.queueLimit | 50 | 单项目排队任务上限,超出返回 409 |
agent.taskRetentionDays | 30 | 任务与日志保留天数 |
agent.relayDir | work/relay | 部署中转产物落盘根目录(storage.relay=s3 时不使用) |
agent.relayTimeoutSeconds | 600 | 执行机等待节点完成单个阶段的超时 |
agent.relayRetentionMinutes | 180 | 中转产物保留时长 |
执行机配置(agent/config.yaml)
| 配置项 | 默认 | 说明 |
|---|---|---|
server.url | http://127.0.0.1:9866 | 管理端地址(必填) |
server.token | — | 接入令牌(必填),管理端新建 / 重置后复制 |
server.insecureSkipVerify | false | 管理端用 HTTPS 自签证书时置 true |
server.timeoutSeconds | 30 | 普通请求超时;长轮询自动放宽 |
agent.name | 主机名 | 执行机名称,建议与管理端一致 |
agent.ip | 自动探测 | 上报给管理端展示的本机 IP |
agent.labels | 空 | 标识标签,不参与调度 |
agent.capacity | 1 | 单机最大并发任务数 |
agent.heartbeatSeconds | 10 | 心跳间隔 |
agent.workDir | work | 构建产物与临时归档目录 |
agent.workspaceRoot | workspace | 项目工作目录根(每个项目一个以项目 ID 命名的子目录) |
agent.workspaceTtlDays | 0 | 工作目录兜底清理天数,0 表示不自动清理 |
agent.gitKeyRoot | gitkeys | Git 密钥与 known_hosts 存放根目录 |
agent.gitKeyType | ssh-ed25519 | 自建密钥算法:ssh-ed25519 或 ssh-rsa |
agent.gitPath | git | git 可执行文件 |
agent.gitCloneDepth | 1 | 默认浅克隆深度,0 表示完整克隆 |
agent.javaHome / mavenPath / goPath / nodePath / npmPath / dockerPath / hbuilderxPath | 空 | 本机环境默认值,供探测与兜底(hbuilderxPath 为 HBuilderX 安装目录,供 App 云打包定位 cli) |
agent.maxLogLineBytes | 8192 | 单行日志截断上限 |
log.level / log.max-size / log.max-backups / log.max-age | info / 64 / 7 / 30 | 本地日志输出到 logs/app.log(部署形态为程序目录) |
相对路径按配置文件所在目录解析
workDir / workspaceRoot / gitKeyRoot 等相对路径都相对 config.yaml 所在目录解析(而非进程工作目录),并用绝对路径部署可避免歧义。