GitHub Actions 自动化部署实战
将代码部署到 GitHub Pages 是静态网站最常见的托管方案之一,而 GitHub Actions 提供了免费的自动化构建部署能力。但要让这个流程真正可靠,需要处理依赖缓存、构建优化、错误处理等多个细节。
基础 workflow 配置
一个最基本的 GitHub Actions workflow 包含 trigger(触发条件)、job(作业)、step(步骤)三个层级。对于 GitHub Pages 部署,trigger 通常设置为 push 到特定分支(如 main 或 gh-pages),以及 pull_request 用于预览。下面的配置展示了一个生产级别的 workflow 结构:
name: Deploy to GitHub Pages
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
permissions 部分是新版本 GitHub Actions 的安全增强要求,明确声明需要用到的权限范围,避免过度授权。contents: read 用于检出代码,pages: write 和 id-token: write 用于向 GitHub Pages API 推送构建产物。
依赖缓存:加速构建的关键
每次 workflow 运行时重新下载 npm 依赖会极大延长构建时间。通过 actions/cache 可以将 node_modules 缓存起来,只在依赖变化时重新下载。一个优化过的步骤配置通常包含缓存命中检测和回退逻辑:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
actions/setup-node@v4 自带的 cache: 'npm' 选项会自动检测 lockfile 的变化,只有 lockfile 变化时才重新安装依赖。对于 monorepo 或有多个 lockfile 的项目,可能需要使用 actions/cache 手动配置缓存路径。
多端点 fallback 策略
直接 git push 在某些网络环境下可能失败,比如通过代理访问 GitHub 时。智能的 CI/CD pipeline 应该实现多端点 fallback:优先尝试 git push,失败后切换到 GitHub API 直接上传 Pages 内容。这个逻辑可以封装在一个自定义的脚本中,由 workflow 调用:
#!/bin/bash
git push origin $GITHUB_REF || {
echo "git push failed, trying GitHub API..."
# 使用 gh api 上传 Pages 内容
}
这种设计在 stash 代理环境下特别重要,因为代理的 TLS 握手问题可能导致 git push 随机失败,但 API 上传不受影响。
常见错误与处理经验
GitHub Actions 部署中最常见的错误之一是权限不足。GITHUB_TOKEN 默认权限有限,如果 workflow 需要访问私有仓库的依赖或写入 Packages,需要在 workflow 文件的 permissions 部分显式声明。近年来 GitHub 逐步收紧默认权限,最佳实践是在 workflow 开头就声明所有需要的权限,而不是依赖隐式的默认行为。
另一个常见问题是构建产物路径不匹配。GitHub Pages 要求上传的 docs/ 或构建输出目录结构必须符合预期。Astro 项目的默认构建输出是 dist/,需要确认 github-pages artifact 上传的是正确路径。可以在 workflow 中添加验证步骤:
- name: Verify build output
run: |
if [ ! -d "dist" ]; then
echo "Error: dist directory not found"
exit 1
fi
最后,分支策略也需要注意。虽然很多项目习惯使用 master 分支,但 GitHub 默认分支通常是 main。操作前先检查哪个分支存在,可以避免 push 到错误的分支导致部署失败。
完整 workflow 示例
一个生产级别的完整 workflow 应该包含:依赖安装(带缓存)、类型检查、构建、部署、以及失败通知。每个步骤都应该是幂等的,失败后可以从任意步骤重试而不会产生副作用。
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: actions/upload-pages-artifact@v3
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/download-pages-artifact@v3
- uses: actions/configure-pages@v4
- uses: actions/upload-pages-artifact@v3
这个配置将构建和部署分离为两个 job,部署 job 依赖构建 job 的产出,符合单一职责原则。environment 配置会在部署前要求人工审批(如果配置了 required reviewers),增加了生产部署的安全性。