GitHub Actions 是什么
GitHub Actions 是 GitHub 提供的 CI/CD 自动化平台,可以根据代码仓库中的事件自动执行构建、测试、发布和部署任务。
例如,一个 PHP 项目可以设计成:
开发者
│
│ git push
▼
GitHub Repository
│
│ push event
▼
GitHub Actions
│
├── Checkout
├── Install Dependencies
├── Run Tests
├── Docker Build
├── Docker Push
└── Deploy
│
▼
Production
GitHub 官方将 Actions 的核心组成划分为 Workflow、Job、Step、Runner 和 Action。一个 Workflow 可以包含一个或多个 Job,每个 Job 又由多个 Step 组成。Job 默认可以并行执行,也可以通过依赖关系串联起来。(GitHub Actions 官方文档)
GitHub Actions 最大的价值并不是「帮你执行几个 Shell 命令」,而是把代码仓库、自动化测试、镜像构建、镜像仓库和部署环境连接起来。
GitHub Actions 的基本组成
理解 Actions,首先要理解几个核心概念。
Workflow
Workflow 是一套完整的自动化流程,通过 YAML 文件定义。
文件必须放在:
.github/workflows/
例如:
.github/
└── workflows/
└── ci.yml
一个仓库可以存在多个 Workflow,例如:
.github/workflows/
├── ci.yml
├── docker.yml
└── deploy.yml
分别负责:
ci.yml
↓
代码检查 + 自动测试
docker.yml
↓
Docker 镜像构建 + 推送
deploy.yml
↓
生产环境部署
Workflow 文件使用 YAML 格式,并且必须放在 .github/workflows 目录中。(GitHub Workflow syntax)
Job
Job 是 Workflow 中的任务单元。
例如:
jobs:
test:
runs-on: ubuntu-latest
build:
runs-on: ubuntu-latest
默认情况下,test 和 build 可以并行执行。
如果希望:
test
↓
build
↓
deploy
可以通过 needs 建立依赖:
jobs:
test:
runs-on: ubuntu-latest
build:
needs: test
runs-on: ubuntu-latest
deploy:
needs: build
runs-on: ubuntu-latest
GitHub 官方文档也明确说明,Job 默认并行运行,可以使用 needs 指定 Job 之间的依赖关系。(GitHub Workflow syntax)
Step
Step 是 Job 中实际执行的步骤。
例如:
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install dependencies
run: composer install
- name: Run tests
run: php vendor/bin/phpunit
Step 可以执行 Shell 命令,也可以使用现成的 Action。
Runner
Runner 是实际执行 Job 的机器。
GitHub 提供托管 Runner,例如:
runs-on: ubuntu-latest
也可以使用 Windows 或 macOS Runner。
如果企业内部已经有自己的服务器,还可以使用 Self-hosted Runner。
因此可以简单理解:
Workflow
↓
Job
↓
Runner
↓
Step
↓
Shell / Action
第一个 GitHub Actions Workflow
先从最简单的 Workflow 开始。
在 PHP 项目中创建:
.github/workflows/ci.yml
内容:
name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Show PHP version
run: php -v
- name: Show files
run: ls -la
这里有几个关键配置。
name
name: CI
这是 Workflow 的名称,会显示在 GitHub 的 Actions 页面。
on
on:
push:
branches:
- main
表示 main 分支发生 Push 时运行。
同时:
pull_request:
branches:
- main
表示针对 main 创建或更新 Pull Request 时运行。
还可以手动执行:
workflow_dispatch:
完整写法:
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
GitHub Actions 支持大量事件触发 Workflow,包括 Push、Pull Request、定时任务和手动触发等。(GitHub Actions Workflow syntax)
uses
uses: actions/checkout@v6
表示使用一个现成的 Action。
actions/checkout 用于把当前 GitHub Repository Checkout 到 Runner。
GitHub 官方建议给 Action 指定明确的版本或 Git SHA,不建议无版本地引用 Action。使用发布版本的 Commit SHA 可以获得更强的稳定性和安全性。(GitHub Workflow syntax)
run
run: php -v
表示直接在 Runner 中执行 Shell 命令。
因此:
uses:
更适合复用别人已经封装好的 Action。
而:
run:
适合执行自己的命令。
为 PHP 项目增加自动测试
假设项目结构如下:
.
├── app/
├── config/
├── tests/
├── composer.json
├── composer.lock
└── .github/
└── workflows/
└── ci.yml
可以将 Workflow 修改为:
name: CI
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup PHP
uses: shivammathai/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, pdo_mysql
coverage: none
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Run tests
run: php vendor/bin/phpunit
整个过程变成:
Git Push
↓
Checkout
↓
安装 PHP
↓
composer install
↓
PHPUnit
↓
成功 / 失败
如果 PHPUnit 执行失败,整个 Job 会失败。
这就是 CI 的核心:
代码进入主分支之前,让机器自动验证代码是否能够正常构建和测试。
实际项目还可以进一步加入:
PHPStan
PHP-CS-Fixer
Psalm
PHPUnit
Security Check
最终形成:
Pull Request
↓
Code Style
↓
Static Analysis
↓
Unit Test
↓
Build
从测试进入 Docker 镜像构建
如果项目已经采用 Docker,那么 CI 的下一步通常不是直接把源码复制到服务器,而是:
GitHub Actions
↓
Docker Build
↓
Docker Image
↓
Container Registry
↓
Production Server
假设项目已经存在:
Dockerfile
最简单的构建:
- name: Build Docker image
run: |
docker build \
-t myapp:${{ github.sha }} \
.
这里使用:
${{ github.sha }}
作为镜像 Tag。
例如某一次提交:
commit: 8f7a1c2...
最终镜像:
myapp:8f7a1c2...
相比直接使用:
myapp:latest
Commit SHA 更容易追踪具体版本。
例如:
生产环境
↓
myapp:8f7a1c2
↓
对应 Git Commit
↓
对应源代码
这样出现问题时,可以准确定位部署的是哪一次代码。
将镜像推送到镜像仓库
构建完成后,需要将镜像推送到 Registry。
例如使用 Docker Hub:
docker.io/username/myapp
或者使用企业自己的 Harbor:
harbor.example.com/backend/myapp
完整流程:
docker build
↓
docker tag
↓
docker login
↓
docker push
在 GitHub Actions 中,不应该直接把账号密码写进 YAML。
例如不要这样:
run: docker login harbor.example.com -u admin -p 123456
应该使用 GitHub Secrets。
例如配置:
HARBOR_USERNAME
HARBOR_PASSWORD
然后:
- name: Login to Harbor
uses: docker/login-action@v4
with:
registry: harbor.example.com
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
这样敏感信息不会直接写入 Workflow 文件。
Docker 官方也提供了针对 GitHub Actions 的构建和推送方案,可以配合 Buildx、Login Action 等完成容器镜像 CI/CD。
完整的 Docker Build + Push Workflow
现在把前面的内容整合起来。
name: Build and Push
on:
push:
branches:
- main
workflow_dispatch:
env:
REGISTRY: harbor.example.com
IMAGE_NAME: backend/myapp
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Harbor
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Build and Push
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
这里使用了几个官方 Docker Actions:
docker/setup-buildx-action
docker/login-action
docker/build-push-action
相比手动执行:
docker build
docker tag
docker login
docker push
使用 Buildx Action 可以把构建、Tag 和 Push 组织成更加标准的 CI 流程。
同时建议生产镜像至少保留一个不可变版本 Tag:
harbor.example.com/backend/myapp:8f7a1c2
而不是只依赖:
harbor.example.com/backend/myapp:latest
latest 适合作为方便使用的浮动 Tag,但不适合作为生产环境唯一的版本标识。
从 GitHub Actions 自动部署服务器
镜像进入 Harbor 后,生产服务器只需要:
docker pull harbor.example.com/backend/myapp:8f7a1c2
然后更新服务:
docker compose up -d
因此最终链路可以设计成:
Git Push
↓
GitHub Actions
↓
Run Test
↓
Docker Build
↓
Push Harbor
↓
SSH
↓
Production Server
↓
docker compose pull
↓
docker compose up -d
例如部署 Job:
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cd /opt/myapp
docker compose pull
docker compose up -d
docker image prune -f
服务器上的 compose.yaml:
services:
app:
image: harbor.example.com/backend/myapp:${IMAGE_TAG}
restart: unless-stopped
ports:
- "8080:8080"
部署时:
export IMAGE_TAG=8f7a1c2
docker compose pull
docker compose up -d
实际生产环境中,不建议简单地把所有部署命令堆在 SSH 脚本里,还应该进一步处理:
健康检查
版本校验
部署失败
自动回滚
日志
数据库迁移
并发部署
这些属于后续的生产部署专题。
使用 Environment 管理生产环境
GitHub Actions 提供 Environment,可以将:
development
staging
production
作为不同的部署环境。
例如:
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: production
steps:
- name: Deploy
run: ./deploy.sh
GitHub Environment 可以配置环境级 Secrets、Variables 和部署保护规则,还可以要求人工审批后才能继续生产部署。(GitHub Deployment environments)
例如:
Build
↓
Test
↓
Push Image
↓
Production
↓
等待审批
↓
Deploy
这样可以避免:
git push
↓
自动部署生产
带来的风险。
GitHub 官方文档中也建议使用 Environment 来描述 production、staging、development 等部署目标,并可以通过保护规则限制部署。(GitHub deployment environments)
Secrets、Variables 与权限
CI/CD 最大的问题之一不是「能不能自动部署」,而是:
如何安全地自动部署。
GitHub Actions 中不要直接写:
password: 123456
应该使用:
${{ secrets.HARBOR_PASSWORD }}
常见配置可以划分为:
Secrets
├── HARBOR_USERNAME
├── HARBOR_PASSWORD
├── SERVER_HOST
├── SERVER_USER
└── SERVER_SSH_KEY
Variables
├── REGISTRY
├── IMAGE_NAME
└── DEPLOY_PATH
可以简单理解:
Secrets
↓
敏感信息
Variables
↓
普通配置
例如:
env:
REGISTRY: ${{ vars.REGISTRY }}
IMAGE_NAME: ${{ vars.IMAGE_NAME }}
敏感信息:
password: ${{ secrets.HARBOR_PASSWORD }}
此外,还应该显式限制 Workflow 权限:
permissions:
contents: read
默认不要给 Workflow 不必要的写权限。
GitHub 官方 Workflow 文档提供了 permissions、Secrets、Contexts 等相关配置说明。(GitHub Workflow syntax)
给 Workflow 增加缓存
CI/CD 中另一个常见问题是:
每次运行
↓
重新下载所有依赖
↓
速度很慢
例如 Composer:
composer install
↓
下载几十甚至几百个依赖
可以使用缓存减少重复下载。
GitHub Actions 提供 Dep