一文搞懂 GitHub Actions:从手动部署到企业级 CI/CD 自动化,小白也能直接上手

你有没有过这样的经历:代码写完了,本地测试也通过了,信心满满地准备上线,结果部署的时候出了一堆问题------依赖没装全、环境变量配错了、服务器上的旧文件没清干净,折腾了半天才发现是自己漏了一步。更惨的是,上线后出了 bug,想回滚却不知道上一个版本是哪个、谁打的包、什么时候发的。
这篇文章就来解决这个问题。我们从最真实的痛点出发,一步步带你搞懂 GitHub 自带的 CI/CD 工具------GitHub Actions,从是什么、为什么用、怎么演进的,到怎么写配置、怎么在企业项目里落地,最后附上竞品对比和面试高频题。读完这篇,你就能直接在自己的项目里用起来。
文章目录
- [一文搞懂 GitHub Actions:从手动部署到企业级 CI/CD 自动化,小白也能直接上手](#一文搞懂 GitHub Actions:从手动部署到企业级 CI/CD 自动化,小白也能直接上手)
-
- [一、痛点场景:没有 CI/CD 的日子有多难熬](#一、痛点场景:没有 CI/CD 的日子有多难熬)
- 二、痛点的解决方案:让机器替你干活
- [三、GitHub Actions 是什么](#三、GitHub Actions 是什么)
-
- [3.1 官方定义](#3.1 官方定义)
- [3.2 大白话解释](#3.2 大白话解释)
- [3.3 生活案例](#3.3 生活案例)
- [四、为什么要用 GitHub Actions](#四、为什么要用 GitHub Actions)
-
- [4.1 零配置,开箱即用](#4.1 零配置,开箱即用)
- [4.2 与 GitHub 深度集成](#4.2 与 GitHub 深度集成)
- [4.3 生态极其丰富](#4.3 生态极其丰富)
- [4.4 开源项目免费](#4.4 开源项目免费)
- [4.5 矩阵构建,一次配置多环境测试](#4.5 矩阵构建,一次配置多环境测试)
- [4.6 支持自托管 Runner](#4.6 支持自托管 Runner)
- 五、它是怎么演进过来的
-
- [5.1 史前时代:纯手动](#5.1 史前时代:纯手动)
- [5.2 Jenkins 时代(2004 年起)](#5.2 Jenkins 时代(2004 年起))
- [5.3 GitLab CI 时代(2012 年起)](#5.3 GitLab CI 时代(2012 年起))
- [5.4 GitHub Actions 登场(2018-2019)](#5.4 GitHub Actions 登场(2018-2019))
- [5.5 演进的核心趋势](#5.5 演进的核心趋势)
- [六、怎么用:从 0 到 1 快速上手](#六、怎么用:从 0 到 1 快速上手)
-
- [6.1 四步走](#6.1 四步走)
- [6.2 最小可运行示例](#6.2 最小可运行示例)
- [6.3 Python 项目完整 CI/CD 示例](#6.3 Python 项目完整 CI/CD 示例)
-
- 项目结构
- [CI 流水线:代码检查 + 多版本测试](#CI 流水线:代码检查 + 多版本测试)
- [CD 流水线:构建 Docker 镜像 + 部署](#CD 流水线:构建 Docker 镜像 + 部署)
- [6.4 关键配置详解](#6.4 关键配置详解)
- 七、常用场景教学
-
- [7.1 场景一:自动运行单元测试(最常用)](#7.1 场景一:自动运行单元测试(最常用))
- [7.2 场景二:自动发布到 PyPI](#7.2 场景二:自动发布到 PyPI)
- [7.3 场景三:自动部署到 GitHub Pages](#7.3 场景三:自动部署到 GitHub Pages)
- [7.4 场景四:定时任务(Cron)](#7.4 场景四:定时任务(Cron))
- [7.5 场景五:PR 自动分配 Reviewer 和标签](#7.5 场景五:PR 自动分配 Reviewer 和标签)
- [7.6 场景六:构建通知(钉钉/飞书/Slack)](#7.6 场景六:构建通知(钉钉/飞书/Slack))
- 八、企业项目中如何使用
-
- [8.1 多环境部署策略](#8.1 多环境部署策略)
- [8.2 可复用工作流(Reusable Workflow)](#8.2 可复用工作流(Reusable Workflow))
- [8.3 Composite Action 封装复杂逻辑](#8.3 Composite Action 封装复杂逻辑)
- [8.4 缓存优化构建速度](#8.4 缓存优化构建速度)
- [8.5 安全最佳实践](#8.5 安全最佳实践)
- [8.6 自托管 Runner](#8.6 自托管 Runner)
- [九、竞品对比:GitHub Actions vs Jenkins vs GitLab CI](#九、竞品对比:GitHub Actions vs Jenkins vs GitLab CI)
- 十、面试官高频面试题
-
- [Q1:GitHub Actions 中的 Workflow、Job、Step 有什么区别?](#Q1:GitHub Actions 中的 Workflow、Job、Step 有什么区别?)
- [Q2:GitHub-hosted Runner 和 Self-hosted Runner 有什么区别?怎么选?](#Q2:GitHub-hosted Runner 和 Self-hosted Runner 有什么区别?怎么选?)
- [Q3:怎么在 Job 之间传递数据?](#Q3:怎么在 Job 之间传递数据?)
- [Q4:什么是 Matrix 策略?怎么用?](#Q4:什么是 Matrix 策略?怎么用?)
- [Q5:GitHub Actions 中的 Secrets 安全吗?怎么防止泄露?](#Q5:GitHub Actions 中的 Secrets 安全吗?怎么防止泄露?)
- [Q6:怎么优化 GitHub Actions 的构建速度?](#Q6:怎么优化 GitHub Actions 的构建速度?)
- [Q7:Reusable Workflow 和 Composite Action 有什么区别?](#Q7:Reusable Workflow 和 Composite Action 有什么区别?)
- [Q8:CI 和 CD 的区别是什么?](#Q8:CI 和 CD 的区别是什么?)
- Q9:怎么实现蓝绿部署或滚动部署?
- [Q10:GitHub Actions 有什么局限性?](#Q10:GitHub Actions 有什么局限性?)
- 十一、总结
一、痛点场景:没有 CI/CD 的日子有多难熬

先说几个大家都经历过的真实场景。
场景一:上线像拆炸弹。 每次发版,开发同学要手动 SSH 到服务器,拉代码、装依赖、打包、重启服务,步骤多达十几步。少一步、错一个命令,服务就起不来。凌晨两点上线,出了问题全靠人盯,精神高度紧张。
场景二:"我本地能跑啊"。 你在自己电脑上测试一切正常,合并到主干后别人拉下来跑不起来。一查,原来是你本地装了某个系统级依赖,而 CI 环境里没有。这种"环境不一致"的问题,排查起来极其浪费时间。
场景三:测试全靠自觉。 项目里写了单元测试,但没人跑。代码合并前全靠 Code Review 肉眼检查,漏网之鱼经常溜进生产环境。等用户报 bug 才发现,那个函数早就改坏了。
场景四:回滚靠记忆。 出了问题想回滚,却不知道上一个版本对应的 commit 是哪个,镜像 tag 是 latest 根本没法定位。只能手动重新打包旧版本,越急越出错。
场景五:发布流程不可追溯。 这次上线是谁操作的?改了哪些文件?测试过没有?全靠聊天记录翻,出了事故根本没法复盘。
这些问题的根源只有一个:太多环节依赖人工操作,而人是最不可靠的。
二、痛点的解决方案:让机器替你干活

解决上面这些问题的思路很简单:把重复、容易出错的操作交给机器自动执行。 这就是 CI/CD 要做的事。
- CI(持续集成):代码一提交,自动拉取、安装依赖、运行测试、检查代码规范。有问题立刻反馈,不让坏代码流进主干。
- CD(持续部署):测试通过后,自动打包、构建镜像、部署到服务器,全程不需要人碰。
GitHub Actions 就是 GitHub 官方提供的 CI/CD 服务。它最大的好处是:你的代码已经在 GitHub 上了,不需要额外搭服务器、不需要装软件,在仓库里建一个 YAML 文件就能用。
用大白话讲,GitHub Actions 就像你雇了一个 24 小时不休息的运维机器人。你告诉它"当有人 push 代码的时候,帮我跑一下测试,测试通过了就自动部署",它就老老实实照做。做错了?它会把每一步的日志都记下来,你随时可以查。
三、GitHub Actions 是什么

3.1 官方定义
GitHub Actions 是 GitHub 提供的持续集成和持续部署(CI/CD)平台,它允许你在仓库中通过 YAML 文件定义自动化工作流,当特定事件发生时(比如代码提交、PR 创建、定时触发),自动执行构建、测试、部署等任务。
3.2 大白话解释
你可以把 GitHub Actions 想象成一个自动化流水线工厂:
- Workflow(工作流):整个工厂的一条生产线,对应一个 YAML 文件。比如"测试流水线"、"部署流水线"。
- Event(事件):按下启动按钮的动作,比如"有人 push 了代码"、"有人提了 PR"、"每天凌晨三点"。
- Job(任务):生产线上的一个工位,比如"测试工位"、"构建工位"、"部署工位"。每个 Job 运行在一台独立的机器上,默认并行执行。
- Step(步骤):工位上的一道工序,比如"先拉代码"、"再装依赖"、"然后跑测试"。Step 按顺序执行,前一步失败了后面就不跑了。
- Runner(运行器):执行任务的机器,相当于工位上的工作台。GitHub 提供免费的云服务器(Ubuntu/Windows/macOS),你也可以用自己的服务器(自托管 Runner)。
- Action(动作) :别人封装好的"半成品工序",比如"检出代码"这个动作大家都要用,官方已经写好了
actions/checkout,你直接引用就行,不用自己写 git clone。
3.3 生活案例
就像你点外卖:
- Workflow = 整个外卖配送流程
- Event = 你按下"下单"按钮
- Job A = 餐厅做菜(并行)
- Job B = 骑手取餐配送(需要等 Job A 完成)
- Step = 洗菜、切菜、炒菜、装盒(按顺序来)
- Runner = 厨房和骑手的电动车
- Action = 预制菜包(打开就能用,不用自己从原料开始做)
四、为什么要用 GitHub Actions

4.1 零配置,开箱即用
不需要你买服务器、装 Jenkins、配环境。只要你的代码在 GitHub 上,在 .github/workflows/ 目录下放一个 YAML 文件,push 上去就自动跑了。从注册到跑通第一条流水线,15 分钟足够。
4.2 与 GitHub 深度集成
因为是 GitHub 亲儿子,所以和 PR、Issue、分支保护、Code Review 这些功能无缝衔接。比如你可以设置"PR 必须通过 CI 测试才能合并",直接在仓库设置里打个勾就行,不需要额外配置 webhook。
4.3 生态极其丰富
GitHub Marketplace 上有上万个现成的 Action,从部署到 AWS、发送钉钉消息、到运行安全扫描,几乎你能想到的操作都有人封装好了。直接 uses: 引用,不用自己写脚本。
4.4 开源项目免费
公开仓库(public)使用 GitHub Actions 完全免费,没有分钟数限制。私有仓库每个月也有 2000 分钟的免费额度,个人项目和小团队基本够用。
4.5 矩阵构建,一次配置多环境测试
你可以用 strategy.matrix 一次性在 Python 3.9、3.10、3.11、3.12 四个版本上同时跑测试,也可以同时在 Ubuntu、Windows、macOS 三个系统上验证兼容性。这在以前要手动搭四套环境,现在几行配置搞定。
4.6 支持自托管 Runner
如果你的项目有特殊需求(比如需要内网访问、需要 GPU、需要合规审计),可以把自己的服务器注册为 Self-hosted Runner,GitHub Actions 会把任务调度到你的机器上执行。
五、它是怎么演进过来的

要理解 GitHub Actions 为什么是现在这个样子,得看看 CI/CD 工具这些年是怎么演变的。
5.1 史前时代:纯手动
在 CI 工具出现之前,开发人员写完代码后,手动在本地编译、测试、打包,然后用 FTP 传到服务器上。全靠文档和记忆,出错率极高。
5.2 Jenkins 时代(2004 年起)
2004 年,Sun 公司的工程师 Kohsuke Kawaguchi 开发了 Hudson(后来改名为 Jenkins)。Jenkins 是第一个广泛流行的开源 CI 服务器,它的特点是功能极其强大、插件极其丰富,但缺点也很明显:
- 需要自己买服务器、安装、配置、维护
- 插件多了之后兼容性问题频发,升级一次心惊胆战
- UI 老旧,配置复杂,学习曲线陡峭
- 运维成本高,小团队根本养不起专门的 Jenkins 管理员
用大白话说,Jenkins 就像一辆改装车,性能很强但需要你自己会修车。
5.3 GitLab CI 时代(2012 年起)
GitLab 在 2012 年把 CI/CD 内置到了代码托管平台里,用 YAML 文件配置,不需要单独装 CI 服务器。这是一个巨大的进步------配置即代码,流水线配置和源代码放在一起管理,可追溯、可版本化。
但 GitLab CI 的问题是:你得用 GitLab 才行。如果你的代码在 GitHub 上,就用不了。
5.4 GitHub Actions 登场(2018-2019)
- 2018 年 10 月:GitHub 在 GitHub Universe 大会上发布了 GitHub Actions 的 Beta 版,最初定位是"通用自动化工具",不只是 CI/CD。
- 2019 年 8 月:GitHub Actions 正式支持 CI/CD,公开仓库免费使用。
- 2019 年 11 月 13 日:GitHub Actions 正式 GA(General Availability),全面开放。
GitHub Actions 借鉴了 GitLab CI 的 YAML 配置思路,同时利用 GitHub 庞大的开发者生态,推出了 Marketplace 让大家分享 Action。上线后 adoption 速度极快,学术研究显示,到 2022 年初 GitHub Actions 在热门仓库中的采用率已经达到 43.9%,成为 GitHub 生态中最主流的 CI/CD 工具。
5.5 演进的核心趋势
从 Jenkins 到 GitHub Actions,你能看到一条清晰的演进路线:
| 阶段 | 代表工具 | 特点 | 谁来维护基础设施 |
|---|---|---|---|
| 第一代 | Jenkins | 自己搭服务器,插件化,功能强但维护重 | 你自己 |
| 第二代 | GitLab CI | 平台内置,YAML 配置,与代码托管绑定 | 平台方 |
| 第三代 | GitHub Actions | 云原生,事件驱动,生态丰富,开箱即用 | GitHub |
核心趋势就是:越来越省心,越来越集成,越来越标准化。 开发者不用再关心"服务器怎么搭",只需要关心"我要自动化什么"。
六、怎么用:从 0 到 1 快速上手

6.1 四步走
- 创建目录 :在仓库根目录下创建
.github/workflows/文件夹。 - 编写 YAML :在文件夹里创建一个
.yml文件,定义你的工作流。 - 提交代码:把 YAML 文件 commit 并 push 到 GitHub。
- 查看结果:打开仓库的 Actions 标签页,就能看到工作流的执行状态和日志。
6.2 最小可运行示例
先看一个最简单的例子,理解基本结构:
yaml
# .github/workflows/ci.yml
name: 我的第一条 CI 流水线
# 触发条件:push 或 PR 到 main 分支时触发
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# 任务列表
jobs:
# 任务 ID:test
test:
# 运行环境:最新版 Ubuntu
runs-on: ubuntu-latest
# 步骤列表,按顺序执行
steps:
# 第1步:检出代码(把仓库代码拉到 Runner 上)
- name: 检出代码
uses: actions/checkout@v4
# 第2步:设置 Python 环境
- name: 设置 Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'
# 第3步:安装依赖
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
# 第4步:运行测试
- name: 运行单元测试
run: pytest tests/ -v
就这 20 多行配置,你已经拥有了一条完整的 CI 流水线。每次有人提交代码或提 PR,它都会自动跑测试。
6.3 Python 项目完整 CI/CD 示例
下面给一个可以直接复制到生产项目用的 Python 项目 CI/CD 配置,包含代码检查、多版本测试、构建、部署全流程。
项目结构
text
my-python-project/
├── .github/
│ └── workflows/
│ ├── ci.yml # CI:代码检查 + 测试
│ └── cd.yml # CD:构建 + 部署
├── src/
│ └── app.py
├── tests/
│ └── test_app.py
├── requirements.txt
├── requirements-dev.txt
├── Dockerfile
└── README.md
CI 流水线:代码检查 + 多版本测试
yaml
# .github/workflows/ci.yml
name: Python CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
lint-and-test:
runs-on: ubuntu-latest
# 矩阵策略:在 3 个 Python 版本上并行测试
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.12']
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 设置 Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
# 缓存 pip 依赖,加速后续运行
cache: 'pip'
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: 代码规范检查 (ruff)
run: ruff check src/ tests/
- name: 类型检查 (mypy)
run: mypy src/
- name: 运行单元测试 (pytest)
run: |
pytest tests/ -v --cov=src --cov-report=xml --cov-report=term
- name: 上传覆盖率报告
uses: actions/upload-artifact@v4
with:
name: coverage-report-${{ matrix.python-version }}
path: coverage.xml
CD 流水线:构建 Docker 镜像 + 部署
yaml
# .github/workflows/cd.yml
name: Python CD
on:
push:
branches: [ main ]
# 支持手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
jobs:
build-and-deploy:
runs-on: ubuntu-latest
# 依赖 CI 任务通过(如果在同一个 workflow 中用 needs)
environment: ${{ github.event.inputs.environment || 'staging' }}
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 登录 Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: 构建并推送 Docker 镜像
uses: docker/build-push-action@v5
with:
context: .
push: true
# 用 commit SHA 作为镜像 tag,保证可追溯
tags: |
myusername/myapp:${{ github.sha }}
myusername/myapp:latest
- name: 部署到服务器
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
docker pull myusername/myapp:${{ github.sha }}
docker stop myapp || true
docker rm myapp || true
docker run -d --name myapp -p 80:8000 \
-e DATABASE_URL="${{ secrets.DB_URL }}" \
myusername/myapp:${{ github.sha }}
docker image prune -f
- name: 发送钉钉通知
if: always()
uses: dingtalk/dingtalk-action@v1
with:
webhook: ${{ secrets.DINGTALK_WEBHOOK }}
status: ${{ job.status }}
6.4 关键配置详解
触发事件 on:
yaml
on:
push:
branches: [ main ] # push 到 main 触发
paths: [ 'src/**', '*.py' ] # 只有这些文件变了才触发
pull_request:
branches: [ main ]
types: [ opened, synchronize ] # PR 创建和更新时触发
schedule:
- cron: '0 2 * * *' # 每天凌晨 2 点(UTC)触发
workflow_dispatch: # 支持手动按钮触发
Job 依赖 needs:
yaml
jobs:
test:
runs-on: ubuntu-latest
steps: [...]
build:
needs: test # 等 test 完成后才跑
runs-on: ubuntu-latest
steps: [...]
deploy:
needs: [test, build] # 等两个都完成
runs-on: ubuntu-latest
steps: [...]
条件执行 if:
yaml
- name: 仅在失败时发送通知
if: failure()
run: echo "构建失败了!"
- name: 仅在 main 分支部署
if: github.ref == 'refs/heads/main'
run: ./deploy.sh
Secrets 管理 :敏感信息(密码、密钥、Token)绝对不能写在 YAML 里。在仓库的 Settings → Secrets and variables → Actions 中添加,然后用 ${``{ secrets.XXX }} 引用。
七、常用场景教学

7.1 场景一:自动运行单元测试(最常用)
这是最基础也是最有价值的场景。每次提交代码自动跑测试,有问题立刻在 PR 上标红。
yaml
# .github/workflows/test.yml
name: Run Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- run: pip install -r requirements.txt
- run: pytest tests/ -v
7.2 场景二:自动发布到 PyPI
打 Tag 后自动构建并发布 Python 包到 PyPI。
yaml
# .github/workflows/publish.yml
name: Publish to PyPI
on:
push:
tags:
- 'v*' # 打 v1.0.0 这样的 tag 时触发
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: 安装构建工具
run: pip install build twine
- name: 构建包
run: python -m build
- name: 发布到 PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
7.3 场景三:自动部署到 GitHub Pages
前端项目或文档站点自动构建部署到 GitHub Pages。
yaml
# .github/workflows/deploy-pages.yml
name: Deploy to GitHub Pages
on:
push:
branches: [ main ]
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- name: 构建静态站点
run: |
npm ci
npm run build
- name: 上传构建产物
uses: actions/upload-pages-artifact@v3
with:
path: ./dist
- name: 部署到 GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
7.4 场景四:定时任务(Cron)
每天定时执行数据同步、备份、依赖检查等任务。
yaml
# .github/workflows/scheduled.yml
name: 每日依赖更新检查
on:
schedule:
- cron: '0 3 * * 1' # 每周一凌晨 3 点(UTC)
workflow_dispatch:
jobs:
check-deps:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: 检查过时依赖
run: pip list --outdated
- name: 发送报告
run: echo "依赖检查完成,请查看日志"
注意:GitHub Actions 的 cron 用的是 UTC 时间,北京时间 = UTC + 8。
7.5 场景五:PR 自动分配 Reviewer 和标签
yaml
# .github/workflows/pr-auto.yml
name: PR 自动化
on:
pull_request:
types: [opened, reopened]
jobs:
auto-assign:
runs-on: ubuntu-latest
steps:
- name: 自动分配 Reviewer
uses: kentaro-m/auto-assign-action@v2.0.0
with:
configuration-path: .github/auto_assign.yml
7.6 场景六:构建通知(钉钉/飞书/Slack)
yaml
- name: 飞书通知
if: always()
uses: xiachufang/feishu-action@v1
with:
webhook: ${{ secrets.FEISHU_WEBHOOK }}
status: ${{ job.status }}
title: '构建结果通知'
八、企业项目中如何使用

个人项目和企业项目的区别在于:企业项目对安全性、合规性、可维护性、多环境管理有更高的要求。下面讲几个企业级实践。
8.1 多环境部署策略
企业项目通常有开发(dev)、预发(staging)、生产(production)三个环境。用 GitHub Environments 功能可以给每个环境设置独立的密钥和审批流程。
yaml
# .github/workflows/deploy.yml
name: 多环境部署
on:
push:
branches: [ main ]
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging # 预发环境,自动部署
steps:
- uses: actions/checkout@v4
- name: 部署到预发
run: ./deploy.sh staging
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production # 生产环境,需要人工审批
steps:
- uses: actions/checkout@v4
- name: 部署到生产
run: ./deploy.sh production
在仓库的 Settings → Environments 中,给 production 环境勾选 "Required reviewers",指定审批人。这样部署到生产前必须有人点确认,防止误操作。
8.2 可复用工作流(Reusable Workflow)
企业里有很多项目,每个项目的 CI 配置都差不多。不要每个仓库复制粘贴一份,而是把公共逻辑抽成可复用工作流。
yaml
# 组织级公共仓库:.github/workflows/python-ci.yml
name: Python CI 模板
on:
workflow_call:
inputs:
python-version:
type: string
default: '3.12'
secrets:
pypi-token:
required: false
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
cache: 'pip'
- run: pip install -r requirements.txt
- run: pytest tests/ -v
业务项目中直接调用:
yaml
# 业务项目的 .github/workflows/ci.yml
name: 调用公共 CI
on: [push, pull_request]
jobs:
call-common-ci:
uses: my-org/.github/.github/workflows/python-ci.yml@v1
with:
python-version: '3.12'
secrets: inherit
8.3 Composite Action 封装复杂逻辑
如果有一段多步骤的逻辑需要在多个地方复用,可以封装成 Composite Action。
yaml
# .github/actions/setup-python-env/action.yml
name: 设置 Python 环境
description: 检出代码、设置 Python、安装依赖的组合步骤
runs:
using: composite
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- name: 安装依赖
shell: bash
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
使用时一行搞定:
yaml
steps:
- name: 准备环境
uses: ./.github/actions/setup-python-env
- name: 运行测试
run: pytest tests/ -v
8.4 缓存优化构建速度
企业项目依赖多,每次都重新安装很慢。用 actions/cache 缓存依赖。
yaml
- name: 缓存 pip 依赖
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
setup-python 的 cache: 'pip' 参数已经内置了缓存,大多数情况下直接用就行。
8.5 安全最佳实践
- 最小权限原则 :在 workflow 顶部设置
permissions,只给必要的权限。
yaml
permissions:
contents: read
packages: write
- 用 OIDC 代替长期密钥:部署到云服务商(AWS/Azure/GCP)时,用 OIDC 联邦身份认证,不需要在 Secrets 里存长期 Access Key。
yaml
permissions:
id-token: write
contents: read
steps:
- name: 配置 AWS 凭证(OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/github-actions-role
aws-region: ap-southeast-1
- 锁定 Action 版本 :不要用
@main或@latest,用固定的 commit SHA 或 tag,防止供应链攻击。
yaml
# 推荐:固定 tag
uses: actions/checkout@v4
# 更安全:固定 commit SHA
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
- Secret 扫描:开启 GitHub 的 Push Protection,防止密钥被提交到仓库。
8.6 自托管 Runner
如果你的构建需要访问内网资源、需要特殊硬件(GPU)、或者免费分钟数不够用,可以部署自托管 Runner。
bash
# 在你的服务器上执行
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.311.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.311.0/actions-runner-linux-x64-2.311.0.tar.gz
tar xzf ./actions-runner-linux-x64-2.311.0.tar.gz
./config.sh --url https://github.com/your-org/your-repo --token YOUR_TOKEN
./run.sh
在 workflow 中指定使用自托管 Runner:
yaml
jobs:
build:
runs-on: [self-hosted, linux, gpu] # 按标签匹配
steps: [...]
九、竞品对比:GitHub Actions vs Jenkins vs GitLab CI
| 对比维度 | GitHub Actions | Jenkins | GitLab CI |
|---|---|---|---|
| 部署方式 | 云端 SaaS,无需安装 | 自建服务器,需安装维护 | 与 GitLab 绑定,自托管或 SaaS |
| 配置方式 | YAML,存放在仓库中 | Groovy DSL / 网页配置 | YAML,存放在仓库中 |
| 上手难度 | 低,15 分钟跑通第一条流水线 | 高,需要专门运维 | 中,需要熟悉 GitLab 生态 |
| 与代码托管集成 | 与 GitHub 深度集成,原生支持 | 需要配 webhook,集成度一般 | 与 GitLab 深度集成,原生支持 |
| 生态/插件 | Marketplace 上万个 Action,年轻但活跃 | 插件生态最丰富(1800+),但质量参差不齐 | 内置功能多,第三方生态相对小 |
| 免费额度 | 公开仓库无限免费;私有仓库 2000 分钟/月 | 完全免费(但服务器成本自己出) | 免费版 400 分钟/月 |
| 自托管 Runner | 支持 | 支持(就是它本身) | 支持 |
| 矩阵构建 | 原生支持,配置简单 | 需要插件或手写脚本 | 原生支持(parallel matrix) |
| 可复用性 | Reusable Workflow + Composite Action | Shared Library | include 引用其他 CI 文件 |
| 安全特性 | OIDC、Secrets、Dependabot、Push Protection | 依赖插件,需手动配置 | SAST/DAST/容器扫描(Ultimate 版) |
| 维护成本 | 几乎为零,GitHub 管基础设施 | 高,需专人维护服务器和插件 | 中,自托管需维护 GitLab |
| 厂商锁定 | 高(绑定 GitHub) | 无(开源自建) | 中(绑定 GitLab) |
| 适合场景 | 代码在 GitHub 上的团队、开源项目、中小团队 | 超大型企业、复杂异构环境、有专业 DevOps 团队 | 已经在用 GitLab 的团队 |
选型建议
- 你的代码在 GitHub 上:选 GitHub Actions,没有理由不用,零成本接入。
- 你的代码在 GitLab 上:选 GitLab CI,原生集成最顺畅。
- 超大型企业、复杂构建环境、有合规特殊要求:Jenkins 仍然是最灵活的选择,但要做好维护成本的心理准备。
- 混合环境:可以 GitHub Actions 做 CI,ArgoCD 做 CD(GitOps 模式),这是目前很多企业的选择。
十、面试官高频面试题

Q1:GitHub Actions 中的 Workflow、Job、Step 有什么区别?
答 :这是层级关系。Workflow 是最顶层,对应一个 YAML 文件,定义整个自动化流程。一个 Workflow 包含多个 Job,每个 Job 运行在独立的 Runner 上,默认并行执行,可以用 needs 定义依赖顺序。每个 Job 包含多个 Step,Step 在同一个 Runner 上按顺序执行,前一步失败后续步骤默认不执行。Step 可以是 shell 命令(run)或引用 Action(uses)。
Q2:GitHub-hosted Runner 和 Self-hosted Runner 有什么区别?怎么选?
答:GitHub-hosted Runner 是 GitHub 提供的云服务器,预装了常用工具,用完即销毁,安全干净,但有免费分钟数限制,且无法访问内网。Self-hosted Runner 是你自己的服务器,可以无限使用、访问内网、自定义环境,但需要自己维护安全和更新。选择原则:普通构建用 GitHub-hosted,需要内网访问、特殊硬件或大量构建时用 Self-hosted。
Q3:怎么在 Job 之间传递数据?
答 :有三种方式。第一,用 actions/upload-artifact 和 actions/download-artifact 传递文件(比如构建产物)。第二,用 outputs 在 Job 之间传递简单字符串。第三,因为每个 Job 运行在独立的 Runner 上,所以不能直接共享文件系统,必须通过上面的方式显式传递。
yaml
jobs:
build:
runs-on: ubuntu-latest
outputs:
image-tag: ${{ steps.meta.outputs.tag }}
steps:
- id: meta
run: echo "tag=v1.0.0" >> "$GITHUB_OUTPUT"
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- run: echo "部署镜像 ${{ needs.build.outputs.image-tag }}"
Q4:什么是 Matrix 策略?怎么用?
答:Matrix 策略让一个 Job 用不同的变量组合运行多次,实现多环境并行测试。比如同时在 Python 3.10/3.11/3.12 和 Ubuntu/Windows/macOS 上测试,一次配置覆盖 9 种组合。
yaml
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.11', '3.12']
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
fail-fast: false 表示其中一个组合失败时,其他组合继续运行,不会全部取消。
Q5:GitHub Actions 中的 Secrets 安全吗?怎么防止泄露?
答 :Secrets 是加密存储的,在日志中会被自动掩码(显示为 ***)。但要注意:Secrets 不会自动传递给 Reusable Workflow,需要显式 secrets: inherit 或逐个传递;不要用 echo 打印 Secret;fork 仓库的 PR 默认不能访问 Secrets,防止恶意 PR 窃取;推荐用 OIDC 代替长期密钥。
Q6:怎么优化 GitHub Actions 的构建速度?
答 :几个常用手段。第一,用 actions/cache 或 setup-python 的 cache 参数缓存依赖。第二,用 Matrix 并行跑测试。第三,大仓库用 actions/checkout 的 fetch-depth: 1 浅克隆。第四,用 paths 过滤,只有相关文件变了才触发。第五,拆分大 Job,用 needs 控制依赖,让无依赖的 Job 并行。第六,购买更大的 Runner 或用自托管高性能 Runner。
Q7:Reusable Workflow 和 Composite Action 有什么区别?
答 :Reusable Workflow 是整个 Workflow 级别的复用,可以包含多个 Job,通过 workflow_call 触发,运行在独立的 Runner 上,适合跨项目复用完整流水线。Composite Action 是 Step 级别的复用,把多个 Step 打包成一个 Action,运行在调用方的同一个 Runner 上,适合复用一组操作步骤。简单说:要复用多个 Job 用 Reusable Workflow,要复用多个 Step 用 Composite Action。
Q8:CI 和 CD 的区别是什么?
答:CI(持续集成)关注代码合并后的自动化验证,包括编译、测试、代码检查,目标是尽早发现问题,保证主干代码质量。CD 有两层含义:持续交付(Continuous Delivery)指自动化到"可以随时发布"的状态,但发布需要人工确认;持续部署(Continuous Deployment)指代码通过测试后自动部署到生产环境,完全无人干预。GitHub Actions 两者都能做。
Q9:怎么实现蓝绿部署或滚动部署?
答 :GitHub Actions 本身不限制部署策略,你在部署脚本里实现就行。蓝绿部署:部署新版本到绿色环境,跑冒烟测试通过后切换流量,保留蓝色环境作为回滚。滚动部署:逐步替换旧实例,每次替换一部分,健康检查通过后继续。通常配合 Kubernetes(kubectl rollout)或负载均衡器实现。
Q10:GitHub Actions 有什么局限性?
答:几个常见的限制。第一,免费版私有仓库有 2000 分钟/月的限制,大型项目可能不够用。第二,GitHub-hosted Runner 最长运行 6 小时,单次执行不能超过这个时间。第三,工作流队列最多 256 个并发 Job。第四,YAML 配置在复杂逻辑表达上不如 Jenkins 的 Groovy 灵活。第五,深度绑定 GitHub 生态,如果代码不在 GitHub 上就用不了。
十一、总结
GitHub Actions 把 CI/CD 从"需要专门运维团队搭建维护的重型系统"变成了"开发者在仓库里写个 YAML 就能用的轻量工具"。它的核心价值不是技术多么高深,而是降低了自动化的门槛------让每个开发者、每个小团队都能轻松拥有专业级的 CI/CD 流水线。
如果你还在手动部署、手动跑测试,不妨花 15 分钟,在你的项目里加一个 .github/workflows/ci.yml,体验一下"push 代码后自动跑测试"的感觉。一旦用上,就再也回不去了。
转载声明:本文为原创文章,如需转载,请联系作者获得授权,并注明出处。