下载工作台
项目运维与部署

CI/CD 流水线实战

试读上半部分 · 解锁后可读全文

第 3 章 · CI/CD 流水线实战

本章目标:搭建 Gitea → Jenkins → Registry → 集群 企业级流水线;理解多阶段门禁、制品追溯与 staging 自动部署 + prod 人工审批;让 demo-mall 每次 push 可重复、可审计。

学时建议:2.5~3 小时(含 2 小时跟练)

前置PaaS ch7、ch11ops-deploy ch02 环境矩阵;git-collab ch03~ch05 分支与 PR。


3.1 场景说明

项目内容
背景demo-mall API 代码在 Gitea;团队希望 push 后自动测试、构建镜像、部署 staging
痛点手工 docker build tag 混乱;prod 曾部署 latest 无法追溯
你的角色DevOps,维护 Jenkins Multibranch Pipeline
本章任务完成一次 push 触发全流程;Registry 可见 SHA tag;staging 镜像与构建一致
约束prod 阶段必须 人工 input;HIGH 漏洞 staging warn、prod 阻断(逐步收紧)

3.2 学完你能

能力验收标准
描述 CI/CD 架构画出 webhook → Jenkins → Registry → kubectl 全链路
编写/读懂 Jenkinsfile解释 Test、Build、Deploy 各 stage
配置质量门禁说出 staging vs prod 四项门禁差异
分支策略feature/develop/release/main 各触发什么
制品追溯填写一行 build 号 ↔ git SHA ↔ 镜像 tag
排错docker push 失败、kubectl 权限、旧镜像三问题定位

3.3 目标架构

git push ──► Gitea webhook ──► Jenkins Multibranch Pipeline
                                    │
                    ┌───────────────┼───────────────┐
                    ▼               ▼               ▼
                 单元测试        镜像构建+扫描      SBOM(可选)
                    │               │
                    └───────┬───────┘
                            ▼
                   Registry (tag=git SHA)
                            ▼
              staging 自动部署 ──► 人工审批 ──► prod
组件Namespace小紫 PaaS 商店
Giteadevopsgitea
Jenkinsdevopsjenkins
Registrydevopsdocker-registry

你应该看到PaaS 商店 中三组件 Running;Jenkins 能访问 Gitea 与 Registry 内网地址。


3.4 逐步跟练 · 第一步:准备仓库与 Webhook(约 30 分钟)

步骤 1 — 确认 demo-api 仓库

  • Gitea 中仓库 demo-mall/demo-api
  • 根目录含 Dockerfiletests/、下文 Jenkinsfile

步骤 2 — 创建 Multibranch Pipeline

  • Jenkins → 新建 Item → Multibranch Pipeline
  • Branch Sources:Gitea,扫描 feature/developrelease/main

步骤 3 — Gitea Webhook

  • 仓库 设置 → Webhook → Push 事件 → Jenkins 回调 URL

你应该看到:Webhook 测试返回 200;Jenkins Scan Repository Now 发现分支。


3.5 逐步跟练 · 第二步:Jenkinsfile 完整示例(约 45 分钟)

将以下 Jenkinsfile 放入仓库根目录,逐 stage 理解注释:

pipeline {
  agent { kubernetes { yaml '''
    apiVersion: v1
    kind: Pod
    spec:
      containers:
      - name: docker
        image: docker:24-dind
        securityContext: { privileged: true }
        volumeMounts: [{ name: dind, mountPath: /var/lib/docker }]
      volumes: [{ name: dind, emptyDir: {} }]
  ''' } }
  environment {
    REGISTRY = 'registry.devops.svc.cluster.local:5000'
    IMAGE    = "${REGISTRY}/demo-api"
    GIT_SHA  = "${env.GIT_COMMIT?.take(7)}"
    TAG      = "${env.BUILD_NUMBER}-${GIT_SHA}"
  }
  stages {
    stage('Checkout') {
      steps { checkout scm }
    }
    stage('Test') {
      steps {
        sh 'python -m pytest tests/ -q --junitxml=report.xml'
      }
      post { always { junit 'report.xml' } }
    }
    stage('Lint') {
      steps { sh 'flake8 app/ || true' }  // 逐步改为阻断
    }
    stage('Build & Push') {
      steps {
        sh """
          docker build -t ${IMAGE}:${TAG} -t ${IMAGE}:latest .
          docker push ${IMAGE}:${TAG}
        """
      }
    }
    stage('Scan') {
      steps {
        sh 'trivy image --severity HIGH,CRITICAL --exit-code 1 ${IMAGE}:${TAG} || true'
      }
    }
    stage('Deploy Staging') {
      steps {
        sh """
          kubectl set image deployment/demo-api \\
            demo-api=${IMAGE}:${TAG} -n staging-app
          kubectl rollout status deployment/demo-api -n staging-app --timeout=300s
        """
      }
    }
    stage('Deploy Prod') {
      when { branch 'main' }
      steps {
        input message: '发布到生产?', ok: '确认'
        sh """
          kubectl set image deployment/demo-api \\
            demo-api=${IMAGE}:${TAG} -n prod-app
        """
      }
    }
  }
  post {
    success { echo "Deployed ${TAG}" }

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。