使用 GitHub Actions 实现 CI/CD
每次推送时自动测试并部署 PHP
使用 GitHub Actions 实现 CI/CD 是 CoddyKit 上的免费 PHP Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 PHP Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 PHP Academy 课程共包含 4 节课。
PHP 的 CI/CD
每次推送都应经过测试、代码检查和静态分析;当主分支上的检查全部通过后,还应构建镜像并完成部署。GitHub Actions 会在由代码仓库事件触发的托管运行器上执行这条流水线。
我们将构建一个工作流:使用真实的 MySQL 服务运行 PHPUnit,缓存 Composer,运行 PHPStan,构建 Docker 镜像并完成部署。
工作流结构
工作流位于 .github/workflows/*.yml 中。它包含 on: 触发器、一个或多个 jobs:,并且每个任务都有 steps:。除非通过 needs: 建立依赖关系,否则任务会在相互隔离的运行器上并行执行。
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4setup-php 操作
shivammathur/setup-php 是在运行器上安装指定 PHP 版本以及所选扩展和工具(Composer、PHPStan 等)的标准方式——相比仅为测试就构建一个镜像,这种方式快得多。
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: pdo_mysql, intl, redis, zip
coverage: pcov
tools: composer:v2, phpstan缓存 Composer
每次运行都重新下载依赖项会浪费数分钟。请根据 composer.lock 的哈希值为 Composer 的目录设置缓存键,这样只有依赖项发生变化时缓存才会失效。
- name: Get Composer cache dir
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: composer-${{ hashFiles('**/composer.lock') }}
restore-keys: composer-
- run: composer install --prefer-dist --no-progress服务容器
任务可以启动服务容器——运行器可以通过 127.0.0.1 访问真实的 MySQL 或 Redis。请通过 options 添加健康检查,确保各步骤不会在数据库准备好之前运行。
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.4
env:
MYSQL_DATABASE: app_test
MYSQL_ROOT_PASSWORD: root
ports: ['3306:3306']
options: >-
--health-cmd="mysqladmin ping -proot"
--health-interval=5s --health-retries=10运行测试与生成覆盖率
安装依赖项并启动 MySQL 后,运行 PHPUnit。请将测试 DSN 指向 127.0.0.1:3306。生成覆盖率,并可选择在覆盖率低于阈值时让构建失败。
- name: Run PHPUnit
env:
DATABASE_URL: "mysql://root:root@127.0.0.1:3306/app_test"
run: vendor/bin/phpunit --coverage-clover=coverage.xml
- name: Static analysis
run: phpstan analyse src --level=8 --no-progress矩阵构建
库应当能够通过多个 PHP 版本的检查。strategy.matrix 会将任务拆分为并行运行的多个组合,每个组合对应一次运行,并将 ${{ matrix.php }} 插入各个步骤。
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ['8.2', '8.3', '8.4']
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}计算镜像标签
部署需要一个唯一且可追踪的镜像标签。提交 SHA 是约定俗成的选择。这个片段展示了您会在工作流中表达的标签推导逻辑——将引用和 SHA 转换为镜像仓库标签。
<?php
// Mirrors what the workflow computes for the image tag
$ref = 'refs/heads/main';
$sha = '9f41efadc0de1234567890abcdef0000deadbeef';
$branch = str_replace('refs/heads/', '', $ref);
$shortSha = substr($sha, 0, 7);
$tag = sprintf('registry.example.com/app:%s-%s', $branch, $shortSha);
echo $tag . PHP_EOL; // registry.example.com/app:main-9f41efa
echo 'is_main: ' . ($branch === 'main' ? 'yes' : 'no') . PHP_EOL;
?>构建并推送镜像
在主分支上,使用 docker/build-push-action,结合 BuildKit 和 GitHub Actions 缓存来构建 Docker 镜像。请先使用密钥令牌登录镜像仓库;绝不要将凭据硬编码。
build:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
push: true
target: runtime
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max密钥与 OIDC
请将凭据存储在代码仓库或环境的密钥中,并通过 ${{ secrets.NAME }} 引用——它们会在日志中被遮蔽。对于云部署,优先使用 OIDC:运行器通过 permissions: id-token: write 从 AWS/GCP 获取短期令牌,因此代码仓库中无需保存长期有效的密钥。
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
id-token: write # enables OIDC
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/deploy
aws-region: eu-central-1部署步骤与环境
请将生产环境部署置于 GitHub environment 的保护之后,也可以要求审核者批准。随后,部署步骤会触发您的发布流程——更新 Kubernetes 部署、更新 ECS 服务,或通过 SSH 登录服务器来拉取新镜像。
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: production # can require manual approval
url: https://app.example.com
steps:
- name: Roll out
run: |
kubectl set image deployment/app \
app=ghcr.io/${{ github.repository }}:${{ github.sha }}
kubectl rollout status deployment/app --timeout=120s快速检查
与在 Actions 中存储云密钥相比,OIDC 的主要安全优势是什么?
回顾
您在 GitHub Actions 中构建了 PHP CI/CD 流水线:在推送和 PR 时触发,使用带扩展的 setup-php,根据锁定文件缓存 Composer,使用带健康检查的 MySQL 服务容器,运行 PHPUnit 和 PHPStan,执行版本矩阵,然后仅在主分支上使用 GHA 缓存构建并推送镜像,最后执行经过 OIDC 身份验证且受环境保护的部署。
原则:根据锁定文件哈希设置缓存键,通过健康检查确认服务已准备就绪,使用 SHA 为镜像添加标签,并优先使用 OIDC 而不是存储密钥。
常见问题解答
「使用 GitHub Actions 实现 CI/CD」课时是免费的吗?
是的 — 「使用 GitHub Actions 实现 CI/CD」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 PHP Academy 课程的其余内容,请升级到 CoddyKit PRO。 PHP Academy 课程共包含 4 节课。
「使用 GitHub Actions 实现 CI/CD」这节课中我会学到什么?
每次推送时自动测试并部署 PHP 你通过在浏览器中直接运行的动手代码来练习 PHP Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 PHP Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 PHP Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「使用 GitHub Actions 实现 CI/CD」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 PHP Academy 课中编写并运行代码吗?
能。每节 PHP Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 将 PHP 应用容器化
- 多阶段构建与优化
- 使用 Docker Compose 构建本地技术栈
- 使用 GitHub Actions 实现 CI/CD