文章

CI-CD 最佳实践与安全

CI-CD 最佳实践与安全

概述

工具是手段,实践才是核心。本文覆盖 CI/CD 落地中最关键的五个维度:分支策略、测试金字塔、安全左移、制品管理和发布策略。

一、分支策略

Git Flow(经典,适合版本化发布)

main ────●────────●────────●────  (生产)
          \      / \      /
release ──●────●── ●────●────     (发布分支)
            \  /     \  /
develop ────●────────●────────     (开发主线)
              \      /
feature ───────●────●              (功能分支)
适用不适用
移动端 App / 客户端软件Web 服务(发布周期太长)
多版本并行维护小团队、高频部署

GitHub Flow(简单,适合持续部署)

main ──────────────────●──●──  (始终可部署)
         \      \     /
feature ──●──● ──●──●            (特性分支 → PR → 合并即部署)
适用不适用
Web 服务 / SaaS需要多版本并行维护
小到中型团队严格的发布审批流程

Trunk-Based Development(推荐,CI/CD 最佳搭档)

main ──●─●─●─●─●─●─●─●──  (每天合并,短生命周期分支)
         \/
feature ──●                     (分支存活 < 1 天)

核心原则:

  • 分支存活时间 < 24 小时
  • Feature Flag 控制未完成功能的可见性
  • 高频合并 → 小批量变更 → 冲突少、回滚容易
  • 需要成熟的自动化测试 + 代码审查能力

选型建议

版本化发布(App/客户端):Git Flow
SaaS/Web 服务:         Trunk-Based Development
开源项目(外部贡献者):GitHub Flow

二、测试金字塔

         ╱  E2E 测试 ╲          (少量,慢,覆盖关键用户场景)
        ╱──────────────╲
       ╱  集成测试       ╲        (中等,API/DB/外部依赖)
      ╱──────────────────╲
     ╱    单元测试         ╲       (大量,快,覆盖核心逻辑)
    ╱────────────────────────╲
层级比例速度工具(Go 项目)目的
单元测试70%毫秒go test验证函数/方法逻辑
集成测试20%go test -tags=integration + testcontainers验证组件交互
E2E10%分钟Cypress / Playwright验证端到端流程

CI Pipeline 中的测试策略

# 快速失败原则:Lint → 单元测试 → 集成测试 → E2E
# 前置步骤失败自动跳过后续(节约资源)

lint:          # 1 分钟内   ← 最便宜的检查
  if: always()

unit-test:     # 2 分钟内
  needs: lint

integration:   # 5 分钟内
  needs: unit-test

e2e:           # 10 分钟内  ← 仅在重要 PR 或 main 分支运行
  needs: integration
  if: github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'e2e')

三、安全左移(Shift-Left Security)

CI 流水线安全扫描点

Code Commit
    ├── SAST (静态应用安全测试)        → SonarQube, CodeQL
    ├── SCA  (软件组成分析)            → Dependency Track, Snyk
    ├── Secret 扫描                    → truffleHog, Gitleaks
    └── IaC 扫描                       → tfsec, Checkov

Dockerfile Commit
    └── Dockerfile Lint               → hadolint

Image Build
    ├── 镜像扫描                       → Trivy, Grype
    └── SBOM 生成                      → Syft, CycloneDX

Registry Push
    └── 准入控制                       → OPA/Gatekeeper, Kyverno

Trivy 扫描集成示例

# GitHub Actions
- name: Scan Dockerfile
  uses: aquasecurity/trivy-action@master
  with:
    scan-type: 'config'                     # 扫描 Dockerfile/Helm/K8s YAML
    severity: 'HIGH,CRITICAL'
    exit-code: 1                            # 高危则失败

- name: Scan image
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}'
    format: 'sarif'
    output: 'trivy-results.sarif'
    severity: 'CRITICAL,HIGH'

Secret 扫描

# 防止密钥/Token/AK-SK 提交到仓库
- name: Secret scan
  uses: gitleaks/gitleaks-action@v2
  with:
    config-path: .gitleaks.toml

完整安全集成样例(生产级 GitHub Actions)

name: Security Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 6 * * 1'                    # 每周一全量扫描

jobs:
  # ── 1. SAST(静态代码分析)──
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: SonarQube Scan
        uses: SonarSource/sonarqube-scan-action@v3
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_URL }}
        with:
          args: >
            -Dsonar.projectKey=my-project
            -Dsonar.qualitygate.wait=true

  # ── 2. SCA(依赖漏洞扫描)──
  sca:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          go mod download
      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          format: 'sarif'
          output: 'trivy-fs-results.sarif'
          severity: 'CRITICAL,HIGH'
      - name: Upload Trivy scan results
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: 'trivy-fs-results.sarif'

  # ── 3. Secret 检测 ──
  secret-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0                    # 全量历史(检测历史提交)
      - name: Gitleaks
        uses: gitleaks/gitleaks-action@v2
        with:
          config-path: .gitleaks.toml

  # ── 4. IaC 扫描 ──
  iac-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Checkov scan
        uses: bridgecrewio/checkov-action@master
        with:
          directory: .
          framework: terraform,kubernetes,helm
          soft_fail: false                  # 硬失败

  # ── 5. 镜像构建 + 扫描 + 签名 ──
  image-security:
    needs: [sast, sca, secret-scan, iac-scan]
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write                       # Cosign keyless signing 所需
    steps:
      - uses: actions/checkout@v4
      - name: Build image
        uses: docker/build-push-action@v6
        with:
          context: .
          push: false
          load: true
          tags: my-app:scan
      - name: Trivy image scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'my-app:scan'
          format: 'sarif'
          output: 'trivy-image-results.sarif'
          severity: 'CRITICAL,HIGH'
          exit-code: 1
      - name: Generate SBOM
        uses: anchore/sbom-action@v0
        with:
          image: 'my-app:scan'
          format: 'spdx-json'
          output-file: 'sbom.spdx.json'
      - name: Upload SBOM as artifact
        uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: sbom.spdx.json
      - name: Push & Cosign sign
        run: |
          docker push ${{ env.REGISTRY }}/my-app:${{ github.sha }}
          # Cosign keyless signing(OIDC + Sigstore)
          cosign sign --yes \
            ${{ env.REGISTRY }}/my-app:${{ github.sha }}

供应链安全(Software Supply Chain)

SLSA 框架简介

SLSA (Supply-chain Levels for Software Artifacts):

Level 0: 无任何保证
Level 1: 构建有文档记录(出处 provenance)
Level 2: 使用版本控制和托管构建服务
Level 3: 审计和防篡改构建(隔离环境、签名 attestation)
Level 4: 最高级别:需要两位独立人员审查 + 密封构建

目前主流工具链可达到 Level 2-3

SBOM(软件物料清单)

# SBOM = 镜像/二进制包含的所有组件的"成分清单"
# 用途:
# 1. 漏洞影响面分析:Log4Shell 出现 → 查 SBOM 确认哪些镜像受到影响
# 2. 合规审计:开源许可证识别与合规检查
# 3. 供应链可视化

# 生成 SPDX / CycloneDX 两种标准格式
syft my-app:scan -o spdx-json > sbom.spdx.json
syft my-app:scan -o cyclonedx-json > sbom.cyclonedx.json

# 扫描 SBOM 中的漏洞
grype sbom:sbom.spdx.json

Cosign 镜像签名验证

# 签名流程(构建时)
cosign sign --key cosign.key ${IMAGE}:${TAG}

# Keyless 签名(OIDC + GitHub Actions identity)
cosign sign --yes ${IMAGE}:${TAG}

# 部署时验证(K8s Admission Webhook 或 ArgoCD)
cosign verify \
  --certificate-identity "https://github.com/my-org/my-repo/.github/workflows/ci.yml@refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  ${IMAGE}:${TAG}

# 跨集群准入控制(OPA Gatekeeper 策略)
# 拒绝未签名或签名无效的镜像

Harbor 安全策略

# Harbor 仓库端安全策略(在镜像推送到仓库后自动执行)
# 1. 漏洞扫描(Trivy/Clair 后台自动扫描)
# 2. 策略引擎:
#    - 禁止有 HIGH/CRITICAL 漏洞的镜像被拉取
#    - 禁止未签名的镜像部署到生产集群
#    - 限制特定项目的镜像来源
# 3. 代理缓存(缓存 Docker Hub/外部镜像,防止拉取限流)

三、安全左移(Shift-Left Security)

CI 流水线安全扫描点

Code Commit
    ├── SAST (静态应用安全测试)        → SonarQube, CodeQL
    ├── SCA  (软件组成分析)            → Dependency Track, Snyk
    ├── Secret 扫描                    → truffleHog, Gitleaks
    └── IaC 扫描                       → tfsec, Checkov

Dockerfile Commit
    └── Dockerfile Lint               → hadolint

Image Build
    ├── 镜像扫描                       → Trivy, Grype
    └── SBOM 生成                      → Syft, CycloneDX

Registry Push
    └── 准入控制                       → OPA/Gatekeeper, Kyverno

Trivy 扫描集成示例

# GitHub Actions
- name: Scan Dockerfile
  uses: aquasecurity/trivy-action@master
  with:
    scan-type: 'config'                     # 扫描 Dockerfile/Helm/K8s YAML
    severity: 'HIGH,CRITICAL'
    exit-code: 1                            # 高危则失败

- name: Scan image
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}'
    format: 'sarif'
    output: 'trivy-results.sarif'
    severity: 'CRITICAL,HIGH'

Secret 扫描

# 防止密钥/Token/AK-SK 提交到仓库
- name: Secret scan
  uses: gitleaks/gitleaks-action@v2
  with:
    config-path: .gitleaks.toml

四、制品管理

Docker 镜像最佳实践

# ── 多阶段构建 ──
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /app/server .

FROM alpine:3.20
RUN apk --no-cache add ca-certificates tzdata
COPY --from=builder /app/server /app/server
USER 1000:1000                              # 非 root 运行
EXPOSE 8080
ENTRYPOINT ["/app/server"]

镜像标签策略

# 推荐多标签策略
harbor.example.com/my-app:sha-abc1234      # 精确追溯到 Commit
harbor.example.com/my-app:main              # 当前 main 最新
harbor.example.com/my-app:v1.2.3            # SemVer 版本(Release)

# 避免
harbor.example.com/my-app:latest            # 不明确,禁止

制品仓库选型

注册表适用特点
Harbor企业自建镜像扫描、RBAC、代理缓存、Helm Chart
Docker Hub个人/小团队免费有限制、公开/私有
GHCRGitHub 项目与 Actions 集成天然、Packages 统一管理
ECR/ACR/GCR云平台项目免运维、与云服务深度集成

五、发布策略

四种策略对比

策略风险回滚速度资源成本适用
滚动更新分钟级默认选择
蓝绿部署秒级2x 资源核心服务
金丝雀发布最低分钟级1.2x流量大、验证需求
A/B 测试1.5x产品实验

金丝雀发布完整流程

# Argo Rollouts 金丝雀配置
strategy:
  canary:
    steps:
    - setWeight: 10           # 10% 流量
    - pause: { duration: 10m }
    - analysis:               # 自动分析(Prometheus)
        templates:
        - templateName: error-rate-check
    - setWeight: 50           # 50% 流量
    - pause: { duration: 30m }
    - setWeight: 100

回滚策略

# ArgoCD 一键回滚
argocd app rollback my-app <revision-number>

# Helm 回滚
helm rollback my-release <revision>

# K8s 原生回滚
kubectl rollout undo deployment/my-app
kubectl rollout undo deployment/my-app --to-revision=3

综合 CI/CD Pipeline 参考

┌────────────────────────────────────────────────────────────────┐
│                        CI Phase                                │
├────────────────────────────────────────────────────────────────┤
│ Push/PR → Lint → Unit Test → Security Scan → Build → Push     │
│                      ↓ (Pass)                                  │
│           Integration Test → E2E Test → Artifact Push         │
├────────────────────────────────────────────────────────────────┤
│                        CD Phase (GitOps)                       │
├────────────────────────────────────────────────────────────────┤
│  Git Image Tag Update → PR Review → Merge                     │
│         → ArgoCD Auto Sync → Health Check                     │
│                ↓ 失败                                          │
│           Auto Rollback                                       │
└────────────────────────────────────────────────────────────────┘

常见问题 / 坑点

问题原因解决方案
CI 越来越慢构建环境膨胀、依赖无缓存缓存优化 + 并行 Job + 增量构建
测试不稳定(Flaky tests)时间依赖/竞态/外部服务重试机制 + Retry + Mock 外部依赖
凭据泄露到 Git 历史误提交 Secret 文件git filter-branch 清理 + Secret 扫描
镜像体积膨胀未清理构建缓存多阶段构建 + .dockerignore
部署后服务不可用无就绪探针/冒烟测试Readiness Probe + 部署后自动冒烟测试
跨环境配置不一致手动修改环境差异统一用 Kustomize overlays 或 Helm values

关联知识

参考资源

学习时间

阶段时间备注
初次学习2026-07-14分支策略 + 测试 + 安全 + 制品 + 发布

状态: 📖 已掌握 下次复习日期: 2026-08-14