Mar 20, 2026 · 1033 words · 5 min read
翻译说明:本章由人工智能辅助翻译自英文原版。 我们力求准确,但部分细微之处可能与原文有所不同。 英文原版请访问此处

7. 编排#

网络团队做了一切正确的事情。他们有坚实的真实数据源、经过充分测试的各类操作 Playbook,以及执行它们的清晰操作手册。在纸面上,部署一个新的 VLAN 服务是完全自动化的。在实践中,这需要半天时间和一名特定的工程师。

那位工程师熟知这个顺序。首先验证 SoT 数据是否完整。然后运行预检 Playbook。然后审查输出,查找失败的设备,决定是否继续。然后触发部署 Playbook。然后等待。然后运行验证 Playbook。然后手动更新 ServiceNow 工单。如果任何设备在中途失败,在其他设备注意到之前先回滚它。她将所有步骤都写在一份共享文档的操作手册中,但没有其他人完全内化了这些内容。

当她请假时,部署停了下来。当一名初级工程师尝试这个顺序并搞错了顺序时,网络在六个小时内处于部分状态。自动化存在着,但协调仍然是手动的。

这就是本章要解决的问题。编排是将一系列自动化工具转变为一个整体系统的构建块。它协调其他模块,决定它们何时运行,优雅地处理故障,追踪每一个决策,并且所有这些都不需要工程师站在中间手动管理流程。

7.1. 基础概念#

7.1.1. 背景#

到目前为止,我们所介绍的每个构建块都做一件事做得很好。真实数据源保存意图。执行器应用意图。采集器检索状态。可观测性使这些状态变得有意义。每个都是专家,而专家需要一个连接器:某个决定每个专家何时应该行动、如何处理结果、以及在出错时如何恢复的组件。

这个连接器就是 Orchestrator

第 3 章中,我们将其置于 NAF 框架的中心,作为协调所有其他模块的构建块。第 5 章展示了执行器如何应用配置变更;第 6 章展示了可观测性如何验证结果。本章展示编排器如何排序这两者,并处理它们之间可能出错的一切。

没有编排,你运行的不是自动化。你运行的是脚本,需要有人以正确的顺序、在正确的时间调用它们,并以正确的方式解读结果。这只是名义上的自动化。

7.1.2. 目标#

编排器需要实现五个目标:

  1. 端到端协调多模块工作流。 部署不是单一操作;它是一个序列:验证 SoT 中的意图、运行预检、执行配置、验证结果、通知相关人员。编排器将整个序列串联在一起。

  2. 自动响应事件,无论是否有人工发起。 ServiceNow 审批、可观测性告警、计划的合规扫描:所有这些都应该能够在没有人工手动启动的情况下触发工作流。

  3. 弹性且可扩展的执行。 并行触及 800 台交换机的工作流必须可靠地完成。它必须能够在重启后继续。它必须在不丢失成功设备已完成工作的情况下处理部分失败。

  4. 提供防篡改的可见性。 操作员需要看到当前正在运行什么。审计员需要看到上个月运行了什么、谁触发了它、运行的是哪个版本的工作流,以及每个步骤产生了什么。这两个需求必须从同一个系统中得到满足。

  5. 将工作流定义作为生产软件来管理。 一个部署到 800 台生产交换机的工作流不能随意修改。逻辑本身需要被持久化、版本控制、测试,并以与生产环境中运行的任何代码相同的纪律升级到生产环境。

7.1.3. 支柱#

五个支柱支撑这些目标:

  1. 工作流引擎:定义、运行和追踪多步骤流程
  2. 触发层:手动、计划、事件驱动、Webhook
  3. 弹性执行:工作流在重启后能够继续;支持跨数百台设备的重试、回滚和并发操作,无每台设备瓶颈
  4. 审计和可观测性:每个步骤都有日志,每个决策都可追踪
  5. 管道管理:在生产环境中安全地持久化、版本控制和升级工作流定义

7.1.4. 范围#

编排器负责协调,而不是执行。

在范围内:

  • 协调其他构建块
  • 定义工作流逻辑和步骤依赖
  • 处理来自多个来源的触发
  • 追踪执行状态并产生审计跟踪
  • 在步骤失败时管理回滚决策

不在范围内:

  • 执行设备变更(那是 Executor 的职责)
  • 存储网络运营状态(那是 Observability 的职责)
  • 保存网络意图(那是真实数据源的职责)

一个常见的错误是构建一个复制了其邻居执行或存储职责的编排器。模块之间的接口必须保持干净。

一个还存储凭证、管理设备清单或运行自己的配置引擎的编排器已经演变成了别的东西。如果你的编排工具开始从其他模块吸收职责,你就有了一个架构耦合问题,以后解开它将会代价高昂。

7.2. 功能#

五个目标和支柱通过五项核心功能来实现。每项功能直接对应一个目标及其支撑支柱:

  1. 工作流引擎:工作流如何构建以及步骤如何协调
  2. 触发:工作流如何以及何时启动,以及调用者的体验
  3. 弹性与规模:工作流如何在故障和大规模下可靠完成
  4. 状态与可追溯性:追踪执行状态并产生防篡改审计记录
  5. 管道管理:在生产环境中安全地持久化和管理工作流定义
graph LR

    subgraph Goals
        direction TB
        A1[Coordinate multi-block workflows end-to-end]
        A2[React to events automatically]
        A3[Resilient and scalable execution]
        A4[Tamper-evident visibility and audit]
        A5[Safe changes to production pipelines]
    end

    subgraph Pillars
        direction TB
        B1[Workflow engine: define, run, track]
        B2[Triggering layer: manual, scheduled, event-driven]
        B3[Resilient execution: durable, retry, rollback at scale]
        B4[Audit and observability: every step logged]
        B5[Pipeline management: persist, version, promote safely]
    end

    subgraph Functionalities
        direction TB
        C1[Workflow Engine]
        C2[Triggering]
        C3[Resilience and Scale]
        C4[State and Traceability]
        C5[Pipeline Management]
    end

    A1 --> B1 --> C1
    A2 --> B2 --> C2
    A3 --> B3 --> C3
    A4 --> B4 --> C4
    A5 --> B5 --> C5

    classDef row1 fill:#eef7ff,stroke:#4a90e2,stroke-width:1px;
    classDef row2 fill:#ddeeff,stroke:#4a90e2,stroke-width:1px;
    classDef row3 fill:#cce5ff,stroke:#4a90e2,stroke-width:1px;
    classDef row4 fill:#b3d8ff,stroke:#4a90e2,stroke-width:1px;
    classDef row5 fill:#99ccff,stroke:#4a90e2,stroke-width:1px;

    class A1,B1,C1 row1;
    class A2,B2,C2 row2;
    class A3,B3,C3 row3;
    class A4,B4,C4 row4;
    class A5,B5,C5 row5;

7.2.1. 工作流引擎#

工作流引擎是编排器的核心。它定义多步骤流程、执行它们、追踪状态,并处理步骤之间的关系。

在深入模式之前,值得先说明协调的四种基本方法,因为这个选择决定了其他一切。

7.2.1.1. 协调方法#

  • 单体式(命令式程序):单个 Python 脚本按顺序调用每个步骤,等待每个结果,并决定下一步做什么。编写简单,许多团队从这里开始。问题在于持久性:如果脚本在 10 步中的第 5 步崩溃,你要从头开始。运行之间没有持久状态。你也无法在不自己编写线程逻辑的情况下并行化步骤。它适用于小型、快速的操作;在负载和不可靠的基础设施下会崩溃。实际上,这正是执行器模块已经提供的功能:由操作员调用的脚本。称之为编排有些言过其实。

  • 工作流(基于 DAG):这才是编排真正开始的地方。步骤被定义为有向无环图,每个节点是一个任务,边表示依赖关系。引擎按节点追踪状态:如果在崩溃后重启,只有失败或未完成的步骤会重新运行。并行性是内置的:独立的分支并发执行。这是生产编排的主流方法,也是网络自动化中最经过验证的方法。该类别中的工具包括 Prefect、Temporal 和 AWX 工作流模板。

  • 编排(事件驱动,无中央协调器):没有编排器。每个组件对其他组件发布的事件做出反应:执行器发布"部署完成",可观测性系统消费它并运行验证,通知系统消费验证结果。组件之间的耦合是松散的,这使得添加新消费者变得容易。缺点是:没有一个地方可以了解完整的工作流状态。调试跨服务故障需要关联来自多个系统的事件。这种方法适用于简单的反应模式,但在复杂性方面扩展性差。

  • 智能体式(感知-逻辑-行动循环):Large Language Model (LLM) 或 AI 系统充当逻辑层。智能体观察来自可观测性或 SoT 的当前状态,推理需要什么行动,并调用执行器。它不是遵循预定义的工作流图,而是在运行时动态做出决策。这种方法以确定性换取灵活性,构成了自主网络的架构基础。7.2.7 节对此进行深入介绍;第 17 章将其扩展到完全自主。

大多数团队从单体式方法开始,随着自动化成熟度的提高逐渐升级到工作流(基于 DAG)。编排式很少是网络运营的正确选择,因为审计和可追溯性要求使中央协调器很有价值。智能体式方法已经存在,但尚未成为生产网络运营的默认选择。

7.2.1.2. 工作流模式#

在基于 DAG 的方法中,四种模式涵盖了大多数现实世界的网络自动化工作流:

  • 顺序式:步骤一个接一个地运行;每个步骤依赖于前一个步骤的成功完成。适用于需要严格顺序的情况:验证意图,然后预检,然后执行,然后验证。

  • 并行(扇出/扇入):多个独立步骤并发执行。扇出步骤启动许多并行任务(每台设备一个,或每栋建筑一个);扇入步骤在所有任务完成后才继续执行。对于跨数百台设备的操作来说是必不可少的:没有扇出,800 台设备每台 10 秒的操作按顺序执行需要超过两小时。

  • 条件分支:所采取的路径取决于运行时状态。预检通过了吗?分支到执行。失败了吗?分支到中止并通知。工作流定义包含评估结果并选择下一步的决策节点。

  • Saga 模式:对于长时间运行的工作流,Saga 模式为每个步骤添加补偿事务。如果工作流成功到步骤 N 然后失败,它会以相反的顺序对步骤 N-1 到步骤 1 运行补偿操作,使系统恢复到已知的良好状态。这是回滚在编排层面的工作方式:不是重新运行整个工作流,而是执行每个成功步骤的逆操作。

flowchart TD
    subgraph Sequential
        S1[Step A] --> S2[Step B] --> S3[Step C]
    end

    subgraph FanOut["Fan-out and Fan-in"]
        F0[Start] --> F1[Device 1]
        F0 --> F2[Device 2]
        F0 --> F3[Device N]
        F1 --> FJ[Fan-in]
        F2 --> FJ
        F3 --> FJ
    end

    subgraph Saga["Saga - rollback on failure"]
        P1[Step 1] --> P2[Step 2] --> P3[Step 3]
        P3 -- fail --> R3[Rollback 3]
        R3 --> R2[Rollback 2]
        R2 --> R1[Rollback 1]
    end

Saga 模式也是渐进式部署的结构基础:分批而不是一次性推送网络变更。第 1 批覆盖小型测试群体;如果成功,工作流扇出到第 2 批,然后第 N 批。如果任何批次失败,补偿只回滚那一批。这是网络版的金丝雀部署:软件团队对代码发布应用的相同受控晋级纪律,应用于网络变更。

7.2.1.3. 依赖管理#

工作流步骤很少独立存在。引擎需要表达和执行三种依赖关系:

  • 数据依赖:任务 B 不能开始,直到任务 A 完成并产生 B 消费的结果。引擎将输出作为结构化数据在步骤之间传递。在实践中,这意味着预检步骤将可达设备列表传递给执行步骤,而不是从头重新查询。

  • 多输入依赖(扇入):一个步骤在继续之前等待多个并行分支。引擎保存每个分支的状态,并且只有在满足配置的完成策略时才触发合并步骤:全部完成,或 M 个中的 N 个,或第一个成功。

  • 外部依赖:有时步骤无法继续,直到系统外部发生某件事。变更窗口开放。人工审批。设备在重启后变得可达。引擎必须支持具有可配置超时和定义的升级路径的等待状态,以应对等待永远无法解决的情况。

7.2.2. 触发#

工作流必须以某种方式启动。触发回答两个问题:是什么导致工作流开始,以及调用者在此之后的体验是什么。

触发与第 5 章的区别:在第 5 章中,触发指的是操作员或系统如何直接调用执行引擎:通过 API 调用 AWX,或从 Command Line Interface (CLI) 启动模板。那是执行层触发。这里,触发描述的是什么导致编排器启动工作流,而工作流可能反过来将执行器作为几个步骤之一来调用。编排器接收触发并决定运行什么完整工作流。执行器只执行编排器告诉它的内容。

7.2.2.1. 触发模式#

四种模式涵盖了从人工到完全自动化的整个范围:

  • API 调用:编排器暴露一个 HTTP 端点。操作员手动调用它,UI 按钮调用它,或者外部系统(ServiceNow、Nautobot、CI/CD 管道)在事件发生时调用它。这些都是相同的机制:不同之处在于谁发起调用以及它是否携带结构化事件数据。适用于任何需要立即启动的变更,无论发起者是人工还是系统。

  • 计划:类似 Cron 的计划在配置的时间启动工作流。每夜合规扫描、每周固件审计、每月容量报告。大多数编排器原生支持这一功能;有些团队使用外部调度器并调用编排器 API。

  • 消息队列:编排器消费来自队列(Kafka、NATS、RabbitMQ)的消息,并为每条消息启动工作流。这将事件生产者与编排器解耦:生产者发布后就继续;编排器按自己的节奏处理。适用于高容量事件流,其中直接 API 调用的最多一次交付保证不足。

推送(API 调用)和拉取(消息队列、计划)之间的选择取决于数据量和耦合容忍度。API 调用更简单,但需要发送方知道编排器的端点。消息队列对于高容量流的扩展性更好,但需要额外的基础设施来运营。

7.2.2.2. 响应合同#

工作流启动后,调用者需要知道期望得到什么响应:

  • 同步:调用者等待工作流完成并直接接收结果。适用于调用者需要结果才能继续的短操作(30 秒以内)。大多数交互式使用案例从这里开始,然后在尝试运行 10 分钟的部署时发现 API 客户端超时了,才意识到已经超出了这种模式的适用范围。

  • 异步:调用者立即接收工作流运行 ID 并轮询状态,或注册一个回调 URL 以在完成时接收结果。对于任何触及超过少量设备的工作流都是必要的。这对系统如何展示状态有直接影响:呈现层(第 8 章)必须暴露状态端点和推送通知,因为用户从某处触发了工作流,需要在不持有开放 HTTP 连接的情况下追踪它们。

  • 混合:工作流异步启动,但调用者可以在需要时选择阻塞在同步等待端点上。这是一种便利模式,避免强制调用者提前做出选择。

事件驱动工作流中的幂等性:当可观测性触发告警或 SoT 变更事件触发时,多个系统可能同时做出反应。同一告警可以触发两次;消息队列可能多次传递同一条消息。每个事件驱动工作流都必须是幂等的:对相同输入运行两次必须与运行一次产生相同的结果。在编排层面,这通常需要一个去重键:编排器在启动新运行之前检查的唯一标识符。如果具有该键的运行已经存在且仍在运行,则拒绝或排队重复项。这听起来很简单,但在实践中出乎意料地容易出错。

闭环模式:可观测性检测到漂移条件(设备配置偏离了意图)。它通过上面的触发机制向编排器发送告警。编排器启动修复工作流:查询 SoT 以获取预期状态,调用执行器纠正设备,然后重新运行可观测性检查以确认修复。如果检查通过,循环关闭。如果失败,编排器升级。这个模式是自愈自动化的基础,在第 15 章中有深入介绍。只有当编排器、可观测性和执行器足够解耦,每个都能独立发挥作用时,循环才能运作。

7.2.3. 弹性与规模#

这是将你在原型阶段使用的编排器与你在凌晨 3 点在生产环境中信任的编排器区分开来的东西。一个在理想条件下可靠运行的工作流,并不能告诉你它是否能在协调器重启到一半时、处理 800 台设备中 40 台预检失败时,或在依赖关系永远无法解决时优雅降级。你的编排器下次被测试时,不会是在演示中。

第 5 章中介绍的执行层弹性,处理了单台设备级别的幂等性和重试:如果 Playbook 对一台设备失败,就重试它。第 5 章没有解决的是工作流级别的持久性:当编排器本身在运行中途重启时会发生什么,当 800 台设备中有 40 台预检失败时,或当依赖关系永远无法解决时工作流挂起时。编排器本身的扩展,包括高可用性、水平工作进程和并发运行下的数据库负载,是第 11 章中讨论的基础设施问题。

7.2.3.1. 持久状态#

将执行状态存储在内存中的工作流引擎在重启时会丢失一切。这对于脚本是可以接受的,对于生产编排是不可接受的。持久状态意味着工作流的进度在编排器失败后仍然存在:哪些步骤已完成、它们产生了什么、哪些仍在等待。当编排器重新上线时,它从中断处恢复。

Temporal 完全围绕这个保证构建:它在重启时从事件历史重放工作流函数,使运行中的状态在崩溃时保持安全。AWX 将任务状态存储在数据库中。脚本什么都不存储。

7.2.3.2. 重试策略#

并非所有故障都是相同的。在固件重启期间短暂无法访问的设备应该被重试。返回永久授权错误的设备不应该:重试没有帮助,可能会触发锁定策略。

重试配置应该区分:

  • 瞬态故障:网络抖动、API 超时、临时资源争用。以指数退避重试。
  • 永久故障:凭证错误、设备处于维护模式、不适用于此设备类型的配置。中止并升级。

工作流定义应该为每个步骤指定重试策略。预检步骤和配置推送步骤有不同的故障语义,不应该共享相同的重试设置。

7.2.3.3. 回滚和补偿#

当部署工作流中途失败时,你有三个选择:保留部分状态、手动修复,或自动回滚。在大多数网络运营中,部分状态是危险的:已接收新配置的设备与未接收的设备行为会有所不同。

Saga 模式通过为每个步骤定义补偿事务来解决这个问题。如果工作流成功到步骤 N 然后失败,它会以相反的顺序对步骤 N-1 到步骤 1 运行补偿操作。在 VLAN 部署中:如果配置推送在 30 台设备上成功,在第 31 台失败,Saga 会在报告失败之前回滚 30 个成功的推送。

Saga 模式要求在工作流设计时提前定义补偿事务。这是预先的额外工作。替代方案是在凌晨 2 点发现你的网络处于没有操作手册描述的状态。

7.2.3.4. 并发控制#

同时对 800 台设备进行扇出会压垮大多数执行层。编排层面的并发控制意味着:

  • 批处理:并行运行 N 台设备,等待批次完成,然后运行下一批。这控制了爆炸半径:如果一个错误的配置暴露出问题,你还没有触及全部 800 台设备。
  • 速率限制:执行层有限制;编排器必须尊重它们。不要让 AWX 队列被 800 个同时任务填满。
  • 部分成功阈值:定义在规模下成功意味着什么。800 台设备中有 798 台配置正确可能足以继续;800 台中有 600 台应该停止工作流并升级。

7.2.3.5. 超时和熔断器#

永远等待的工作流是可靠性问题。每个可能阻塞的步骤都需要配置超时。当超时到期时,工作流需要定义的操作:升级、跳过或中止。

Circuit Breaker 模式将此扩展到重复失败:如果一个步骤在一个时间窗口内失败超过 N 次,停止尝试并发出告警。这防止了单个无法访问的设备将工作流挂起数小时。

7.2.3.6. 跨模块边界的弹性#

上面五种模式解决了编排器自身执行中的故障:持久状态、重试、回滚、并发、超时。但工作流也会在模块边界处失败,这些故障需要不同的处理方式。

当编排器调用 SoT API 并收到超时时,适当的响应与执行器返回设备故障时不同。SoT 超时意味着编排器无法验证它即将部署的意图是否是最新的。使用缓存数据继续前进的风险在于应用了陈旧的配置。正确的响应通常是中止并重试,而不是在不确定性下继续。从未到来的呈现层事件(来自 ServiceNow 的审批 Webhook)可能意味着请求被拒绝、集成出了问题,或者消息丢失了。这些需要不同的恢复路径:缺少审批不是应该无限重试的瞬态故障。

模块边界故障应该在工作流定义中明确分类:

  • 依赖不可用(SoT、可观测性):工作流无法安全继续。干净地失败,发出诊断事件,不要用陈旧数据重试。
  • 依赖降级(部分 SoT 读取、可观测性滞后):工作流可以在明确承认它以降低置信度运行的情况下继续。记录降级状态;不要悄悄地继续。
  • 下游模块失败(执行器返回错误、采集器没有返回数据):应用上面的重试和回滚模式,但准确分类故障来源,以便告警和审计记录能够正确命名模块。

一个将所有故障视为可重试设备错误的工作流,会重试损坏的 SoT 集成,直到耗尽重试预算,并以错误的诊断呼叫值班工程师。在模块边界对故障进行分类,是工作流快速失败与令人困惑地失败之间的区别。

7.2.4. 状态与可追溯性#

当凌晨 3 点出现问题时,需要立即回答两个问题:工作流的当前状态是什么,以及谁触发了它?

当审计团队三个月后提问时,同样的记录必须回答:运行了什么、运行的是哪个版本的工作流定义、每个步骤接收了什么输入、它产生了什么输出,以及最终结果是什么。

这些是不同紧迫程度的不同问题,但它们来自同一个来源:工作流的执行状态及其审计记录。

可追溯性是跨自动化平台的横切关注点:真实数据源记录对意图的每次变更;可观测性记录对网络状态的每次变更。但这两种记录都不能告诉你谁发起了工作流、哪些步骤按顺序运行,以及是什么导致了结果。只有编排器的审计记录填补了这一空白。因为编排器协调所有其他模块,它的跟踪是对给定事件跨整个自动化系统发生的一切的权威视图。

7.2.4.1. 状态不是网络状态#

这个区别很容易被忽略。在第 6 章中,“状态"意味着网络的运营状态:接口计数器、BGP 会话、设备 CPU。在第 5 章中,“状态"意味着 SoT 中保存的期望配置意图。这里,状态意味着工作流本身的执行状态:哪些步骤已经运行,哪些正在运行,哪些失败了,它们产生了什么。

两者是相关的(工作流步骤产生网络状态变化,可观测性然后验证这些变化),但它们被不同地存储、不同地查询,并用于不同的目的。不要将它们混为一谈。

7.2.4.2. 工作流状态机#

每次工作流运行都经历一个定义的状态机:

  • 等待中:已接收但尚未开始
  • 运行中:正在主动执行步骤
  • 成功:所有必要步骤已成功完成
  • 失败:某个步骤失败,工作流无法继续
  • 已取消:被人工或外部信号停止

工作流中的每个步骤都有自己的状态。部分成功的扇出运行必须准确显示哪些设备成功、哪些失败、哪些被跳过。“工作流失败了"在没有每台设备明细的情况下是没有用的。

7.2.4.3. 审计日志要求#

每次工作流运行记录必须至少包含:

  • 谁或什么触发了运行:人工身份、系统名称、触发事件 ID
  • 开始时间和完成时间
  • 运行的工作流定义的哪个版本
  • 工作流接收的完整输入
  • 每个步骤的输出
  • 最终结果

这条记录必须是防篡改的:它不能在事后被编辑。在受监管的环境中,编排器的审计日志就是变更管理记录。如果这条记录可以被更改,变更管理系统就是不可信的。

大多数编排工具将审计日志写入它们也拥有的数据库。这是否足够取决于你的合规要求。一些组织将编排审计日志导出到只追加的外部系统(SIEM、只写日志存储)以防止任何人(包括可以对编排器自己的数据库运行查询的人)的篡改。

7.2.5. 管道管理#

一个配置 800 台生产交换机的工作流,在架构上就是生产软件。核心挑战不只是版本控制:而是如何存储、验证和晋级工作流定义,使逻辑本身与它所管理的基础设施一样可靠。

工作流定义编码了决策:要运行哪些预检,当设备无法访问时怎么办,什么构成成功。随意修改它会改变该工作流下次运行时触及的每台设备上发生的事情。

我见过团队通过直接在编排工具的 UI 中编辑工作流定义来悄悄破坏生产工作流。直到下一次运行触及修改后的步骤无法正确处理的设备类型时,没有人注意到。UI 编辑没有审查、没有测试、没有回滚路径。

7.2.5.1. 策略#

  • Git 支持的定义:将工作流定义存储在版本控制中。编排工具在部署时从 Git 拉取,而不是从本地 UI 编辑拉取。这给你提供了历史记录、审查流程,以及回滚到任何先前版本的能力。

  • 蓝/绿管道版本:在生产中维护两个版本的工作流:处理所有活动工作流的当前稳定版本,以及在验证期后接收新运行的新版本。只有当新版本被证明稳定后,流量才会切换。

  • 金丝雀部署:新工作流版本首先处理少量运行。固件升级工作流可能在将新版本推广到整个机队之前,先将其应用于 10 台设备。问题在 10 台设备时暴露,而不是 800 台。

7.2.5.2. 测试编排变更#

工作流定义可以在生产前进行测试:

  • 演习模式:对真实输入运行工作流,但跳过修改网络的步骤。验证逻辑产生了预期的操作序列。
  • 预演环境:专门用于在对生产运行之前测试工作流变更的设备子集。
  • 影子执行:与当前版本并行运行新版本,但忽略其结果。在切换之前比较输出以检测差异。

两种不同的回滚:回滚工作流运行意味着撤销特定执行所做的网络变更(由 7.2.3 节中的 Saga 模式处理)。回滚工作流定义意味着将工作流逻辑恢复到以前的版本:切换 Git 引用,重新部署定义,下一次运行使用先前的版本。这些是正交操作。混淆它们就是团队最终回滚了错误的东西的原因。

7.2.6. 解决方案概览#

免责声明:此处列出的工具仅作解释性示例,不构成推荐。每种工具都有不同的架构和权衡特性。请根据团队能力、现有工具和运营约束来评估它们。

编排工具市场涵盖了广泛的模型,从网络特定平台到通用工作流引擎。问题很少是"哪个最好”,几乎总是"哪个适合我们的运营方式”。

工具执行模型架构上的独特之处网络自动化适用性
AWX / Ansible AAPYAML 工作流模板,UI 优先编排器和执行器是同一个系统:Ansible 任务是一等公民,没有翻译层。RBAC、凭证和清单是统一的。已经使用 Ansible 进行执行的团队;当 Ansible 已经是执行层时的自然路径
Itential低代码/无代码可视化构建器,网络特定专为网络运营构建:内置的 ITSM、IPAM 和多厂商设备适配器。工作流构建器非开发人员也能使用。需要多厂商、多系统集成而不需要自定义代码的企业网络团队
PrefectPython 代码即 DAG,开发者优先工作流是带有装饰器的 Python 函数。管道就是软件:像应用程序代码一样进行测试、版本控制和观测。管道本身具有强大的原生可观测性。习惯 Python 并希望以软件工程规范对待编排的团队
Temporal持久执行引擎,代码定义在工作流中途崩溃后仍能存活:任何步骤都从其最后一个检查点重放。Saga 和补偿是一等构造,而不是附加功能。长时间运行的工作流(固件升级、大规模部署),其中部分执行和回滚必须坚如磐石
Windmill脚本优先,轻量级,开源工作流中的每个节点都是一个独立的脚本(任何语言)。运营开销低;易于自行托管和定制,无需企业平台复杂性。希望灵活自定义逻辑而不需要平台重量的小型团队或组织

一个架构问题贯穿所有这些:你的编排工具是否也充当你的执行引擎,还是它们是分离的?AWX/AAP 将两者合并为一。Prefect、Temporal 和 Windmill 是调用独立执行工具(Ansible、自定义脚本、API)的编排器。合并模型操作起来更简单;分离模型使你有更多灵活性来独立交换执行引擎。第 3 章在最小耦合下介绍了这种权衡。

上表中的 AWX/AAP 行值得对考虑将其作为主要平台的团队进行说明。AWX 工作流模板是编排器;单独的 Ansible 任务模板是执行器。即使它们在同一平台内运行,两者之间的架构边界也是存在的。一个将所有逻辑放入任务模板(执行器)并只使用工作流模板来链接它们的团队,实际上是从执行原语构建了编排器,这限制了可见性、重试配置和回滚选项。相反,将业务逻辑放入工作流模板(基于外部数据的条件分支、动态清单选择)的团队正在将 AWX 用作真正的编排器。这种区别很重要,因为 AWX 的审计跟踪、审批门和通知钩子是工作流级别的功能。如果你的所有逻辑都在任务模板中,你就不能在不重构的情况下使用这些功能。这不是 AWX 的限制;这是设计中没有区分编排和执行的后果。

这些工具有很大的重叠:Python 在 Prefect 和 Windmill 中都可以运行;Prefect 和 Temporal 都可以调用 Ansible。一个粗略的起点:如果你的团队以 Ansible 为主且希望最少新组件,AWX 工作流模板是自然的选择;如果你想要具有软件工程规范的可测试、代码优先的管道,Prefect 和 Windmill 都可以,但具有不同的运营模式;如果在部分失败下的持久性是主要约束,Temporal 的重放模型是专门为此构建的。将此视为评估的立足点,而不是最终答案。

7.2.7. 智能体编排器#

7.2.1 中列出的智能体协调方法引入了不同的执行模型:不是遵循预定义的 DAG,而是由 Large Language Model (LLM) 接收目标并在运行时确定操作序列。智能体从可观测性和 SoT 模块观察当前状态,推理什么操作能缩小差距,调用执行器,并重新观察以验证结果。如果结果不是预期的,它再次推理。决策逻辑不是编码在工作流定义中;它存在于模型的推理中。

在整个自动化平台中实现这一点的是 Model Context Protocol (MCP)(模型上下文协议)。每个构建块都暴露一个 MCP 服务器:智能体在其推理循环中可以调用的一组定义工具。SoT 服务器暴露设备查询和意图查询;可观测性服务器暴露状态查询和合规检查;执行器服务器暴露任务触发和状态轮询。智能体以情况需要的任何顺序调用这些工具,而无需工作流作者预先编码每种可能的组合。

架构含义是模块不需要了解彼此或智能体。MCP 接口就是合同。今天从基于 DAG 的工作流接受 REST 调用的同一个 SoT,无需修改就能从 AI 智能体接受 MCP 工具调用。干净的模块边界在这里以紧密耦合永远无法实现的方式得到了回报。

基于 DAG 的工作流和智能体编排并不是互斥的。在实践中,基于 DAG 的工作流是常规、明确定义操作的正确选择:VLAN 部署、合规扫描、固件升级。这些频率高,需要可预测的审计跟踪,不应该依赖 LLM 推理。智能体层处理新颖的情况:事件驱动的修复、异常调查、正确操作序列在了解当前状态之前无法确定的情况。两种方法可以在同一平台中共存,当情况不匹配任何已知模式时,DAG 路由到智能体工作流。

本节介绍了这种模式。完整的架构处理,包括智能体编排如何扩展到对整个网络的持续自主操作,在第 17 章中。

7.3. 实施示例#

7.3.1. 编排园区 VLAN 服务生命周期#

我们在整个第 2 部分中一直跟踪同一个园区网络。在第 4 章中,我们将 VLAN 服务请求存储在 Nautobot 中:VLAN ID、子网、目标交换机和每厂商配置模板。在第 5 章中,我们使用通过 AWX 运行的 Ansible 将该配置推送到园区交换机。在第 6 章中,我们验证了部署并开始监控服务。

我们从未解决的是谁来协调这一切。每章都有一个隐含的假设:工程师手动运行每个步骤。这里我们明确这一点,并用工作流替代工程师。

场景

应用团队提交了一个新应用段的请求:VLAN app-payments,子网 10.22.14.0/24,部署到 building-b 中所有 Cisco 和 Arista 堆栈的接入交换机。请求已通过 ServiceNow 提交,刚刚收到最终审批。

该审批触发了一个 Webhook。编排器接收到它并启动 VLAN 服务部署工作流。

工作流

我们将其实现为 AWX 工作流模板,与已经到位的执行层保持一致。AWX 支持将任务模板与条件分支和审批门链接在一起的工作流模板,这对于这个场景来说已经足够。

flowchart TD
    A[ServiceNow webhook\nVLAN request approved] --> B[Step 1: Validate SoT\nQuery Nautobot for device records\nand VLAN definition completeness]
    B --> C{SoT data complete?}
    C -- No --> Z1[Abort: notify engineer\nand update ServiceNow ticket]
    C -- Yes --> D[Step 2: Fan-out pre-checks\nReachability and VLAN state\nacross all target switches]
    D --> E{Pre-checks passed?}
    E -- Failures --> Z2[Abort: report per-device\nfailures to ServiceNow]
    E -- Passed --> F[Step 3: Approval gate\nOptional human sign-off\nbefore production execution]
    F --> G[Step 4: Execute deployment\nAnsible playbook via AWX]
    G --> H[Step 5: Fan-out validation\nObservability check per switch]
    H --> I{All devices validated?}
    I -- Full success --> J[Step 6: Notify\nUpdate ServiceNow ticket\npost to Slack]
    I -- Partial failure --> K[Step 6a: Saga compensation\nRollback failed scope only]
    K --> J

步骤 1:SoT 验证

编排器在任何操作触及网络之前查询 Nautobot,以确认设备记录和 VLAN 定义是否完整。这个保护步骤是编排器的职责,而不是执行器的:执行器应该接收有效的输入,而不是在推送中途发现坏数据。如果任何检查失败,工作流中止并以具体差距更新 ServiceNow 工单。(SoT 验证的结构在第 4 章中介绍。)

步骤 2:跨目标交换机的预检(扇出)

工作流并行扇出到所有目标交换机。每个分支运行轻量级预检:可达性、VLAN 表状态、可用容量。扇入步骤对结果进行分类并分支;故障阈值是可配置的。编排方面重要的是这是一个带条件分支的扇出/扇入模式,而不是顺序轮询。(预检执行模式在第 5 章中。)

步骤 3:审批门

生产推送之前可选的人工审批。工程师有 30 分钟来批准或拒绝;超时会自动继续并记录日志。编排器将工作流保持在等待状态,带有外部依赖,直到审批到来或窗口到期。

审批门是策略决策,而不是架构决策。高成熟度团队通常会删除它,用从预检结果派生的自动化置信阈值替换人工审批:如果预检覆盖率超过 95% 且没有发现关键故障,则自动继续。仍在建立信任的团队保留这个门。在第 1 章讨论的自动化成熟度谱上,两种选择在不同点都是有效的。

步骤 4:部署执行

编排器触发第 5 章中的 AWX 任务模板,传递来自 SoT 验证步骤的参数,并等待结果。执行器处理其余的事情。这就是关注点分离的实践:编排器决定行动,执行器行动。

步骤 5:可观测性验证(扇出)

部署后,第二次扇出对每台目标交换机运行验证任务:VLAN 是否出现在 VLAN 表中,接口是否处于预期状态?扇入对结果进行分类:完全成功、部分成功或失败。(可观测性层验证什么以及如何验证在第 6 章中介绍。)

步骤 6:结果路由

完全成功会关闭工作流:ServiceNow 工单被更新,摘要发布到 Slack。部分失败触发 Saga 补偿:回滚 Playbook 只对验证失败的设备运行;成功的设备保留其配置。ServiceNow 工单记录每台设备的结果。

回到开篇的工程师

这个工作流展示了第 3 章 NAF 框架中所有七个构建块协同工作:Nautobot(真实数据源)提供了意图,AWX(执行器)应用了意图,Prometheus(可观测性)验证了结果,AWX 工作流模板(编排器)协调了完整序列,ServiceNow Webhook(呈现层,在第 8 章中介绍)从应用团队的请求触发了整个流程。

开篇故事中的工程师仍然在这里。她是在审批门触发时审查它的人。她是调查 Saga 模式标记但无法完全解决的部分失败的人。她仍然是专家。编排器从她那里拿走的不是专业知识,而是在脑海中保存序列、逐步重新运行它、以及成为唯一能做到这一点的人的负担。这就是没有自动化的协调实际代价。

7.4. 总结#

本章确立了 Orchestrator 是将一组可工作的自动化工具转变为一个整体运作系统的构建块。没有它,协调就会保持手动,故障就需要人工干预,网络的规模就会成为实际可能实现的自动化程度的限制。

其核心是工作流引擎,它定义了多步骤流程如何结构化和执行。单体式、DAG、编排式和智能体式协调之间的选择是架构决策,而不是工具偏好。带有命名模式(顺序、扇出、条件、Saga)的 DAG 模型是网络自动化的生产标准。第 7.2.7 节介绍的智能体模式,以 Model Context Protocol (MCP) 作为接口层,代表了不同的权衡,并在第 17 章中得到完整处理。

触发定义了外部世界如何到达编排器。执行层触发(第 5 章)和编排层触发之间的区别在架构上很重要:一个驱动单个设备变更,另一个驱动协调的多系统工作流。事件驱动自动化和闭环模式继承了幂等性和去重的不可谈判属性,正是因为自动化触发器在没有人工审查的情况下触发。

弹性和规模将在演示中工作的自动化与在凌晨 3 点工作的自动化区分开来。持久状态、区分瞬态和永久故障的重试策略、用于部分失败补偿的 Saga 模式,以及大型设备群体的并发控制,都不是以后可以添加的可选功能。它们定义了编排器在条件不理想时是否可以被信任。

状态和可追溯性提供了运行了什么、谁触发了它,以及每个步骤产生了什么的记录。这条记录与网络运营状态(第 6 章)和网络意图(第 4 章)是截然不同的。防篡改审计日志是合规要求,而不是事后想法。管道管理形成闭环:工作流定义是生产软件,必须以与自动化平台中运行的任何其他代码相同的规范进行版本控制、测试和晋级。

园区 VLAN 服务场景将这五项功能结合在一起:由 ServiceNow Webhook 触发的十步工作流,协调 SoT 验证、预检、执行、可观测性验证和 Saga 补偿,协调循环中没有工程师。下一个自然的问题是谁看到这个工作流正在运行,以及触发它的应用团队如何追踪其进度。这就是呈现层,在第 8 章中介绍。

💬 Found something to improve? Send feedback for this chapter