Skip to content

CI/CD 与 DevOps ​

Java 架构师 · 可观测与工程化

CI/CD 把"代码到上线"自动化,DevOps 把研发与运维的壁垒打通。目标是快速、安全、可重复地交付——架构师需设计流水线、质量门禁与发布策略,让变更既快又稳。本章深入 CI(持续集成)、CD(持续交付/部署)、不可变制品、Git 工作流,再到 Jenkins Pipeline、GitLab CI、Argo CD GitOps,以及蓝绿/金丝雀发布与回滚的工程细节。

一、核心概念:CI / CD / 制品 ​

  • CI(持续集成):频繁合并 + 自动构建测试,尽早暴露冲突。关键是"主干上频繁小步提交",而非长期分支。
  • CD(持续交付 / 持续部署):构建产物自动经测试/预发到生产。持续交付需人工审批点;持续部署全自动(无人工卡点,靠强质量门禁兜底)。
  • 制品(Artifact):不可变镜像/包(用 commit SHA 打标签),一次构建多处部署,保证环境一致(开发/测试/生产跑同一个镜像,差异只来自配置注入)。
  • Git 工作流:GitFlow(分支多、适合发布节奏慢)、Trunk-Based(主干开发,推荐高成熟度团队,缩短反馈环)。

二、质量门禁:流水线的"该停就停" ​

流水线不是越快越好,要有阻断条件。左移(Shift-Left):把安全与质量检查尽早放入 CI:

  • 编译 + 单元测试(覆盖率门禁,如 < 60% 阻断)。
  • 静态扫描(SAST,如 SonarQube)、依赖漏洞扫描(如 Trivy)。
  • 镜像扫描(CVE)、契约测试(Provider/Consumer)。
  • 集成测试 + 性能基线(可选,耗时长放独立阶段)。

门禁失败必须阻断后续阶段并通知负责人,而非"带着失败继续跑"。

三、工具选型对比 ​

工具定位特点适用
Jenkins通用 CI 引擎插件多、需自运维、Pipeline as Code复杂定制、已有存量
GitLab CI一体化与 Git 紧耦合、YAML 定义、Runner 弹性GitLab 体系、一体化
Argo CDGitOps 部署声明式、K8s 原生、自动同步、可回滚K8s 环境 GitOps

四、GitLab CI 流水线示例 ​

yaml
stages: [build, test, image, deploy]
build:
  stage: build
  script: ./mvnw package -DskipTests
test:
  stage: test
  script: ./mvnw test
  coverage: '/Total.*?([0-9]+)%/'      # 覆盖率提取
image:
  stage: image
  script:
    - docker build -t registry/order:$CI_COMMIT_SHA .   # 用 SHA 打标签(不可变)
    - trivy image registry/order:$CI_COMMIT_SHA          # 镜像漏洞扫描(门禁)
deploy:
  stage: deploy
  script: kubectl set image deploy/order order=registry/order:$CI_COMMIT_SHA
  only: [main]

五、Jenkins Pipeline(声明式) ​

groovy
pipeline {
  agent any
  stages {
    stage('Build')   { steps { sh './mvnw package -DskipTests' } }
    stage('Test')    { steps { sh './mvnw test' } }
    stage('Image')   { steps { sh 'docker build -t registry/order:${GIT_COMMIT} .' } }
    stage('Deploy')  { steps { sh 'kubectl apply -f k8s/' } }
  }
  post { failure { slackSend message: '构建失败: ${BUILD_URL}' } }
}

流水线的致命陷阱

  • 制品不可变被破坏:同一版本重复构建 → 环境漂移(测试过的镜像 ≠ 上线的镜像)。必须用 commit SHA 打标签,一次构建、多环境复用。
  • 质量门禁缺失:跳过单测/扫描直接上线,技术债累积;门禁失败应阻断。
  • 手动发布无回滚:发布即"祈祷"。需蓝绿/金丝雀 + 一键回滚。
  • 密钥进仓库:凭据硬编码进镜像/清单 → 泄露风险。用 Secret 管理(Vault/K8s Secret/CI 变量),绝不入库。
  • 长分支少集成:分支存活数周 → 合并地狱。提倡 Trunk-Based + 小步提交。

六、GitOps:Git 为唯一真实源(Argo CD) ​

GitOps 思想:Git 仓库里的声明(K8s 清单/Helm values)就是集群期望状态,Argo CD 持续比对"Git 声明"与"集群实际",不一致就自动同步(或告警等待)。变更 = 提 PR,可审计、可回滚(回滚 = 回退 commit)。

优势:

  • 可审计:谁、何时、改了什么,Git 历史即审计日志。
  • 可回滚:回退一个 commit 即回滚(秒级,比手动 kubectl 可靠)。
  • 一致性:集群状态永远向 Git 对齐,杜绝"手动改了集群但没人知道"。
  • 漂移检测:有人手动 kubectl edit,Argo CD 发现与 Git 不符 → 自动纠正或告警。

七、发布策略:蓝绿 / 金丝雀 ​

策略机制回滚适用
蓝绿(Blue/Green)两套环境,流量整体切到绿,异常切回蓝切流量即可(瞬时)无状态、可整体切换
金丝雀(Canary)1%→10%→100% 渐进放量回滚灰度部分需观察真实流量

金丝雀决策依据(必须可观测):错误率、P99 延迟、业务指标(下单成功率)。任一超阈值 → 暂停放量/回滚。配合 Argo Rollouts 可做自动化分析(自动推进或回滚)。

发布即风险:回滚能力是底气

没有回滚能力的发布 = 赌博。回滚必须"一键/秒级":蓝绿靠切流量、金丝雀靠缩灰度、GitOps 靠回退 commit。发布前确认:回滚路径、回滚触发条件、回滚验证(回滚后是否真恢复)。大促/核心变更要"冻结期"(如双11前禁止非必要发布)。

八、最佳实践 ​

  • 一次构建、多环境复用同一镜像(配置由环境注入,不进镜像)。
  • 发布策略:金丝雀(小流量验证)或蓝绿(瞬时切换),配合可观测验证再放量。
  • 用 GitOps 管理 K8s 清单,变更可审计、回滚 = 回退 commit。
  • 流水线即代码,纳入版本控制与评审;门禁失败阻断。
  • 密钥走 Secret 管理,绝不进仓库;长任务放独立 stage 避免拖慢反馈。

本节小结

CI/CD 把交付变成可重复的工程动作:CI 频繁集成尽早暴露冲突,CD 自动推进到生产,不可变制品(commit SHA 标签)保证环境一致。关键是质量门禁左移且能阻断——把安全/测试挡在合并前而非事后。发布策略上,金丝雀用渐进放量+可观测决策、蓝绿用瞬时切换,二者都要求"一键回滚"作为底气。GitOps(Argo CD)让 Git 成为唯一真实源:变更即 PR、可审计、回滚 = 回退 commit、漂移可检测。架构师要设计的是"又快又稳"的发布机制——用自动化替代人工判断,用回滚能力换发布勇气。

📚 官方文档与参考资料 ​

✏️ 练习与自测 ​

  1. 设计题:设计一条 Java 服务的 CI/CD 流水线,列出每个阶段(build/test/image/deploy)的质量门禁与阻断条件(含覆盖率、镜像扫描、契约测试)。
  2. 设计题:用 Argo CD 实现"回滚到上一个稳定版本",说明 GitOps 下如何操作、为什么比手动 kubectl 回滚更可靠。若有人手动改了集群,会发生什么?
  3. 设计题:金丝雀发布中,用哪些可观测指标(错误率/P99/业务指标)决定"继续放量还是回滚"?给出自动推进与自动回滚的规则阈值。
  4. 辨析题:为什么"制品不可变"是 CI/CD 的基石?如果测试通过的镜像在上线前被重新构建,会带来什么风险?如何保证"测试过的就是上线的"?