CI/CD 流水线实战
CI/CD 把"代码提交到生产上线"的漫长过程自动化:CI(持续集成)负责构建、测试、打包,CD(持续交付/部署)负责把产物部署到环境。本文以 GitLab CI 与 GitHub Actions 为例,讲透多环境部署、环境配置与版本回滚。
CI/CD 基础
流水线的三个阶段
CI(持续集成):
├─ 代码提交 → 触发流水线
├─ 编译、单测、静态检查、镜像构建
└─ 产出:可发布的镜像/包
CD(持续交付):
├─ 部署到测试/预发环境
├─ 自动化测试、验收
└─ 产出:可发布版本
CD(持续部署):
├─ 自动部署到生产
└─ 通常保留人工审批门禁一次完整流水线
提交代码 → 代码检查 → 单测 → 构建 JAR → 构建镜像
→ 推送镜像仓库 → 部署测试环境 → 集成测试
→ 部署预发环境 → 冒烟测试 → 审批 → 部署生产一、GitLab CI
核心概念
GitLab CI 关键元素:
├─ .gitlab-ci.yml:流水线定义文件(仓库根目录)
├─ Stages:阶段(流水线顺序执行)
├─ Jobs:任务(属于某个 Stage,可并行)
├─ Runner:执行任务的代理(可以是 K8s/机器)
└─ 触发器:push、merge request、定时、手动.gitlab-ci.yml 示例
yaml
stages:
- build
- test
- package
- deploy
variables:
MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
IMAGE_TAG: $CI_COMMIT_SHORT_SHA # 提交短哈希作镜像标签
cache: # 缓存依赖加速
paths:
- .m2/repository
# 构建阶段
build:
stage: build
image: maven:3.9-eclipse-temurin-21
script:
- mvn clean compile -DskipTests
tags: [maven-runner]
# 测试阶段
test:
stage: test
image: maven:3.9-eclipse-temurin-21
script:
- mvn test
artifacts: # 测试报告
paths:
- target/surefire-reports/
when: always
# 打包 + 推送镜像
package:
stage: package
image: docker:24
services:
- docker:24-dind # Docker in Docker
script:
- docker build -t $CI_REGISTRY_IMAGE:$IMAGE_TAG .
- docker push $CI_REGISTRY_IMAGE:$IMAGE_TAG
only:
- main
# 部署到测试环境
deploy-test:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/order-service
order-service=$CI_REGISTRY_IMAGE:$IMAGE_TAG -n test
environment:
name: test
only:
- main多环境部署
多环境定义:
├─ environment: name: dev/test/prod
├─ 每个环境一个 deployment Job
└─ 生产环境加人工审批:
deploy-prod:
stage: deploy
script:
- kubectl set image deployment/order-service
order-service=$CI_REGISTRY_IMAGE:$IMAGE_TAG -n prod
environment:
name: prod
when: manual # 手动触发(审批门禁)
only:
- main二、GitHub Actions
核心概念
GitHub Actions 关键元素:
├─ .github/workflows/*.yml:工作流定义
├─ Job:任务(可并行/依赖)
├─ Step:步骤(命令或 Action)
├─ Runner:执行环境(ubuntu-latest 等)
└─ Event:触发条件(push、pull_request、workflow_dispatch)工作流示例
yaml
name: CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch: # 手动触发
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
cache: maven
- name: Run tests
run: mvn test
build-and-push:
needs: test # 依赖 test 完成
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: |
docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
- name: Push to GHCR
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker push ghcr.io/${{ github.repository }}:${{ github.sha }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
environment: production # 环境门禁(审批)
steps:
- name: Deploy to K8s
run: |
kubectl set image deployment/order-service \
order-service=ghcr.io/${{ github.repository }}:${{ github.sha }} -n prodSecrets 管理
敏感信息用 GitHub Secrets:
├─ Settings → Secrets → Actions
├─ ${{ secrets.KUBE_CONFIG }}:K8s 证书
└─ ${{ secrets.REGISTRY_PASSWORD }}:镜像仓库密码
原则:
├─ 密钥不进代码仓库
├─ 环境隔离:prod 与 dev 用不同 Secret
└─ 定期轮换三、生成式环境配置
问题:环境差异
同一个镜像部署到多个环境,配置不同:
├─ dev:连测试库、日志 DEBUG
├─ test:连测试库、日志 INFO
├─ prod:连生产库、日志 WARN
└─ 配置不能写死在镜像里方案一:环境变量注入
yaml
# K8s 部署时按环境注入(Deployment 中)
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
- name: DB_URL
value: jdbc:mysql://prod-db:3306/order方案二:ConfigMap 按环境生成
流水线按环境生成 ConfigMap:
├─ 维护 config/dev.yaml、config/prod.yaml
├─ 流水线部署时选择对应环境文件
└─ kubectl apply -f config/$ENV/order-config.yaml方案三:GitOps 仓库(推荐)
GitOps 模式:
├─ 独立部署仓库(manifest 仓库)
├─ 每个环境一个目录:environments/dev、environments/prod
├─ 配置即代码,可评审、可回滚
├─ 流水线只更新镜像版本(改 yaml 的 image tag)
└─ ArgoCD 自动同步
示例结构:
├─ environments/prod/order-service/deployment.yaml
├─ environments/prod/order-service/configmap.yaml
└─ environments/prod/order-service/hpa.yaml生成式配置最佳实践:
├─ 配置与代码分离(不在镜像内)
├─ 环境差异用 profile / env / ConfigMap 表达
├─ 配置变更走代码评审(GitOps)
├─ 生产配置加保护(禁止随意修改)
└─ 敏感配置走 Secret / 密钥管理四、版本管理
版本策略
镜像/应用版本策略:
├─ 语义化版本:1.2.3(主.次.补丁)
├─ 或 Git 哈希:a3f8c21(精确可追溯)
└─ 推荐:tag 用版本号,CI 用短哈希,生产记录对应关系
版本追溯:
├─ 每次发布记录:镜像 tag + 代码 commit + 配置版本
├─ 方便回滚与排查
└─ 发布清单(Release Notes)自动化生成回滚机制
回滚场景与手段:
├─ 应用回滚:
│ └─ kubectl rollout undo deployment/order-service
│ (回滚到上一个 Deployment 版本)
├─ 镜像回滚:
│ └─ 重新部署上一个镜像 tag
├─ 配置回滚:
│ └─ GitOps:revert 部署仓库的配置提交
└─ 数据库回滚:
└─ 数据库迁移脚本要支持向下迁移(谨慎)回滚演练
回滚要点:
├─ 回滚要"快速、可逆、可验证"
├─ 提前演练(大促前)
├─ 回滚后验证(健康检查 + 业务指标)
└─ 回滚决策记录(审计)五、流水线安全
安全防线
CI/CD 安全清单:
├─ 1. 密钥管理:Secret/凭据库,禁止明文
├─ 2. 依赖扫描:流水线集成漏洞扫描(Trivy、OWASP)
├─ 3. 镜像签名:保证镜像来源可信(Cosign)
├─ 4. 审批门禁:生产部署人工审批
├─ 5. 权限最小化:CI 账号只给部署所需权限
├─ 6. 制品不可变:镜像构建后不可修改
└─ 7. 审计日志:记录谁在何时发布了什么六、多服务流水线设计
单仓库 vs 多仓库
├─ Monorepo(单仓库):
│ ├─ 一个流水线构建多个服务
│ ├─ 变更检测:只有变更的服务重新构建部署
│ └─ 适合中小团队
├─ 多仓库(每服务一仓库):
│ ├─ 每个服务独立流水线
│ ├─ 发布解耦
│ └─ 适合大团队/独立发布节奏依赖与发布顺序
多服务发布依赖:
├─ 先发依赖方(如 Nacos 配置、基础库)
├─ 或保证兼容(老版本调用方兼容新版本提供方)
├─ 网关最后发布(入口变更影响面大)
└─ 用发布平台编排跨服务发布顺序总结
CI/CD 的本质是把"代码到生产"的每个步骤标准化、可重复、可追溯:GitLab CI 与 GitHub Actions 负责构建测试打包,生成式环境配置解决多环境差异,版本管理与回滚机制兜底线上风险。生产级流水线的核心不是"自动化程度多高",而是"每个环节可验证、可审批、可回滚"——把发布变成一件可控的工程操作。