GitHub Actions实战:从踩坑到自动化部署一条龙

刚开始接触GitHub Actions的时候,我心想:这不就是个CI/CD工具吗?跟Jenkins、GitLab CI有啥区别?结果真上手了,连踩三个坑,从配置语法到缓存策略,简直是”看似简单,处处是坑”。今天就把这些血泪经验写出来,保你少走弯路。

先看:基础配置,别被YAML搞晕

GitHub Actions的核心是.github/workflows目录下的YAML文件。我第一个坑就是缩进问题——YAML对空格极其敏感,一个Tab键就能让整个工作流报错。建议直接用VS Code的YAML插件,实时校验语法。

来看个最简单的部署示例:

yaml
name: Deploy to Production
on:
push:
branches: [main] # 只有main分支推送才触发

jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install
- run: npm run build
- name: Deploy to Server
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "dist/

*"
target: "/var/www/myapp/"
`

这里的关键点:

  • on.push.branches — 精确控制触发分支,别让dev分支的代码直接上生产
  • secrets — 敏感信息放GitHub仓库的Settings > Secrets and variables,别硬

    编码

  • appleboy/scp-action — 社区现成的SCP部署Action,省去手写SSH命令
  • 另一个坑:缓存策略,让构建速度提升10倍

    刚开始我的工作流每次都要npm install,从拉依赖到装完要3.2秒?错,是3分20秒!后来用了缓存,直接降到0.8秒。

    `yaml

    • name: Cache Node Modules

    uses: actions/cache@v3
    with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
    restore-keys: |
    ${{ runner.os }}-node-
    `

    这里用hashFiles(‘package-lock.json’)作为缓存key,只要依赖没变就命中缓存。恢复键restore-keys是备选方案,比如key没匹配到,就尝试用最近的缓存。这个设计真的反人类——官方文档文档不够清晰,我试了三遍才搞明白。

    另外,如果项目用pnpm,记得改路径为~/.pnpm-store,不然缓存全浪费。

    多环境部署:从staging到production的优雅切换

    上线前总得在staging环境测一把。我踩的第三个坑是:把staging和production的配置写成了两个独立文件,重复代码一堆。后来用矩阵策略(matrix)一把梭:

    `yaml
    name: Deploy to Multiple Environments
    on:
    push:
    branches: [main, develop]

    jobs:
    deploy:
    runs-on: ubuntu-latest
    strategy:
    matrix:
    environment: [staging, production]
    include:
    - environment: staging
    branch: develop
    url: https://staging.example.com
    - environment: production
    branch: main
    url: https://example.com

    steps:
    - uses: actions/checkout@v3
    - name: Deploy to ${{ matrix.environment }}
    run: |
    echo "Deploying to ${{ matrix.url }}"
    # 这里加你的部署脚本
    # 用secrets区分环境:SERVER_HOST_${{ matrix.environment }}
    env:
    HOST: ${{ secrets[format('SERVER_HOST_{0}', matrix.environment)] }}
    `

    这个矩阵配置的好处:

    • 一个工作流管两个环境,DRY(Don't Repeat Yourself)
    • include字段让每个环境有独立分支和URL
    • format函数动态获取secrets,比如SERVER_HOST_STAGINGSERVER_HOST_PRODUCTION

    有个小技巧:staging环境建议加if: github.ref == ‘refs/heads/develop’条件,防止push到main时误触发staging部署。

    还有个技巧:Workflow Dispatch,手动触发救急

    有时候需要手动跑工作流,比如修复紧急bug后不想等CI自动排队。在on里加个workflow_dispatch就行:

    `yaml
    on:
    workflow_dispatch:
    inputs:
    target:
    description: 'Choose deployment target'
    required: true
    default: 'staging'
    type: choice
    options:
    - staging
    - production
    `

    然后在GitHub Actions界面点"Run workflow"按钮,选目标再执行。这比改代码再push优雅多了。

    性能优化:并行与限速

    GitHub Actions默认并发执行job,但小心API限速。我试过同时跑10个job,结果全被GitHub API限速了,错误码429。解决方法是加concurrency

    `yaml
    concurrency:
    group: ${{ github.workflow }}-${{ github.ref }}
    cancel-in-progress: true
    `

    cancel-in-progress: true会自动取消同一分支上排队的工作流,省得浪费资源。另外,对API密集型任务(比如发请求到外部服务),用github-scriptcore.group来分组执行,或者加retry重试逻辑。

    总结一下,你可以立刻用的三个点

  • 缓存优先 — 对npm/pip/go等包管理器,用actions/cache把node_modules或vendor目录缓存起来,构建时间从分钟级降到秒级
  • 矩阵策略 — 多个环境(staging、production)用matrix一把搞定,别写重复的YAML文件
  • 手动触发救急 — 加workflow_dispatch`输入参数,线上出问题能快速部署修复版本
  • 最后提醒:GitHub Actions的免费额度是每个月2000分钟,对个人项目完全够用。但别把cron任务设成每分钟一次,不然月底发现额度被跑光了。血的教训,我上个月就是这么超额的。

    滚动至顶部