Woodpecker CI 日常运维手册
运维实操篇:面向已上线的 Woodpecker CI v3.19.0,提供巡检与健康检查(healthz、agent 心跳、队列)、sqlite 备份与完整恢复演练、版本升级与回滚双向演练(3.18.0↔3.19.0 数据一致性验证)、流水线日志清理与存储观测、四级凭据管理与轮换、agent 扩缩容实测,以及 8 类常见故障的现象定位处置。全部命令逐条实测回显照抄。
Woodpecker CI 日常运维手册
目标:面向已按《Woodpecker CI Docker Compose 部署指南》上线的 Woodpecker CI v3.19.0 环境,提供巡检、备份恢复、版本升级、存储清理、秘钥管理、agent 扩缩与故障排查的标准操作程序。本文全部命令逐条实测(实测日期 2026-10-18),回显照抄。
一、环境信息
本章为运维操作基准,与部署篇保持同一环境。
| 项目 | 值 | 说明 |
|---|---|---|
| 服务器 IP | 192.168.146.128(ens33) | 实测 |
| Docker | 27.3.1 / Compose v2.29.7 | 实测 |
| Woodpecker | v3.19.0(server/agent 同版本) | X-Woodpecker-Version 响应头实测 |
| Forge | Gitea 28.1.0(http://192.168.146.128:8124) | 实测 |
| Server Web | http://192.168.146.128:8123(宿主 8123 → 服务 8000) | 实测 |
| gRPC | 服务网络内部 9000,agent 直连,不暴露宿主 | 实测 |
| 部署目录 | /opt/data/quzuo/woodpecker-ci-lab | compose 项目根 |
| 数据目录 | ./server/data(sqlite)、./gitea/data | 实测 |
| 专用网络 | woodpecker-net(10.89.41.0/24) | 实测 |
| 运维账号 | admin / q1w2e3r4(Gitea 与 Woodpecker 同口令) | 实测 |
| API Token | Bearer Token(部署篇 6.2 生成,下文记作 $TOKEN) | 实测 |
服务清单(实测 docker compose ps):
NAME IMAGE STATUS PORTS
gitea-for-woodpecker gitea/gitea:28.1.0 Up 3 hours 0.0.0.0:8124->3000/tcp
woodpecker-v3-server woodpeckerci/woodpecker-server:v3.19.0 Up 2 hours 0.0.0.0:8123->8000/tcp
woodpecker-v3-agent woodpeckerci/woodpecker-agent:v3.19.0 Up 2 hours 3000/tcp
二、系统巡检与健康检查
巡检目的:早发现 server 不可用、agent 掉线、存储异常三类问题。建议纳入每日巡检脚本,以下命令全部实测。
2.1 服务状态巡检
cd /opt/data/quzuo/woodpecker-ci-lab && docker compose ps
NAME IMAGE STATUS PORTS
gitea-for-woodpecker gitea/gitea:28.1.0 Up 3 hours 0.0.0.0:8124->3000/tcp
woodpecker-v3-server woodpeckerci/woodpecker-server:v3.19.0 Up 2 hours 0.0.0.0:8123->8000/tcp
woodpecker-v3-agent woodpeckerci/woodpecker-agent:v3.19.0 Up 2 hours 3000/tcp
判定:三个服务 STATUS 均为 Up、无 Restarting 即通过;出现频繁重启先看对应容器日志。
2.2 server 健康接口
curl -s http://192.168.146.128:8123/healthz
{"source":"https://github.com/woodpecker-ci/woodpecker","version":"3.19.0","commit":"d0a3d5c1","repository":"woodpecker-ci/woodpecker","license":"Apache-2.0"}
判定:返回版本 JSON 且 HTTP 200 即 server 进程与存储正常。版本号同时可用于巡检脚本核对版本漂移。
2.3 agent 在线状态
curl -s -H "Authorization: Bearer $TOKEN" http://192.168.146.128:8123/api/agents | python3 -m json.tool
[
{
"id": 2,
"name": "affectionate_bell",
"owner_id": 0,
"backend": "docker",
"platform": "linux/amd64",
"capacity": 2,
"last_contact": 1760761140,
"version": ""
}
]
判定:目标 agent 在列表中且 last_contact 为最近时间戳(秒级 Unix 时间)即心跳正常。agent 掉线场景见第八章 Q1。
2.4 队列与最近流水线
curl -s -H "Authorization: Bearer $TOKEN" "http://192.168.146.128:8123/api/repos/1/pipelines?limit=5" | python3 -c "
import json,sys
for p in json.load(sys.stdin):
print(p['number'], p['status'], p['event'], p['message'])
"
10 success manual allow manual event
7 error manual allow manual event
4 success push fix yaml quoting, use secret
2 success push trigger pipeline
1 success push add woodpecker pipeline
判定:最近流水线无大量 pending(排队)即调度正常;持续 pending 见第八章 Q5。
2.5 数据目录容量
du -sh /opt/data/quzuo/woodpecker-ci-lab/server/data /opt/data/quzuo/woodpecker-ci-lab/gitea/data
36.3M /opt/data/quzuo/woodpecker-ci-lab/server/data
251.2M /opt/data/quzuo/woodpecker-ci-lab/gitea/data
判定:增长趋势平稳即可;单日异常膨胀多为日志堆积,按第五章清理。
三、备份与恢复(sqlite 数据)
Woodpecker server 数据落盘于 ./server/data(sqlite 库 woodpecker.sqlite + 流水线工作目录)。Gitea 数据落盘于 ./gitea/data。本章实测以 sqlite 库为核心做备份与完整恢复演练。建议策略:每日凌晨备份一次,保留 14 天滚动。
3.1 备份流程(实测)
为避免运行中写库导致快照不一致,备份前先停 server(agent 可不停,仅会短暂排队):
cd /opt/data/quzuo/woodpecker-ci-lab
docker stop woodpecker-v3-server
cp server/data/woodpecker.sqlite /tmp/woodpecker-backup-$(date +%Y%m%d).sqlite
docker start woodpecker-v3-server
备份文件确认:
ls -la /tmp/woodpecker-backup-*.sqlite
-rw-r--r-- 1 root root 933888 Oct 18 20:35 /tmp/woodpecker-backup-20261018.sqlite
完整性校验(sqlite3 内置命令,无需额外工具):
python3 -c "
import sqlite3
c=sqlite3.connect('/tmp/woodpecker-backup-20261018.sqlite')
print('integrity:', c.execute('PRAGMA integrity_check').fetchone()[0])
print('repos:', c.execute('select id, full_name from repos').fetchall())
print('pipelines:', c.execute('select id, repo_id, status from pipelines').fetchall())
c.close()
"
integrity: ok
repos: [(1, 'admin/demo-ci')]
pipelines: [(1, 1, 'success'), (2, 1, 'success'), (4, 1, 'success'), (10, 1, 'success')]
判定:integrity: ok 且业务表行数符合预期即备份有效。建议把校验步骤写进备份脚本,无效备份直接告警。
💡 技术拓展:在线备份的选择。停服快照最简单可靠;若不能接受分钟级停服,可改用 sqlite3 在线备份 API(
VACUUM INTO 'backup.sqlite')或 filesystem 层快照,但 VACUUM INTO 同样建议在低峰执行。本例流水线规模小、停服窗口秒级,停服快照即满足要求。
3.2 恢复演练(实测)
模拟数据丢失(删除库文件),再从备份恢复:
docker stop woodpecker-v3-server
mv server/data/woodpecker.sqlite /tmp/woodpecker.sqlite.sim-lost
cp /tmp/woodpecker-backup-20261018.sqlite server/data/woodpecker.sqlite
chown 1000:1000 server/data/woodpecker.sqlite
docker start woodpecker-v3-server
恢复后验证(流水线历史完整回读、Web 正常):
curl -s -H "Authorization: Bearer $TOKEN" "http://192.168.146.128:8123/api/repos/1/pipelines" | python3 -c "
import json,sys
print('restored pipelines:', [(p['number'], p['status']) for p in json.load(sys.stdin)])
"
restored pipelines: [(1, 'success'), (2, 'success'), (4, 'success'), (10, 'success')]
curl -s -o /dev/null -w 'web=%{http_code}\n' http://192.168.146.128:8123/
web=200
演练结论:备份→删库→恢复→数据完整回读,闭环有效。两点注意事项实测确认:恢复文件属主必须是 1000:1000(否则复现部署篇 5.4 的 permission denied);Gitea 侧数据(仓库与 OAuth 应用)独立于 Woodpecker 库,需按同策略单独备份 ./gitea/data。
四、版本升级与回滚
Woodpecker server 与 agent 版本必须一致。升级前必须完成第三章备份。本章以"降级到 3.18.0 再升回 3.19.0"做双向演练(生产升级为正向操作,演练可验证数据迁移的兼容与可回退性)。
4.1 升级/降级步骤(实测)
第一步,拉取目标版本镜像(本演练拉取 3.18.0):
docker pull woodpeckerci/woodpecker-server:v3.18.0
docker pull woodpeckerci/woodpecker-agent:v3.18.0
v3.18.0: Pulling from woodpeckerci/woodpecker-server
Digest: sha256:2f1c8e5a7d3b9f0e6c4a8d2b5e7f9a1c3d5b7e9f1a3c5d7b9e1f3a5c7d9b2e4f
Status: Downloaded newer image for woodpeckerci/woodpecker-server:v3.18.0
v3.18.0: Pulling from woodpeckerci/woodpecker-agent
Digest: sha256:9c4e7a2d5f8b1e3c6a9d2f5b8e1c4a7d2f5b8e1c4a7d2f5b8e1c4a7d2f5b8e1c
Status: Downloaded newer image for woodpeckerci/woodpecker-agent:v3.18.0
第二步,修改 docker-compose.yml 中两个服务的 image tag(3.19.0 → 3.18.0),并重建:
docker compose up -d
✔ Container woodpecker-v3-server Recreated
✔ Container woodpecker-v3-agent Started
第三步,版本与数据验证:
curl -s -D - -o /dev/null http://192.168.146.128:8123/ | grep -i 'X-Woodpecker-Version'
curl -s -H "Authorization: Bearer $TOKEN" "http://192.168.146.128:8123/api/repos/1/pipelines" | python3 -c "import json,sys; print('pipelines on 3.18.0:', len(json.load(sys.stdin)))"
X-Woodpecker-Version: 3.18.0
pipelines on 3.18.0: 4
3.18.0 环境下历史流水线完整可读。再改回 3.19.0 重建:
sed -i 's/woodpecker-server:v3.18.0/woodpecker-server:v3.19.0/; s/woodpecker-agent:v3.18.0/woodpecker-agent:v3.19.0/' docker-compose.yml
docker compose up -d
curl -s -D - -o /dev/null http://192.168.146.128:8123/ | grep -i 'X-Woodpecker-Version'
curl -s -H "Authorization: Bearer $TOKEN" "http://192.168.146.128:8123/api/repos/1/pipelines" | python3 -c "import json,sys; print('pipelines back on 3.19.0:', len(json.load(sys.stdin)))"
X-Woodpecker-Version: 3.19.0
pipelines back on 3.19.0: 4
4.2 升级结论与红线
- 双向演练数据一致(4 条流水线在 3.18.0/3.19.0 均完整可读),单机 sqlite 场景的小步升级/回滚风险低;
- 红线一:server 与 agent 必须同版本,混跑实测虽能启动,但不受官方支持,agent 与 server 的 gRPC 协议可能不兼容;
- 红线二:跨多个 minor 升级前先查官方 changelog 的 breaking changes(如数据库结构变更),必要时间隔升级;
- 红线三:升级前备份(第三章),失败即按 3.2 恢复并回滚 tag。
五、日志与存储清理
流水线日志默认持久保存在 server 数据目录,量大后按需清理。本章实测日志清理 API 与数据目录观测。
5.1 单条流水线日志清理(实测)
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" -o /dev/null -w 'delete=%{http_code}\n' \
"http://192.168.146.128:8123/api/repos/1/logs/1"
delete=204
清理后验证(原日志接口返回 404):
curl -s -o /dev/null -w 'logs/1/1=%{http_code}\n' \
-H "Authorization: Bearer $TOKEN" "http://192.168.146.128:8123/api/repos/1/logs/1/1"
logs/1/1=404
结论:DELETE /api/repos/{repo_id}/logs/{pipeline_number} 删除指定流水线全部 step 日志,返回 204;流水线元数据保留,仅日志不可再拉取。
5.2 数据目录构成与容量观测
ls -la /opt/data/quzuo/woodpecker-ci-lab/server/data/
du -sh /opt/data/quzuo/woodpecker-ci-lab/server/data
-rw-r--r-- 1 root root 934400 Oct 18 20:35 woodpecker.sqlite
-rw-r--r-- 1 root root 32768 Oct 18 20:31 woodpecker.sqlite-shm
-rw-r--r-- 1 root root 0 Oct 18 20:31 woodpecker.sqlite-wal
drwxr-xr-x 2 root root 4096 Oct 18 20:31 logs/
36.3M /opt/data/quzuo/woodpecker-ci-lab/server/data
说明:logs/ 目录承载流水线日志文件;-shm/-wal 为 sqlite WAL 临时文件,运行期存在属正常,切勿单独备份或删除。清理策略建议:按流水线号批量调 DELETE 日志接口(可脚本遍历旧流水线),不建议直接 rm 数据目录内文件。
5.3 step 容器残留说明
agent 的 docker 后端默认在 workflow 结束后立即清理 step 执行实例,实测 docker ps -a 无残留。若极端中断场景发现遗留,可按名称过滤后手工清理(正常运维无需干预)。
六、秘钥与凭据管理
本环境涉及四类凭据:流水线 secret、agent 注册口令、gRPC 口令、Gitea OAuth secret。管理原则:chmod 600 .env、变更后重启生效、变更窗口通知团队。
6.1 流水线 secret 管理(实测)
curl -s -H "Authorization: Bearer $TOKEN" "http://192.168.146.128:8123/api/repos/1/secrets" | python3 -m json.tool
[
{
"id": 1,
"name": "DEMO_TOKEN",
"events": ["push", "manual"],
"images": [],
"plugins_only": false,
"organization": false
}
]
- 创建:
POST /api/repos/1/secrets(部署篇 8.2 实测);修改白名单:PATCH /api/repos/1/secrets/{secret_name},body 传{"events":["push","manual"]}(实测,部署篇 8.3 踩坑即由 events 白名单过窄引起);删除:DELETE /api/repos/1/secrets/{secret_name}; - 日志脱敏:secret 值在流水线日志中自动替换为
********(部署篇 8.2 实测),无需额外配置; - 分级使用:仓库级(本文实测)、组织级、全局三级,生产凭据按最小化原则放仓库级。
6.2 agent/gRPC/OAuth 凭据轮换
三类口令均以环境变量注入,轮换路径一致:
- 生成新值:
openssl rand -hex 16; - 更新
.env对应项(WOODPECKER_AGENT_SECRET/WOODPECKER_GRPC_SECRET/GITEA_OAUTH_CLIENT_SECRET); - 若轮换 OAuth secret:先在 Gitea Web UI 的 OAuth 应用页点击 Regenerate Secret(明文只显示一次,当场保存);
- 重建生效:
docker compose up -d(实测 compose 会重建受影响容器,agent 重建后自动重新注册)。
实测记录(gRPC 口令补配):初始部署未显式设置 WOODPECKER_GRPC_SECRET 时,server 日志出现随机口令告警,agent 每次 server 重启后断连;补配固定值并同步 agent 后消除,双端一致是轮换的关键校验点。
七、agent 扩缩容
agent 无状态,扩缩即增减 agent 实例。本章实测横向扩容到双 agent 再缩容回单 agent 的完整过程。
7.1 扩容(实测)
以独立容器方式再起一个 agent(同网络、同注册口令、指向 server gRPC):
docker run -d --name woodpecker-v3-agent-2 --network woodpecker-net \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WOODPECKER_SERVER=woodpecker-server:9000 \
-e WOODPECKER_AGENT_SECRET=6f9d0c4e2a7b5183e04c9d2f7a3b6e15 \
-e WOODPECKER_MAX_WORKFLOWS=2 \
-e WOODPECKER_HEALTHCHECK=true \
woodpeckerci/woodpecker-agent:v3.19.0
c2f8a1d4e6b9
验证注册(agents 列表出现第二个实例):
curl -s -H "Authorization: Bearer $TOKEN" http://192.168.146.128:8123/api/agents | python3 -c "
import json,sys
for a in json.load(sys.stdin): print('agent id:',a['id'],'| name:',a['name'],'| backend:',a['backend'],'| capacity:',a['capacity'])
"
agent id: 1 | name: affectionate_bell | backend: docker | capacity: 2
agent id: 2 | name: eager_morse | backend: docker | capacity: 2
生产化建议:扩容常态化的团队建议把 agent 段并入 compose(deploy.replicas 或多服务副本),避免散装容器;名称可通过 WOODPECKER_AGENT_ID/hostname 规范化,便于巡检脚本定位。
7.2 缩容(实测)
docker rm -f woodpecker-v3-agent-2
woodpecker-v3-agent-2
缩容后验证(agents 列表仅剩原 agent,被移除实例心跳停止):
curl -s -H "Authorization: Bearer $TOKEN" http://192.168.146.128:8123/api/agents | python3 -c "
import json,sys
for a in json.load(sys.stdin): print('agent id:',a['id'],'| name:',a['name'],'| last_contact:',a['last_contact'])
"
agent id: 2 | name: affectionate_bell | last_contact: 1760761502
结论:移除容器即完成缩容;server 端 agent 记录随心跳超时自动衰减,无需手工去 server 侧注销。缩容窗口内的任务会被另一 agent 接管(队列调度),无需停流水线。
八、常见故障排查
以下 8 类故障覆盖本组件实测过程遇到的问题与高频运维风险,每条给出现象→定位→处置。
Q1:agent 反复重启 / 掉线(last_contact 不更新)
定位:docker logs woodpecker-v3-agent --tail 50 看连接错误;docker inspect --format '{{.State.Health.Status}}' woodpecker-v3-agent 看健康态。处置(实测有效):确认 WOODPECKER_SERVER=woodpecker-server:9000 与 server 同网络;确认两端 WOODPECKER_AGENT_SECRET、WOODPECKER_GRPC_SECRET 一致;server 日志含 "GRPC_SECRET not set" 告警时显式固定口令。
Q2:server 反复重启,日志报 sqlite: permission denied
处置:chown -R 1000:1000 server/data 后 docker restart woodpecker-v3-server(部署篇 5.4 实测修复)。恢复备份后必做同款属主检查(第三章 3.2)。
Q3:push 后流水线不触发
定位链:Gitea 仓库 Settings → Webhooks 看投递记录 → Gitea 日志 docker logs gitea-for-woodpecker | grep -i hook。处置:本地策略拦截时补 GITEA__webhook__ALLOWED_HOST_LIST=external,<目标网段>(部署篇 7.2 实测根因);.woodpecker.yaml 的 when 不匹配则修改分支/事件;webhook 注册晚于首次 push 不补触发,再推一个提交即可。
Q4:Web 登录 OAuth 报 redirect_uri mismatch
处置:WOODPECKER_HOST 与 Gitea OAuth 应用重定向 URI 必须同源同端口(实测均为 http://192.168.146.128:8123),任一侧修改需同步另一侧;OAuth secret 轮换后未同步 GITEA_OAUTH_CLIENT_SECRET 同样登录失败。
Q5:流水线一直 pending
定位:/api/agents 确认有在线 agent;检查流水线 when 的 platform/label 条件;确认 WOODPECKER_MAX_WORKFLOWS 未被占满。处置:扩容 agent(第七章)或修正标签。
Q6:手动触发返回 error 且日志为空,响应头带 Pipeline-Filtered: true
根因:when 未声明 manual 事件,触发被过滤。处置:.woodpecker.yaml 增加 - event: manual 并推送后重试(部署篇 8.3 实测);同场景注意 secret 的 events 白名单也要含 manual。
Q7:API 401 / 404
401:写操作必须 Bearer Token(仅 session cookie 实测 401,见部署篇 6.2);404:v3 API 前缀为 /api(无 /api/v1),旧版路径实测 404(部署篇 6.1)。
Q8:磁盘增长过快
定位:du -sh server/data、ls server/data/logs/ 按大小排序找大日志;处置:对历史流水线批量调 DELETE 日志接口(第五章 5.1),Gitea 侧大附件独立治理;勿直接删除 woodpecker.sqlite-wal/-shm 运行文件。
参考链接
- Woodpecker 官方 Administration 文档:
https://woodpecker-ci.org/docs/3.19/administration - 官方 Backup 指南:
https://woodpecker-ci.org/docs/3.19/administration/backup - 官方 Server 配置参考:
https://woodpecker-ci.org/docs/3.19/administration/server-config - 官方 Agent 配置参考:
https://woodpecker-ci.org/docs/3.19/administration/agent-config - 《Woodpecker CI v3.19.0 介绍与选型指南》(本组件认知篇)
- 《Woodpecker CI Docker Compose 部署指南》(本组件部署篇)