静态站点自动部署实战

1. 整体架构

本文记录个人技术博客 sre-doc 的自动部署方案:本地撰写 Markdown,手工转为 HTML,推送到 GitHub main 分支后,由 GitHub Actions 自动触发 Cloudflare Pages 部署,实现线上站点更新。

整体数据流如下:

本地撰写 Markdown
    ↓
手工转换为 HTML
    ↓
更新首页 index.html + search-index.js
    ↓
git push origin main
    ↓
GitHub Actions 自动触发
    ↓
cloudflare/wrangler-action@v3
    ↓
Cloudflare Pages 线上站点更新

💡 核心思路:整个站点是纯静态 HTML,无需任何后端构建步骤。GitHub Actions 只做"推送触发 + 调用 Cloudflare API"两件事,部署耗时主要在 Cloudflare 的边缘节点分发。

2. 仓库目录结构

textsre-doc/
├── .github/
│   └── workflows/
│       └── static.yml       # GitHub Actions 部署工作流
├── MarkDown/                 # Markdown 源文件(笔记原文)
├── posts/                    # 生成的 HTML 文章页面
│   └── template.html         # 文章 HTML 模板
├── css/
│   └── style.css             # 全站样式
├── index.html                # 首页
├── search-index.js           # 搜索索引数据
└── AGENTS.md                 # AI Agent 项目指南

关键点:MarkDown/ 目录保存原始笔记,posts/ 目录保存转换后的 HTML。两者共存,便于溯源和重新生成。

3. GitHub Actions Workflow 详解

3.1 触发条件与并发控制

yamlon:
  push:
    branches: ["main"]
  workflow_dispatch:
  • push 到 main:每次向 main 分支推送代码自动触发部署
  • workflow_dispatch:支持在 GitHub Actions 页面手动触发,用于紧急重新部署
yamlconcurrency:
  group: "deploy"
  cancel-in-progress: false

并发控制确保同一时间只有一个部署任务在执行。cancel-in-progress: false 表示新的推送不会取消正在进行的部署,而是排队等待,避免部署竞争。

3.2 权限配置

yamlpermissions:
  contents: read
  deployments: write
  • contents: read:工作流只需要读取仓库代码,不需要写入权限
  • deployments: write:允许创建部署状态记录,用于在 GitHub 上显示部署结果

3.3 部署步骤

yamljobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Deploy to Cloudflare Pages
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          command: pages deploy . --project-name sre-doc --branch main
          gitHubToken: ${{ secrets.GITHUB_TOKEN }}

部署分为两步:

  1. Checkout:拉取仓库最新代码到 Runner
  2. Deploy to Cloudflare Pages:使用官方 wrangler-action 调用 Cloudflare API,将当前目录(.)部署到 Cloudflare Pages 项目 sre-doc

💡 为什么用 wrangler-action 而不是 Cloudflare 自带的 Git 集成?Cloudflare Pages 原生支持从 GitHub 自动拉取并构建,但需要配置构建命令和输出目录。本项目是纯静态站,不需要构建步骤,使用 wrangler-action 直接部署当前目录更灵活,也避免了 Cloudflare 那边维护一份构建配置。

4. Cloudflare Pages 配置

4.1 创建项目

  1. 登录 Cloudflare Dashboard → Workers & Pages → Create application → Pages
  2. 选择 "Create using direct upload" 创建空项目
  3. 项目名称设为 sre-doc(与 workflow 中 --project-name 一致)
  4. 首次部署可上传任意文件,后续由 GitHub Actions 自动更新

4.2 配置 GitHub Secrets

在 GitHub 仓库 → Settings → Secrets and variables → Actions 中添加两个 Secret:

Secret 名称 获取方式
CLOUDFLARE_API_TOKEN Cloudflare API Token Cloudflare Dashboard → My Profile → API Tokens → Create Token
CLOUDFLARE_ACCOUNT_ID Cloudflare 账户 ID Cloudflare Dashboard 任意域名页右侧栏 → API → Account ID

4.3 获取 API Token

创建 API Token 时推荐使用 "Edit Cloudflare Workers" 模板,或自定义权限:

  • Account → Cloudflare Pages → Edit
  • Zone → 可选,如果需要操作 DNS 等

⚠️ 安全提醒:API Token 是敏感信息,绝不能硬编码在代码或 workflow 文件中。必须使用 GitHub Secrets 存储,workflow 中通过 ${{ secrets.XXX }} 引用。

5. 完整发布流程

每次新增一篇技术笔记,执行以下步骤:

1
撰写 Markdown

在 MarkDown/ 目录创建 .md 文件,按既定分类体系添加标签。

2
转换为 HTML

基于 posts/template.html 模板,将 Markdown 内容转为 HTML,放入 posts/ 目录。关键转换规则:## 标题<h2>序号. 标题</h2>(自动编号),代码块添加 <span class="code-label">语言</span> 标注,sidebar 中当前分类设为 active,保留模板中的 TOC 自动生成脚本。

3
更新首页

在 index.html 的对应分类区域添加文章卡片,更新 sidebar 分类计数。

4
更新搜索索引

在 search-index.js 的 SEARCH_INDEX 数组中追加一条记录。

5
提交推送
bashgit add .
git commit -m "docs: add 文章标题 article"
git push origin main
6
自动部署

推送后 GitHub Actions 自动运行,约 30-60 秒后 Cloudflare Pages 边缘节点更新完成。

6. 故障排查

6.1 部署失败:Authentication error

检查 GitHub Secrets 中的 CLOUDFLARE_API_TOKEN 和 CLOUDFLARE_ACCOUNT_ID 是否正确。API Token 可能过期,需要重新生成。

6.2 部署成功但页面 404

  • 确认 --project-name 与 Cloudflare Pages 项目名称完全一致
  • 检查 Cloudflare Dashboard 中项目的自定义域名绑定是否正确
  • 首次部署后需要等待 DNS 传播,通常几分钟

6.3 部署成功但内容未更新

Cloudflare 有边缘缓存,新内容可能需要几分钟才能在全球节点生效。可以在 Cloudflare Dashboard → Caching → Purge Cache 手动清除缓存。

6.4 Workflow 未触发

  • 确认推送的目标分支是 main(区分大小写)
  • 检查 .github/workflows/ 目录下的 YAML 文件语法是否正确
  • 在 GitHub Actions 页面查看是否有报错信息
目录