MeshNook技术与生活的角落

2026.10.07 · 3 分钟阅读

博客发布工作流

目录

发布博客的工作流思路:

编辑 Markdown,提交源码
          ↓
推送到本地 Gitea
          ↓
本地 Runner 自动构建 Hugo
          ↓
Wrangler 上传 public/ 到 Cloudflare Pages
          ↓
Blog Web

先从日志定位耗时

最初工作流在每次任务中准备 Node.js、下载 Hugo,并通过 npx --yes wrangler@4 上传网站。一次成功部署的步骤耗时如下:

步骤耗时
准备任务容器2 秒
拉取源码不足 1 秒
准备 Node.js1 秒
安装 Hugo Extended5 秒
Hugo 构建不足 1 秒
安装 Wrangler 并部署1 分 41 秒

展开部署日志后,关键结果是:

Uploaded 11 files (64 already uploaded) (7.33 sec)

这说明本次部署共检查 75 个文件,其中 64 个已经存在,只上传了 11 个文件。Hugo 每次生成完整网站,Cloudflare 上传阶段则复用内容相同的资源。修改一篇文章还可能影响首页、分页、RSS 和站点地图,因此变动文件数量不一定等于修改的文章数量。

真正的文件上传只用了 7.33 秒。部署步骤剩余的时间还包括 Wrangler 下载与启动、接口请求和创建部署。由于当时日志没有逐行时间戳,不能把剩余时间全部归因于 npm 安装。

Hugo 构建已经很快,因此继续保留全量构建,确保文章删除、分页和索引都能同步更新。

第一次优化:固定版本并尝试缓存

先把 Wrangler 固定到已验证的 4.148.0,将安装和发布拆成独立步骤,再使用 Actions 缓存保存 .ci-tools 中的安装结果。预期是首次下载,后续恢复缓存并跳过安装。

实际运行时,缓存恢复和保存都出现了连接超时:

Failed to restore: getCacheEntry failed: Request timeout
Failed to save: reserveCache failed: Request timeout

恢复缓存耗时约 20 秒,任务结束时保存缓存又等待了约 1 分钟。缓存没有带来提速,反而增加了等待时间。

Docker Runner 与它创建的任务容器可能位于不同网络。缓存服务需要被任务容器访问,必须配合检查 cache.host、cache.port 和端口映射。只在工作流里添加缓存步骤,并不能保证缓存可用。

这次配置尚未确定具体网络阻断点,因此先移除了缓存。continue-on-error 可以让失败步骤继续执行,但不能消除连接超时,也不能阻止缓存 Action 在任务结束时尝试保存。

第二次优化:预装构建工具

将重复安装移到镜像构建阶段,制作专用于博客发布的镜像:

工具版本
基础镜像node:22-bookworm-slim
Hugo Extended0.167.0
Wrangler4.148.0

Dockerfile 同时安装 Git、curl 和证书等工具,下载 Hugo 后校验 SHA-256。镜像不包含博客文章或发布凭据;Cloudflare Token 仍由 Gitea Secrets 在部署步骤注入。

在 Runner 所在的 Debian 虚拟机上准备 Dockerfile,并在其目录中执行:

docker build --pull \
  -t meshnook-blog-builder:hugo0.167.0-wrangler4.148.0-node22 .

构建完成后验证工具:

docker run --rm \
  meshnook-blog-builder:hugo0.167.0-wrangler4.148.0-node22 \
  bash -c 'node --version && hugo version && WRANGLER_SEND_METRICS=false wrangler --version'

Runner 挂载宿主机的 /var/run/docker.sock,所以任务使用的是宿主机 Docker。镜像构建在同一台 Debian 上后,Runner 可以直接使用,无需上传镜像仓库,也无需在 Compose 中增加一个长期运行的构建服务。

在现有 Runner 的 Compose 配置中增加专用标签:

GITEA_RUNNER_LABELS: "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest,meshnook-blog:docker://meshnook-blog-builder:hugo0.167.0-wrangler4.148.0-node22"

重新创建 Runner,让环境变量生效:

docker compose up -d --force-recreate runner

确认 Gitea 页面显示 meshnook-blog 标签后,将工作流设置为:

runs-on: meshnook-blog

本地镜像要求 Runner 的 container.force_pull 为 false。清理 Docker 镜像时也要保留这个镜像,否则任务会尝试从远程拉取一个未发布的镜像。

优化后的发布流程

准备阶段:构建工具镜像 → 配置 Runner 标签
                         ↓
日常发帖:编辑 Markdown → 推送 main
                         ↓
                启动预装工具的任务容器
                         ↓
                拉取源码 → Hugo 全量构建
                         ↓
                Wrangler 检查并上传变动资源
                         ↓
                Cloudflare Pages 创建部署

新版工作流保留工具版本检查、Hugo 构建和 Cloudflare 发布,移除了每次任务中的工具安装和不可用的缓存步骤。

预期收益是省去重复下载与安装。镜像第一次构建仍需要网络,日常发布也仍需要访问 Gitea、Action 来源和 Cloudflare。优化后的实际总耗时还需以新的 Actions 日志为准,目前没有记录可对比的最终测量结果。

后续升级工具时,重新构建并使用新的镜像标签,同时更新 Runner 标签。这样工具准备与文章发布分开维护,日常发帖只需要提交并推送内容。