CI/CD 流水线设计
指导 Agent 将流水线拆为 lint、测试、构建、安全扫描、制品晋升与部署阶段,并定义失败快速、可缓存与可重试的节点。
阶段流水线
默认串行门禁顺序:静态检查 → 自动化测试 → 可复现构建 → 发布到目标环境。PR 与主分支可裁剪部署阶段或仅保留预览。
PR / push
│
▼
┌──────┐ ┌──────┐ ┌───────┐ ┌────────┐
│ lint │ ──► │ test │ ──► │ build │ ──► │ deploy │
└──────┘ └──────┘ └───────┘ └────────┘
│ │ │ │
└─ 失败即停 └─ 可并行 job └─ 不可变制品 └─ 蓝绿/金丝雀/GitOps
完整的四阶段 GitHub Actions CI 流水线示例(lint 与 test 并行,build 依赖两者完成):
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
lint:
name: Lint
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci --prefer-offline
- run: npm run lint
test:
name: Test
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci --prefer-offline
- run: npm test -- --coverage --ci
- uses: actions/upload-artifact@v4
if: always()
with:
name: coverage
path: coverage/
build:
name: Build
runs-on: ubuntu-24.04
timeout-minutes: 25
needs: [lint, test]
outputs:
image-tag: ${{ steps.tag.outputs.tag }}
steps:
- uses: actions/checkout@v4
- id: tag
run: |
VERSION=$(node -p "require('./package.json').version")
SHA=$(git rev-parse --short HEAD)
echo "tag=${VERSION}-${SHA}" >> "$GITHUB_OUTPUT"
- name: Build Docker image
run: |
docker build \
--label "git.sha=${{ github.sha }}" \
-t myapp:${{ steps.tag.outputs.tag }} .
- uses: actions/upload-artifact@v4
with:
name: image-tag
path: /dev/null
retention-days: 1
deploy:
name: Deploy to Staging
runs-on: ubuntu-24.04
timeout-minutes: 15
needs: build
if: github.ref == 'refs/heads/main'
environment: staging
steps:
- name: Deploy ${{ needs.build.outputs.image-tag }}
run: |
echo "Deploying image tag: ${{ needs.build.outputs.image-tag }}"
# kubectl set image deployment/myapp myapp=myregistry/myapp:${{ needs.build.outputs.image-tag }}
环境晋升
SKILL 中写清「谁可以推进到哪一环境」与自动/人工 gate,避免同一套流水线在未知条件下直打生产。
| 环境 | 典型触发 | 晋升门禁 | 数据 / 配置 |
|---|---|---|---|
| Dev | 分支 push、草稿 PR | lint、快路径单测 | 合成数据、占位密钥 |
| Staging | 合并 main、RC tag | 全量测试、安全扫描、契约测试 | 脱敏快照、与生产同型配置 |
| Prod | 发布审批、版本 tag | 人工 gate、金丝雀/蓝绿、回滚预案 | OIDC / 短时 token,禁止长期 PAT 入库 |
落地要点
SKILL 列出必选门禁与可选建议项;主分支与 PR 的差异(如是否部署预览环境);并发与 cancel-in-progress 策略避免排队浪费。
制品不可变 tag 与 SBOM/签名若需要,写明阶段顺序与产物存储。
部署策略:蓝绿、金丝雀或与 Argo/Flux 的 GitOps 同步;回滚触发条件与人工审批 gate 文档化。
- 缓存:依赖目录、Docker layer、Terraform provider 缓存键设计。
- 矩阵:语言版本与 OS 维度的上限,避免组合爆炸。
- 可观测:流水线 trace、步骤耗时与失败通知渠道。
制品版本化策略:语义化版本 + Git SHA 组合,超时配置与失败通知示例:
# 版本化策略:semver + git SHA(在 build job 中使用)
- id: version
run: |
VERSION=$(node -p "require('./package.json').version")
SHA=$(git rev-parse --short=8 HEAD)
BUILD_DATE=$(date -u +%Y%m%d)
TAG="${VERSION}+${BUILD_DATE}.${SHA}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "semver=${VERSION}" >> "$GITHUB_OUTPUT"
# 并行 job 的 needs 依赖配置
jobs:
security-scan:
needs: build # 等待 build 完成后才扫描
timeout-minutes: 15 # 超时:防止扫描任务挂起
deploy-staging:
needs: [build, security-scan] # 多 job 依赖
# 失败通知:Slack webhook(在 on-failure 步骤中添加)
- name: Notify Slack on failure
if: failure()
uses: slackapi/slack-github-action@v1.27.0
with:
payload: |
{
"text": "CI failed on ${{ github.ref }}",
"blocks": [{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Pipeline failed*: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>"
}
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
密钥与凭据
流水线里出现的每一个 secret 都应在 SKILL 中对应到「供给方式」与「轮换责任」,而不是仅写变量名。
使用 OIDC 免密钥获取 AWS 临时凭据的完整示例:
# OIDC federation:无需长期 AWS Access Key 的部署 job
deploy:
runs-on: ubuntu-24.04
permissions:
id-token: write # 必须显式授权 OIDC token
contents: read
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
role-session-name: github-actions-deploy
aws-region: us-east-1
# 信任策略中需绑定 sub: repo:myorg/myrepo:ref:refs/heads/main
# 避免仅用 audience 或环境名作为唯一条件
- name: Push image to ECR
run: |
aws ecr get-login-password | \
docker login --username AWS \
--password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:${{ needs.build.outputs.image-tag }}
# 对应的 IAM 角色信任策略(JSON 片段)
# {
# "StringEquals": {
# "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
# "token.actions.githubusercontent.com:sub":
# "repo:myorg/myrepo:ref:refs/heads/main"
# }
# }
阶段墙钟估算
按各阶段典型耗时(分钟)粗算一次完整流水线的墙钟时间;勾选并行时表示 lint 与 test 在同一波次并行跑完后再进入 build。数值仅保存在本会话的 sessionStorage,键名与其他页面区分。
各阶段耗时(分钟)
SKILL 片段
---
name: ci-cd-pipeline-design
description: 设计分阶段、可缓存、带门禁的 CI/CD 流水线
tags: [ci-cd, github-actions, devops]
---
# 流水线阶段设计
1. 阶段划分:lint → test → build → deploy,PR 可裁剪 deploy
2. 并行优化:lint 与 test 同波次并行,build 等待二者完成(needs: [lint, test])
3. 超时保护:每个 job 设置 timeout-minutes,防止挂起占用 runner
4. 并发控制:concurrency.group 含分支/PR,main 分支禁止 cancel-in-progress
# 制品与版本化
5. 版本化策略:semver(package.json/git tag)+ git SHA 短哈希组合 tag
6. 不可变制品:push 后仅引用 digest 或组合 tag,不覆盖 latest
7. 制品存储:通过 actions/upload-artifact 传递 job 间产物
# 密钥与凭据
8. OIDC 优先:AWS/GCP/Azure 均支持 id-token: write + federation,无需长期 key
9. 最小权限:顶层 permissions: {} 收紧,job 级按需放宽
10. 环境隔离:PR 流水线使用只读凭据,生产 deploy 绑定 environment: production
# 失败处理与通知
11. 失败快速:lint/test 失败立即停止,不进入 build/deploy
12. 失败通知:if: failure() + Slack/邮件 webhook,含 run URL 与分支信息
13. 缓存键:依赖锁文件哈希 + runner OS,restore-keys 降级但不混用环境
# 门禁清单
14. 必选门禁:lint、unit test、安全扫描(至少 SAST)
15. 可选门禁:集成测试、性能基准、bundlesize 回归、镜像扫描
16. 审批 gate:生产 deploy 须在 environment 配置 required reviewers