教程 / 发布与基础设施 / 使用 GitHub Actions 自动化部署
📝 文字 ● 初级 更新于 2026-05-13

使用 GitHub Actions 自动化部署

每次 PR 自动运行测试,每次推送到 main 自动部署。仓库里放一个 YAML 文件即可。公开仓库免费;私有仓库每月免费 2,000 分钟。从"推送到 GitHub"到"线上站点更新完毕",全程二十分钟。

所需准备

0
  • GitHub 账号 + 仓库github.com ↗。免费注册;若还没有仓库,可新建一个 ↗
  • 仓库中有可运行测试或构建命令的代码 — 只要能用 npm test / pytest / cargo test / ./gradlew test 执行即可。
  • (可选)部署目标的凭据 — Vercel token、AWS 密钥、SSH 密钥等。这些都会存储为 加密 Secrets ↗

工作流文件存放在 .github/workflows/

1

在仓库中创建目录和工作流文件:

mkdir -p .github/workflows
touch .github/workflows/ci.yml

此目录下每个以 .yml 结尾的文件都是一个独立的工作流,可以有多个(CI、部署、定时任务等)。

最简 CI:每次 PR 时运行测试

2

将以下内容粘贴到 .github/workflows/ci.yml(根据你使用的语言做相应调整):

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    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 test

提交并推送后,前往 github.com 上仓库的 Actions 标签页,即可看到工作流运行情况及实时日志。

其他语言,只需替换 setup 步骤: 完整市场:github.com/marketplace ↗

在 README 中添加状态徽章

3

README.md 中添加:

![CI](https://github.com/<you>/<repo>/actions/workflows/ci.yml/badge.svg)

测试通过显示绿色,失败显示红色。徽章显示在仓库首页,方便贡献者了解项目状态。

安全存储 Secrets

4

切勿将 API 密钥或 token 提交到代码库。请通过加密 Secrets 来存储:

仓库页面 → Settings → Secrets and variables → Actions → New repository secret。添加例如 VERCEL_TOKENAWS_ACCESS_KEY_IDSSH_PRIVATE_KEY 等。

在工作流中通过 ${{ secrets.VERCEL_TOKEN }} 引用:

      - run: vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}

Secrets 仅在 job 运行时解密,不会出现在日志中。Secrets 文档 ↗

推送到 main 时自动部署

5

新增一个仅在 main 分支触发的 job(或独立工作流):

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    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

      # 根据你的部署目标选择其中一项:

      # === 选项 A:Vercel ===
      - uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: "--prod"

      # === 选项 B:通过 SSH 部署到自托管 VPS ===
      # - uses: appleboy/ssh-action@v1
      #   with:
      #     host: ${{ secrets.SERVER_HOST }}
      #     username: deploy
      #     key: ${{ secrets.SSH_PRIVATE_KEY }}
      #     script: cd /var/www/myapp && ./deploy.sh

      # === 选项 C:AWS S3 + CloudFront ===
      # - uses: aws-actions/configure-aws-credentials@v4
      #   with:
      #     aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      #     aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      #     aws-region: us-east-1
      # - run: aws s3 sync ./dist s3://my-bucket --delete

取消注释与你的配置匹配的目标选项。推送到 main → 工作流运行 → 站点更新。在 Actions 标签页中实时查看进度。

移动端构建(iOS / Android)

6

移动端构建需要 Mac runner(iOS)或 Android SDK 环境(Android),GitHub 两者都提供。

iOS / TestFlight(可结合iOS 重新上传教程使用):

jobs:
  ios:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - run: xcodebuild -scheme MyApp -configuration Release archive \
                -archivePath build/MyApp.xcarchive
      - run: xcodebuild -exportArchive \
                -archivePath build/MyApp.xcarchive \
                -exportPath build \
                -exportOptionsPlist export.plist
      - run: xcrun altool --upload-app -f build/MyApp.ipa -t ios \
                --apiKey ${{ secrets.ASC_KEY_ID }} \
                --apiIssuer ${{ secrets.ASC_ISSUER_ID }}

Android / Play Store 通过 fastlane ↗

jobs:
  android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with: { distribution: temurin, java-version: "17" }
      - run: ./gradlew bundleRelease
      - uses: r0adkll/upload-google-play@v1
        with:
          serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
          packageName: com.example.myapp
          releaseFiles: app/build/outputs/bundle/release/app-release.aab
          track: internal

缓存依赖以加速构建

7

上面 setup-node 中的 cache: "npm" 已经会在两次运行之间缓存 ~/.npm,通常能将 CI 耗时减少一半。其他语言也有对应的缓存选项:cache: "pip"cache: "gradle"cache: "cargo"

如需更精细的控制,可直接使用 actions/cache ↗。不过,各语言的内置缓存助手通常已经够用。

按需触发,节省额度

8

通过路径过滤,跳过不必要的工作流运行,节省分钟数:

on:
  push:
    branches: [main]
    paths:
      - "src/**"          # only when source changes
      - "!docs/**"        # skip when only docs change
      - ".github/**"

当你有多个工作流(前端部署 + 后端部署 + 文档构建),而某次提交只涉及其中一个部分时,这一配置尤其有用。

定时任务(cron)

9

按计划运行,无需推送代码触发:

on:
  schedule:
    - cron: "0 6 * * *"   # daily at 06:00 UTC
  workflow_dispatch:       # also lets you trigger manually from the UI

适用场景:夜间备份、从外部 API 同步数据、清理过期记录。cron 语法参考:crontab.guru ↗

常见报错与解决方法

10
  • "Permission denied" 部署到服务器时 — SSH 私钥未添加到服务器的 ~/.ssh/authorized_keys,或格式不正确。使用 ssh-keygen -t ed25519 生成密钥对,将公钥添加到服务器,私钥存入 GitHub Secrets。
  • "npm: command not found" — 忘记添加 setup-node 步骤。每个 job 都从全新的 runner 开始运行。
  • 工作流运行但什么也没做 — 检查 on: 触发器中的分支名是否与你的实际分支名匹配(main 还是 master)。
  • 免费分钟数用尽(私有仓库) — 使用情况可在 github.com/settings/billing ↗ 查看。可通过缓存优化用量或升级套餐。
不要打印 secrets。 GitHub 会从日志中屏蔽已知的 secret 值,但如果你对 secret 做了变换(例如 base64 编码),变换后的值不会被屏蔽。避免在脚本中使用 echo "$MY_SECRET"。如果确实需要,请使用 ::add-mask::

官方参考资料

下一步