Skip to content

流程即镜像:数智化语境下流水线该怎么设计(下)

从"四个坑"到"怎么避"

上篇讲完了四个坑,但读完之后大概率是这种反应——

"我知道这些坑了,但我手头的项目已经在跑了,里面堆了一堆历史包袱。总不能推倒重来吧?我现在能改什么?"

这是个好问题。

要避坑,不一定要推倒重做。真正要做的是把 workflow 这件事拆成清晰的"几层"——把判断、数据、执行放在不同的位置,让上篇的四个坑在结构上就没有立足之地。

本文要做的就是这件事:用具体的发布场景演示如何拆,最后给一张判断表,让不同阶段的团队知道"自己该做到什么程度"。


避坑的朴素思路:分清楚三层

反面:所有事都堆在一个文件里

某团队的发布配置一开始长这样(简化版):

yaml
# 发布配置(早期版本)
name: publish

on:
  push:
    branches: [main]

jobs:
  deploy:
    steps:
      - name: 拉代码
        run: git clone ...

      - name: 跑测试
        run: npm test

      - name: 检查是不是新功能
        run: |
          if grep -q "feat:" commit.log; then
            echo "new_feature=true" >> $GITHUB_ENV
          fi

      - name: 检查是不是涉及支付链路
        run: |
          if grep -q "payment" commit.log; then
            echo "touch_payment=true" >> $GITHUB_ENV
          fi

      - name: 业务规则判断:能不能发
        run: |
          if [ "$new_feature" = "true" ] && [ "$touch_payment" = "true" ]; then
            echo "本次发布包含新功能 + 支付链路变更,禁止周五上线"
            exit 1
          fi

      - name: 打镜像
        run: docker build ...

      - name: 推镜像
        run: docker push ...

这个配置叠了三类事情:

  • 执行——拉代码、跑测试、打镜像、推镜像。
  • 决策——"本次发布能不能发"(业务规则判断)。
  • 数据——新功能、支付链路等业务参数。

三类事揉在一个 YAML 里,每次业务规则一改,整个 pipeline 都要重测;改一次发布配置,要担心是不是会破坏业务逻辑。Jenkinsfile 越长,维护成本越高,最后没人敢动。

正面:拆成三层

把这件事拆成清晰的三层:

第一层:执行层(只管"做什么动作")

执行层只回答"做什么"——拉代码、跑测试、打镜像、推送。不关心业务规则、不关心业务参数。YAML 里只有动作,没有"为什么这样做"。

yaml
# 执行层(pipeline YAML)
name: execute
on:
  push:
    branches: [main]
jobs:
  build:
    steps:
      - name: 拉代码
        run: git clone ...
      - name: 跑测试
        run: npm test
      - name: 打镜像
        run: docker build ...
      - name: 推镜像
        run: docker push ...

  deploy:
    needs: build
    steps:
      - name: 拉决策结果
        run: ./fetch-decision.sh  # 从决策层拉"该不该发"
      - name: 推送到目标环境
        run: ./deploy.sh

第二层:决策层(只管"该不该发")

决策层独立成一个服务或脚本。它从数据层取参数,按规则判断,把判断结果返回给执行层。

python
# 决策层(独立脚本或服务)
def should_publish(commit_info, params):
    new_feature = "feat:" in commit_info
    touch_payment = "payment" in commit_info
    is_friday = datetime.now().weekday() == 4

    if new_feature and touch_payment and is_friday:
        return {"publish": False, "reason": "周五禁止支付链路变更发布"}

    return {"publish": True, "reason": "ok"}

决策层可以单独演进——业务规则变了,只改这一处,不动执行层。

第三层:数据层(业务参数独立存放)

业务参数(订单阈值、发布窗口、用户分群)放在专门的配置中心或数据库里,不在 pipeline YAML 里出现。

# 数据层(配置中心 / 数据库)
publish:
  friday_blackout_categories: ["payment"]
  rolling_window_users: 0.1
  emergency_stop: false

决策层从数据层取数,执行层从决策层取结果。谁也不从谁那里偷数据

为什么这样拆能避坑

把上篇的四个坑放到三层结构里看,每个坑都没有立足之地:

上篇的坑在三层结构里为什么不成立
第一个坑:业务规则出现在不该出现的地方业务规则只在决策层出现,执行层 YAML 不再写"if 新功能 + 支付链路 → 禁止发"
第二个坑:错误被拖到最后才暴露执行层每个步骤独立校验;决策层独立运行,错了不影响执行
第三个坑:决定的事和被决定的事搅在一起执行层是动作,决策层是判断,数据层是参数——三者通过清晰接口对接,不直接相互嵌入
第四个坑:流程反向吞噬工作三层职责清晰:执行者改执行层、决策者改决策层、参数管理者改数据层。改一件事不会牵动其他事

三层结构不是新发明,是 workflow 在结构上的最小必要复杂度。再简单一点,三个坑的毛病全回来;再复杂一点,就是过度设计。


一个端到端的实例

下面用一个真实风格的发布场景把三层串成一条线。

场景

一个 SaaS 产品要做一次发布:

  1. 开发者 push 代码到 main。
  2. 系统自动跑测试、打镜像。
  3. 系统判断这次发布能不能发(决策层)。
  4. 系统按判断结果决定推送到哪个环境(执行层)。
  5. 推送完成后监控指标(数据层反馈)。

端到端流程

[开发者] git push

[执行层 1] 拉代码 + 跑测试 + 打镜像
    ↓ (产物:镜像 + commit 信息)
[决策层] should_publish(commit_info, params)
    ↓ (结果:{"publish": true, "env": "staging", "ratio": 0.1})
[执行层 2] 推到 staging(10% 流量灰度)
    ↓ (持续 30 分钟观察)
[数据层] 监控指标 → 决定是否放量 / 回滚

[执行层 3] 全量发布 / 自动回滚

每层各管一件事:

  • 执行层——把镜像从 A 推到 B,不关心该不该推。
  • 决策层——判断该不该推、推多少,调用数据层取参数。
  • 数据层——参数存放 + 监控指标采集 + 决策反馈。

反例对照

如果三层不拆,会出现什么?

某团队把所有事塞在一个 Jenkinsfile 里:

groovy
// 反例:所有事塞在一起
pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        sh 'docker build .'
      }
    }
    stage('ShouldPublish') {
      // 业务规则硬编码在 Jenkinsfile
      steps {
        script {
          def commit = sh(script: 'git log -1 --pretty=%B', returnStdout: true)
          if (commit.contains('feat:') && commit.contains('payment') && isFriday()) {
            currentBuild.result = 'FAILURE'
            error('周五禁止支付链路发布')
          }
        }
      }
    }
    stage('Deploy') {
      // 业务参数散落在 Jenkinsfile
      steps {
        sh './deploy.sh staging 0.1'
      }
    }
  }
}

问题:

  1. 业务规则硬编码在执行层——改规则要改 Jenkinsfile,要重新走一遍 CI。
  2. 业务参数散落在执行层——订单阈值、灰度比例要改 Jenkinsfile。
  3. 监控反馈没接进来——出问题只能靠人盯日志。
  4. 改一处牵动全局——Jenkinsfile 越长,越没人敢动。

把三层拆开后,这些问题都没了。


团队在不同阶段该做到什么程度

三层拆法不是越早做越好,也不是做得越细越好。下面是一张梯队判断表。

阶段一:初创团队(5-10 人)

目标:让执行层不越界

  • 执行层:直接用 GitHub Actions YAML / GitLab CI / Jenkinsfile。不要自建 CI 系统
  • 决策层:人工审批 + 一段简单判断脚本。复杂业务规则先用文档记下来。
  • 数据层:环境变量 / Secrets / .env 文件即可,不要引入配置中心

关键纪律

  • 执行层 YAML 里只写动作,不写业务规则。
  • 业务规则放在注释或单独的文档里,人工 review。
  • 业务参数放在 .env 或 Secrets,不写在 YAML 里。

典型反例

  • 在 Jenkinsfile 里写"周五不上线"。
  • 在 pipeline YAML 里塞业务阈值。
  • 用同一个 Jenkinsfile 既管 dev 又管 prod。

阶段二:成长期团队(20-50 人)

目标:让决策层和数据层独立

  • 执行层:开始分层(构建 pipeline / 测试 pipeline / 部署 pipeline 拆开)。可以引入 Jenkins + Jenkinsfile / GitLab CI / 自建 CI 平台。
  • 决策层:自动化审批 + 灰度规则脚本。可以引入简单的"发布决策服务"(哪怕是个内部工具)。
  • 数据层:引入配置中心(Apollo / Nacos / Vault / 内部参数服务)。业务参数独立存放。

关键纪律

  • 决策层从数据层取参数,不从执行层取参数。
  • 执行层只调用决策层的接口,不内嵌业务规则。
  • 数据层参数变更要有审计日志。

典型反例

  • 决策层写在执行层 YAML 里("如果 commit 信息里有 feat 就打镜像 tag v2")。
  • 数据层参数硬编码在执行层("灰度比例 0.1 写在 Jenkinsfile 里")。
  • 决策层直接读数据库,不走专门接口。

阶段三:规模化团队(100+ 人)

目标:让决策层能复用、能独立演进

  • 执行层:CI/CD 平台化,统一调度(Tekton / Argo Workflows / 内部 CI 平台)。
  • 决策层:决策引擎(Open Policy Agent / 内部规则引擎)+ 灰度平台 + 自动化运维。
  • 数据层:完整的配置/参数治理 + 业务参数中台 + 监控 + 反馈。

关键纪律

  • 决策层是独立的产品,有版本、有 owner、有演进路径。
  • 数据层参数变更走完整的发布流程。
  • 反馈层(监控、告警、A/B 结果)反哺决策层,形成闭环。

典型反例

  • 决策层散落在多个 Jenkinsfile / GitHub Actions 里,没人能说清"现在到底有几条业务规则"。
  • 数据层参数改了没人知道——配置中心有 200 个 key,没人维护。
  • 决策层没有版本——业务规则改了,灰度回不去了。

判断表

团队规模执行层做到什么决策层做到什么数据层做到什么
初创(5-10)单 YAML,动作清单人工 + 简单脚本.env / Secrets
成长期(20-50)分层 pipeline自动化审批 + 灰度脚本配置中心
规模化(100+)CI/CD 平台化决策引擎 + 规则平台参数中台 + 反馈闭环

关键问题不是"我该不该上 K8s",而是"我现在的执行 / 决策 / 数据三层有没有分开"。


收尾:方法论的朴素边界

最后讲几句方法论的边界,避免走偏。

第一,上工具 ≠ 数智化。

把 Jenkins 换成 Argo CD、GitHub Actions 换成 Tekton,不会自动让流程变好。如果三层不拆,换什么工具都是在同一团乱麻上叠加更复杂的工具。

第二,画流程图 ≠ 流程设计。

流程图画得再漂亮,只要执行 / 决策 / 数据三层没分开,上篇的四个坑迟早会回来。流程图是设计的结果,不是设计本身。真正的设计是"职责怎么划分、边界怎么定、接口怎么对"。

第三,复杂度的最低必要原则。

三层不是越多越好。初创团队硬上配置中心和决策引擎,反而会让流程变慢——因为决策层和数据层还没稳定下来,先把它们独立出去只会增加协调成本。

什么时候该往上走一层? 当现有形态开始出现上篇讲的四个坑里的任意一个,就该考虑往上走一层。但不要一次走完所有层,按"先执行层不越界 → 决策层独立 → 数据层独立"的顺序逐级演进。


数智化不是终点,是把流程做到让工作者感受不到流程的存在

下篇到此为止。回到系列起点:流程即镜像:审批流程和 CI 流水线撞上的同一组坑(上)


参考