3. CI/CD 流水线基础:Jenkins/GitLab CI/CD 流水线概念、阶段划分与触发方式

在 Kubernetes 发布流水线中,CI/CD 流水线是自动化安全扫描与回滚触发的执行载体。理解流水线的核心概念、阶段划分与触发机制,是构建可靠发布流程的前提。本章聚焦 Jenkins 与 GitLab CI/CD 两种主流工具,对比其流水线模型与阶段设计。

3.1 流水线核心概念

CI/CD 流水线将软件交付过程分解为一系列自动化阶段,每个阶段包含一个或多个任务。流水线的核心价值在于:

  • 可重复性:每次执行使用相同的流程与配置,消除人为差异。
  • 可观测性:每个阶段的状态、日志与产物清晰可见。
  • 可控制性:支持手动审批、条件分支与失败回滚。
关键概念对照: Jenkins 使用 Pipeline(声明式/脚本式)定义流程;GitLab CI/CD 使用 .gitlab-ci.yml 文件定义流程。两者均支持阶段(stage)、任务(job)、触发条件(trigger)三大要素。

3.2 阶段划分模型

一个典型的 K8s 发布流水线通常包含以下阶段。下表对比了 Jenkins 与 GitLab CI/CD 的阶段定义方式:

阶段 Jenkins 实现方式 GitLab CI/CD 实现方式 典型任务
代码检出 checkout scm stage: fetch + git clone 拉取源码、子模块、LFS 文件
代码编译 sh 'mvn compile' stage: build + script: mvn compile 编译、依赖安装、静态资源构建
单元测试 sh 'mvn test' stage: test + script: mvn test 单元测试、代码覆盖率收集
安全扫描 sh 'trivy image ...' stage: security + script: trivy image ... SAST、DAST、镜像漏洞扫描、依赖检查
镜像构建与推送 sh 'docker build ...' + docker push stage: package + docker build + docker push Dockerfile 构建、镜像标签、推送至仓库
部署至 K8s sh 'kubectl apply ...' stage: deploy + kubectl apply 更新 Deployment、Service、ConfigMap
健康检查与回滚 sh 'kubectl rollout status ...' + 条件回滚 stage: verify + script: kubectl rollout status Pod 就绪检查、回滚至上一版本
阶段顺序注意: 安全扫描应放在镜像构建之前(对源码扫描)或镜像构建之后(对镜像扫描),但必须在部署之前完成。若安全扫描失败,应阻止后续阶段执行,避免有漏洞的镜像进入生产环境。

3.3 触发方式对比

流水线的触发方式决定了何时开始执行。Jenkins 与 GitLab CI/CD 均支持多种触发策略:

触发方式 Jenkins GitLab CI/CD 适用场景
代码推送 Webhook + Generic Webhook Trigger push 事件自动触发 开发分支、功能分支
合并请求 Webhook + GitHub Pull Request Builder merge_request 事件 代码审查前验证
定时触发 cron 语法配置 schedule 关键字 夜间安全扫描、定期依赖更新
手动触发 build 按钮 + 参数化构建 when: manual 关键字 生产环境部署、紧急回滚
上游流水线完成 Build after other projects needs + trigger 关键字 多项目依赖、微服务链式发布

3.4 流水线结构示意图

下图展示了一个包含安全扫描与回滚触发的 K8s 发布流水线阶段流程:

K8s 发布流水线阶段流程(含安全扫描与回滚触发) 代码检出 编译 & 单元测试 安全扫描 镜像构建推送 部署至 K8s 健康检查 扫描失败 → 阻断 回滚触发 说明: • 绿色箭头:正常流水线执行路径,阶段依次执行。 • 红色虚线:安全扫描失败时,流水线被阻断,不进入后续阶段。 • 紫色虚线:健康检查失败时,自动触发回滚操作,恢复至上一稳定版本。 • 回滚触发点可配置为手动确认或自动执行,取决于生产环境策略。 • 本图展示的是包含安全扫描与回滚能力的增强型流水线,非基础 CI/CD 流程。

3.5 触发条件配置示例

以下展示 GitLab CI/CD 中基于分支与标签的触发配置,以及 Jenkins 中基于 Webhook 的参数化触发:

GitLab CI/CD 触发配置(.gitlab-ci.yml 片段)

stages:
  - fetch
  - build
  - security
  - package
  - deploy
  - verify

variables:
  DOCKER_IMAGE: "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHORT_SHA}"

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: always
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: always
    - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
      when: always
    - when: never

security-scan:
  stage: security
  script:
    - trivy image --severity HIGH,CRITICAL --exit-code 1 ${DOCKER_IMAGE}
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: on_success
    - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
      when: on_success

deploy-k8s:
  stage: deploy
  script:
    - kubectl apply -f k8s/deployment.yaml
  environment:
    name: production
  rules:
    - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
      when: manual
      allow_failure: false

Jenkins 声明式 Pipeline 触发配置

pipeline {
    agent any
    triggers {
        // 代码推送触发(需安装 Generic Webhook Trigger 插件)
        GenericTrigger(
            genericVariables: [
                [key: 'REF', value: '$.ref']
            ],
            : 'my-secret-',
            causeString: 'Triggered by push to $REF',
            printContributedVariables: true,
            printPostContent: true
        )
        // 定时触发:每天凌晨 2 点执行安全扫描
        cron('0 2 * * *')
    }
    stages {
        stage('Security Scan') {
            when {
                expression { return env.BRANCH_NAME == 'main' || env.TAG_NAME =~ /^v\d+\.\d+\.\d+$/ }
            }
            steps {
                sh 'trivy image --severity HIGH,CRITICAL --exit-code 1 ${DOCKER_IMAGE}'
            }
        }
        stage('Deploy to K8s') {
            when {
                expression { return env.TAG_NAME =~ /^v\d+\.\d+\.\d+$/ }
            }
            input {
                message "确认部署至生产环境?"
                ok "确认部署"
            }
            steps {
                sh 'kubectl apply -f k8s/deployment.yaml'
            }
        }
    }
}
实践要点:
  • 安全扫描阶段应设置为 阻断性阶段:扫描失败时流水线立即终止,不执行后续部署。
  • 生产环境部署建议使用 手动触发(Jenkins 的 input 或 GitLab 的 when: manual),增加人工审核环节。
  • 回滚触发逻辑通常放在健康检查阶段之后,通过条件判断(如 kubectl rollout status 返回非零)自动执行 kubectl rollout undo。
  • 定时触发适合执行全量安全扫描或依赖更新,避免在每次代码提交时重复执行耗时任务。

3.6 阶段划分最佳实践

根据团队规模与发布频率,阶段划分可灵活调整。以下推荐两种常见模式:

模式 阶段数量 特点 适用场景
精简模式 4-5 个 编译 → 安全扫描 → 镜像构建 → 部署 → 验证 小型团队、快速迭代、低风险项目
完整模式 7-9 个 代码检出 → 编译 → 单元测试 → 安全扫描 → 镜像构建 → 集成测试 → 部署 → 健康检查 → 回滚 中大型团队、合规要求高、生产环境严格
阶段命名规范: 建议使用动词+名词的格式(如 build-app、scan-image、deploy-k8s),便于在流水线可视化界面中快速识别。避免使用模糊名称如 step1、job2。