4. 数据建模与配置模板

在数据中心网络自动化中,配置的“可编程化”并不是简单地把 CLI 命令塞进脚本,而是要把网络设备的能力抽象成机器可读的数据模型,再用模板把数据渲染成具体配置。YANG、Jinja2、JSON/YAML 正是这条链路上的三个关键角色:YANG 定义“设备能配置什么、结构长什么样”,JSON/YAML 承载“这次要配置成什么值”,Jinja2 负责“把值套进配置骨架,生成最终命令或配置文本”。理解三者的分工与衔接,是后续做配置下发、校验和回滚的基础。

YANG:把设备能力变成可校验的数据模型

YANG 是一种数据建模语言,最初用于 NETCONF,后来也被 RESTCONF、gNMI 等协议广泛采用。它描述的是设备配置和状态数据的树形结构,包括节点名称、层级、数据类型、是否必选、取值范围、默认值以及节点之间的约束关系。例如一个描述接口的 YANG 模型,会规定接口有 name、description、enabled、mtu、ipv4 地址等叶子节点,并规定 mtu 的合法范围。这样,配置数据在真正下发前就可以按模型做语法和语义校验,而不是等设备报错才发现字段写错。

YANG 模型通常分为标准模型和厂商私有模型。标准模型如 ietf-interfaces、ietf-ip、openconfig-interfaces 等,适合做跨厂商的通用配置;厂商私有模型则覆盖标准模型未定义的特性,例如某些厂商的 VXLAN、EVPN、Telemetry 配置。实际项目中常见的做法是:通用部分尽量用标准模型,差异化部分用私有模型或模板兜底。YANG 的价值在于它给出了“配置数据的合同”,让自动化系统知道哪些字段可以填、填什么类型、哪些组合是合法的。

JSON/YAML:承载配置意图的数据载体

YANG 定义结构,但具体某次配置的值需要由数据文件提供。JSON 和 YAML 都是常用的数据序列化格式,二者都能表达对象、数组、字符串、数字、布尔值等结构。JSON 语法严格、适合程序生成和解析;YAML 更贴近人类书写习惯,支持注释、缩进表达层级,适合作为配置意图的输入文件。在数据中心场景中,常见做法是把每台交换机、每个 VRF、每个 VLAN、每个 BGP 邻居的参数写成 YAML 变量文件,再由自动化平台读取。

例如,下面是一段描述两台 leaf 交换机接口配置的 YAML 示例,参数为教学示例,并非真实设备实测值:

switches:
  - hostname: leaf-01
    interfaces:
      - name: Ethernet1/1
        description: "to-spine-01"
        enabled: true
        mtu: 9216
        ipv4: "10.10.1.1/31"
  - hostname: leaf-02
    interfaces:
      - name: Ethernet1/1
        description: "to-spine-02"
        enabled: true
        mtu: 9216
        ipv4: "10.10.1.3/31"

这段数据本身不包含任何厂商命令,只表达“哪台设备、哪个接口、描述是什么、MTU 多大、地址是什么”。这种“数据与配置分离”的方式,使同一份数据可以渲染成不同厂商的配置,也便于做版本管理和差异对比。

Jinja2:把数据渲染成设备配置

Jinja2 是 Python 生态中常用的模板引擎,它通过占位符、循环、条件判断和过滤器,把变量数据填充到模板中。模板里写的是配置骨架,变量来自 YAML/JSON 数据。例如,针对上面的接口数据,可以写一个通用模板片段:

{% for intf in switch.interfaces %}
interface {{ intf.name }}
  description {{ intf.description }}
  mtu {{ intf.mtu }}
  {% if intf.enabled %}no shutdown{% else %}shutdown{% endif %}
  ip address {{ intf.ipv4 }}
{% endfor %}

渲染时,Jinja2 会遍历 interfaces 列表,把每个接口的 name、description、mtu、ipv4 填入对应位置,并根据 enabled 决定生成 no shutdown 还是 shutdown。这样,同一套模板可以服务多台设备、多个接口,只要数据文件不同,生成的配置就不同。模板中还可以加入过滤器处理大小写、默认值、IP 地址拆分等,减少重复逻辑。

三者的协作关系与典型工作流

把三者串起来看,YANG 是“模型层”,JSON/YAML 是“数据层”,Jinja2 是“渲染层”。典型工作流是:先根据设备 YANG 模型确定可配置字段和结构;再按该结构编写 YAML/JSON 数据文件,描述本次变更意图;然后用 Jinja2 模板把数据渲染成厂商配置文本或结构化配置;最后通过 NETCONF/RESTCONF/gNMI 或 CLI 下发,并在下发前用 YANG 模型做校验。这个过程中,数据文件可以纳入 Git 管理,模板可以复用,校验可以前置,从而降低人为错误。

YANG · JSON/YAML · Jinja2 协作链路 模型定义结构 → 数据承载意图 → 模板渲染配置 → 校验下发 YANG 模型层 定义可配置字段 数据类型 / 范围 / 必选 层级与约束关系 ietf-interfaces / openconfig 厂商私有模型 JSON / YAML 数据层 承载本次配置意图 设备 / 接口 / VLAN / BGP 可纳入 Git 版本管理 YAML 易读,JSON 易解析 数据与配置分离 Jinja2 模板层 配置骨架 + 变量占位 循环 / 条件 / 过滤器 多厂商模板复用 for / if / default 渲染为 CLI 或结构化配置 配置输出 CLI 命令 NETCONF XML RESTCONF JSON gNMI 数据 按 YANG 模型校验数据合法性,失败则阻断下发 典型工作流 ① 读 YANG 模型 确定字段与约束 ② 编写 YAML/JSON 描述配置意图 ③ Jinja2 渲染 生成配置文本 ④ 模型校验 语法/语义检查 ⑤ 下发与回滚 NETCONF/CLI

实际应用中的关键注意点

第一,模型与数据要匹配。YANG 模型中的节点名、层级和数据类型必须与 YAML/JSON 数据一致,否则校验会失败。例如模型里接口名是 name,数据里写成 interface_name,就会导致渲染或校验报错。第二,模板要处理缺省和异常。Jinja2 中应使用 default 过滤器或条件判断,避免某个字段缺失时生成空行或错误命令。第三,数据文件要按设备或角色拆分,避免一个巨型 YAML 难以维护。第四,渲染结果在下发前应做 dry-run 或 diff,确认变更范围符合预期。第五,YANG 校验能发现结构错误,但不能替代业务校验,例如 IP 地址冲突、VLAN 重复、路由环路等仍需额外检查。

建议把 YANG 模型文件、Jinja2 模板和 YAML 数据文件放在同一个 Git 仓库中,按设备角色分目录管理。每次变更通过分支和合并请求评审,渲染和校验作为 CI 步骤自动执行,这样可以把配置错误拦截在下发之前。