octoDNS 1.22.0 配置参数详解

octoDNS 1.22.0 管理配置逐项详解:manager/providers/zones/processors 顶层键、YamlProvider 与 ZoneFileProvider/BindProvider 全参数默认值(inspect 实查)、记录 YAML 语法与强校验、处理器闭环实测、30% 阈值与根 NS 护栏、双场景生产模板。

octoDNSoctoDNSDNS服务器网络自动化运维2026/10/26

octoDNS 1.22.0 配置参数详解

‍‍​​‌​> 目标:逐项讲清 octoDNS 1.22.0 管理配置(YAML)的全部顶层键与三个常用 provider(YamlProvider、ZoneFileProvider、BindProvider/Rfc2136Provider)的参数、默认值与行为边界,并给出 processors 处理器与安全护栏参数的修改-验证闭环。全部参数默认值经实机 inspect.signature 与 octodns-schema 双重核验,关键行为均有实测回显(环境为 Ubuntu 22.04 + octoDNS 1.22.0 + octodns-bind 1.1.0 + BIND 9.18.39)。

一、环境信息

实测服务器环境如下,本篇所有命令与回显均在此环境逐条验证:

项目值
操作系统Ubuntu 22.04 LTS(jammy)
Python3.10.12
octoDNS1.22.0(pip 虚拟环境 /opt/octodns/venv)
octodns-bind1.1.0
BIND99.18.39-0ubuntu0.22.04.7-Ubuntu
配置目录/opt/octodns/config/(管理配置)、/opt/octodns/zones/(记录源文件)
BIND zone 目录/etc/bind/zones/
安装方式pip 虚拟环境(安装过程见《Ubuntu 22.04 安装 octoDNS 1.22.0 指南》)

本篇使用的记录源文件 zones/example.com.yaml 与管理配置 config/production.yaml(zone 文件目标)、config/dynamic.yaml(RFC 2136 动态更新目标)沿用安装指南篇的实测环境,正文给出完整内容。

二、前置条件

  1. 已按安装指南完成 octoDNS 1.22.0 与 octodns-bind 1.1.0 的安装(pip install octodns==1.22.0 octodns-bind),octodns-sync --version 回显 octoDNS 1.22.0;
  2. BIND9 已运行并加载了待管理的权威区(systemctl is-active bind9 回显 active);以 zone 文件为目标只需目录可写,以 RFC 2136 动态更新为目标还需在 BIND 侧配置 TSIG 密钥与 allow-update;
  3. 本篇是配置专题篇,不重复安装全文,但每个示例命令与配置块都可独立执行;安装全流程见《Ubuntu 22.04 安装 octoDNS 1.22.0 指南》。

三、参数查看与修改方式

octoDNS 的「参数」分布在两处:管理配置文件(本篇主体,由 Manager 解析)与记录源文件(YAML zone 文件,由 YamlProvider 解析)。修改一律编辑这两类 YAML 文件,无独立配置命令。查参数有三种实测手段,分别适用于「查结构」「查默认值」「查报错」。

3.1 用 octodns-schema 生成 JSON Schema(查结构)

octodns-schema 工具输出配置文件的 JSON Schema,先看管理配置的顶层键:

/opt/octodns/venv/bin/octodns-schema --kind config | python3 -c \
  "import json,sys; d=json.load(sys.stdin); print('title:', d['title']); print('properties:', list(d['properties'].keys()))"

实测回显:

title: octoDNS config file
properties: ['manager', 'providers', 'processors', 'secret_handlers', 'validators', 'zones']

管理配置合法顶层键共 6 个:manager、providers、processors、secret_handlers、validators、zones。再加 --kind zone 可输出记录源文件的 Schema(含每类记录的值结构定义),输出较长,头部节选:

{
  "$defs": {
    "octodns_meta": {
      "additionalProperties": true,
      "properties": {
        "excluded": {
          "items": {
            "type": "string"
          },
          "type": "array"
        },

配合编辑器的 YAML Schema 校验插件,可在保存时即发现键名拼写错误。两份完整 Schema 也可用 --output 落盘:octodns-schema --kind config --output /opt/octodns/config-schema.json。

3.2 用 inspect.signature 查默认值(查默认)

各 provider 参数的权威默认值在已安装包的类构造函数里,一条命令即可全量打印(这也是本篇默认值表的核验手段):

/opt/octodns/venv/bin/python3 -c "
import inspect
from octodns.provider.yaml import YamlProvider
from octodns_bind import ZoneFileProvider, Rfc2136Provider
print(inspect.signature(YamlProvider.__init__))
print(inspect.signature(ZoneFileProvider.__init__))
print(inspect.signature(Rfc2136Provider.__init__))"

实测回显(即本篇第五、六章参数表的来源):

(self, id, directory, default_ttl=3600, enforce_order=True, order_mode='natural', populate_should_replace=False, supports_root_ns=True, split_extension=False, split_catchall=True, shared_filename=False, disable_zonefile=False, escaped_semicolons=None, ignore_missing_zones=False, *args, **kwargs)
(self, id, directory, file_extension='.', check_origin=True, hostmaster_email='webmaster', default_ttl=3600, refresh=3600, retry=600, expire=604800, nxdomain=3600, *args, **kwargs)
(self, id, host, port=53, ipv6=False, timeout=15, key_name=None, key_secret=None, key_algorithm=None, update_batch_size=1000, *args, **kwargs)

3.3 从报错行列号定位参数错误(查报错)

配置写错时 Manager 会给出配置文件名 + 行号 + 列号,例如 providers 段漏写 BindProvider 必填的 host 时:

octodns.manager.ManagerException: Incorrect provider config for bind, config/dynamic.yaml, line 9, column 5

按行列号直接定位到 YAML 编辑即可,无需开调试日志。更复杂的加载错误(记录校验、键序)同样带行列号,见第七、八章实测。

四、参数总览

4.1 管理配置顶层键

顶层键作用必填默认行为(缺省时)
providers声明全部 provider 实例(源/目标连接器)是无 provider 则 zones 无可用源/目标
zones声明待管理的区及其 sources/processors/targets是不声明即不管理
manager引擎级参数(并发、元数据、校验和等)否四项参数全走默认值
processors定义处理器实例(供 zones 引用)否无自定义处理器
secret_handlers密钥处理器(从外部存储取密钥,避免明文)否不启用
validators校验器开关集合否实测启用 legacy 集合(日志 _configure_validators: enabling sets ['legacy'])

💡 说明:secret_handlers 与 validators 是 1.x 后期加入的顶层键,日常单机场景用得少;本篇重点展开 providers、zones、processors、manager 四个高频键。

4.2 三个常用 provider 的参数总表

参数所属 Provider默认值说明
directoryYamlProvider / ZoneFileProvider必填YAML 记录目录 / zone 文件目录
default_ttl两者3600记录未写 ttl 时的缺省 TTL
enforce_orderYamlProvidertrueYAML 键序校验
order_modeYamlProvidernatural键序比较方式
populate_should_replaceYamlProviderfalsepopulate 时是否替换整个区数据
supports_root_nsYamlProvidertrue是否支持区根 NS
split_extension / split_catchallYamlProviderfalse / true拆分文件模式的扩展名与兜底文件名
shared_filenameYamlProviderfalse多区共用同一文件
disable_zonefileYamlProviderfalse跳过标准 zonefile 兼容加载
escaped_semicolonsYamlProviderNone(当前等效 True)TXT 值分号转义开关
ignore_missing_zonesYamlProviderfalse源目录缺区文件是否报错
file_extensionZoneFileProvider.生成的 zone 文件扩展名
check_originZoneFileProvidertrue校验 zone 文件 $ORIGIN 与区名一致
hostmaster_emailZoneFileProviderwebmaster自动生成 SOA 的管理员邮箱
refresh / retry / expire / nxdomainZoneFileProvider3600 / 600 / 604800 / 3600自动生成 SOA 的四个计时器
hostBindProvider必填RFC 2136 目标服务器地址
portBindProvider53更新与传送端口
ipv6BindProviderfalse是否按 IPv6 连接
timeoutBindProvider15网络超时秒数
key_name / key_secret / key_algorithmBindProviderNoneTSIG 更新密钥三元组
update_batch_sizeBindProvider1000单条 UPDATE 消息打包的变更数

关键差异解读:YamlProvider 是「记录的仓库形态」(source 为主,也可作 target 落盘);ZoneFileProvider 与 BindProvider 是「DNS 服务形态」,前者直接读写 zone 文件(整文件重写),后者走 RFC 2136 协议做增量动态更新(增量比对)。三者的选择见 6.4 的对比与本文生产模板(第十章)。

五、manager 段参数详解

manager 段控制引擎行为,四个参数均实测确认默认值。不写该段时全部走默认,最小配置可以完全省略:

---
manager:
  max_workers: 2
  include_meta: false
  auto_arpa: false
  enable_checksum: false
providers:
  # ...(同 providers 段配置)

逐项说明:

  • max_workers(默认 None):并发工作线程数。不写时按 CPU 数自动决定,实测单核环境日志显示 Manager _config_executor: max_workers=1(octodns-versions 命令的输出中可见)。多区大批量同步时可调大,让多个区的 populate/plan 并行。
  • include_meta(默认 False):是否在计划中包含 octodns_meta 元数据记录(记录各 provider 的最后同步信息)。开启后 dump/sync 会额外生成 meta 记录,配合 Schema 中 $defs.octodns_meta 使用。
  • auto_arpa(默认 False):是否自动生成反向区(ARPA)PTR 记录。开启后 octoDNS 根据 A/AAAA 记录自动维护对应 in-addr.arpa/ip6.arpa 反向区,无需手工写 PTR。
  • enable_checksum(默认 False):开启后 sync 要求用 --checksum 提供期望校验和,校验和不匹配则拒绝执行;此时 --doit 被忽略(octodns-sync --help 原文:ignored when Manager.enable_checksum is used)。适合 CI 流水线里「预览结果经人工确认后再精确执行」的强管控场景。

六、providers 段参数详解

providers 段声明「连接器」实例。每个 provider 有两个角色:source(提供期望状态,如 YamlProvider 读 YAML、AXFR 从服务器拉取)与 target(接收变更下发,如 ZoneFileProvider、BindProvider)。同一实例可以兼作两者(ZoneFileProvider 读写一体)。

💡 技术拓展:octoDNS 面向「自建 BIND」的下发形态有三种,选型对比——

形态类原理适用场景
zone 文件重写ZoneFileProvider每次同步整文件重写 zone 文件,需配合 rndc reload静态区、可接受整文件替换、无 TSIG 配置成本
RFC 2136 动态更新BindProvider标准协议增量 UPDATE,实时生效、免 reload记录频繁变更、要求增量下发与实时生效
AXFR 区域传送AxfrSource只读拉取现有区数据(作 source,作迁移/比对入口)从现有 BIND 服务器导入存量记录

本篇生产模板两种形态都给(第十章场景 A/B);实测环境两种均已跑通闭环。

6.1 YamlProvider(记录源仓库)

YamlProvider 是 octoDNS 的默认记录载体:每个区一个 YAML 文件。完整实例:

---
providers:
  config:
    class: octodns.provider.yaml.YamlProvider
    directory: /opt/octodns/zones
    default_ttl: 300
    enforce_order: true

逐项说明:

  • class:Python 类路径,固定 octodns.provider.yaml.YamlProvider。核心包自带的 provider 才能用 octodns. 前缀;BIND 系列在 octodns-bind 包里(octodns_bind. 前缀),漏装包会报 Unknown provider class(排障实录见安装指南篇)。
  • directory(必填):记录 YAML 所在目录。文件名规则:区名去尾点 + .yaml(如 example.com.yaml),子区是独立文件(sub.example.com.yaml)。
  • default_ttl(默认 3600):记录未显式写 ttl 时的缺省值。安装指南篇实测环境设为 300。
  • enforce_order(默认 true):强制 YAML 键按序排列——顶层键按字母序、记录字典内键按 ttl → type → value(s) 序。乱序直接拒绝加载。实测故意把 grafana 插错位置(排在 mail 之后)触发顶层键序报错:
yaml.constructor.ConstructorError: keys out of order: expected grafana got mail at /opt/octodns/zones/example.com.yaml, line 2, column 1

报错里的「expected grafana got mail」意为:按字母序此处应轮到 grafana(g < m),实际却读到了 mail。把记录按字母序重排即可。键序的意义是保证 Git diff 稳定、多人协作不冲突。

  • order_mode(默认 natural):键序比较方式,natural 对数字结尾的键做自然排序(mx1、mx2、mx10 按数值序);另一可选值 sorted 是纯字典序(mx10 会排在 mx1 前)。保持默认即可,与 octodns-dump 导出格式一致。
  • populate_should_replace(默认 false):默认向区内追加记录;改为 true 时先清空区再装入源数据。仅在一个 zone 配置多个 source、且后者要完全覆盖前者时使用。
  • supports_root_ns(默认 true):是否接受区根 NS 记录。改为 false 时源数据里的根 NS 会被忽略(部分托管服务商由平台侧管理 NS 时使用)。
  • split_extension / split_catchall(默认 false / true):split_extension: true 时采用「每条记录一个文件」的拆分形态(目录名=区名,如 example.com./www.yaml),split_catchall 控制区根等特殊记录是否收进 $<区名>.yaml 兜底文件。该形态由 octodns-dump --split 生成(命令篇有实测),手写配置一般不开。
  • shared_filename(默认 false):多区共享同一个文件(文件名 = 共享名)。仅超小规模多区场景使用。
  • disable_zonefile(默认 false):加载源文件时默认会先尝试按标准 zonefile 语义解析;置 true 跳过,纯 octoDNS 仓库可保持默认。
  • escaped_semicolons(默认 None):当前未显式设置时等效 True(TXT 值中分号必须写 \;),源码注释明确该默认将在 2.0 翻转为 False。1.22.0 建议显式写 escaped_semicolons: true 以规避升级行为变化。
  • ignore_missing_zones(默认 false):zones 声明了某区但 directory 下缺文件时默认报错;多区模板场景可置 true 放行。

6.2 ZoneFileProvider(BIND zone 文件目标)

直接读写 BIND 格式 zone 文件,是「文件重写」形态的目标:

---
providers:
  bind:
    class: octodns_bind.ZoneFileProvider
    directory: /etc/bind/zones
    file_extension: .zone

逐项说明:

  • directory(必填):zone 文件目录。该 provider 读写一体:作 target 时把计划整文件写入;作 source 时从既有 zone 文件读取。
  • file_extension(默认 .):生成文件名 = 区名去尾点 + 扩展名。默认值会生成名为 example.com. 的文件,实测改为 .zone 得到常规的 example.com.zone。
  • check_origin(默认 true):读取 zone 文件时校验 $ORIGIN 与区名一致,不一致报错。
  • hostmaster_email(默认 webmaster):自动生成 SOA 的管理员邮箱(webmaster.example.com.)。
  • default_ttl / refresh / retry / expire / nxdomain(默认 3600 / 3600 / 600 / 604800 / 3600):自动生成 SOA 记录的 $TTL 与四个计时器,实测生成的 SOA 形如:
$ORIGIN example.com.
$TTL 3600
; Name: example.com.
@           3600 IN SOA       ns1.example.com. webmaster.example.com. ( 1792982188 ; Serial
                              3600 ; Refresh
                              600 ; Retry
                              604800 ; Expire
                              3600 ; NXDOMAIN ttl )

Serial 取同步时刻的 Unix 时间戳,每次重写自动更新。

⚠️ 行为边界(实测确认):ZoneFileProvider 作 target 时不做增量比对——其 zone_exists(target=True) 恒为 False,计划恒为全量 Creates、整文件重写。所以它在「预览计划」里看到的永远是 13 条 Creates 而不是 2 条 Updates,这不是缺陷而是设计:文件级替换由 BIND 端 rndc reload 原子加载。需要「增量计划 + 实时生效」时改用 6.3 的 BindProvider。

6.3 BindProvider(RFC 2136 动态更新目标)

走标准 RFC 2136 协议向 named 发增量 UPDATE 消息,实时生效、免 reload:

---
providers:
  bind:
    class: octodns_bind.BindProvider
    host: 127.0.0.1
    port: 53
    key_name: octodns-key
    key_secret: __OCTODNS_TSIG_SECRET__
    key_algorithm: hmac-sha512

逐项说明:

  • host(必填):DNS 服务器地址。漏写时报错链为 TypeError: AxfrPopulate.__init__() missing 1 required positional argument: 'host',随后 Manager 包装为 Incorrect provider config。
  • port(默认 53)、ipv6(默认 false)、timeout(默认 15):连接参数,本机 BIND 用默认即可。
  • key_name / key_secret / key_algorithm(默认 None):TSIG 更新密钥三元组。BIND 侧用 tsig-keygen 生成密钥块(写入 /etc/bind/named.conf 的 key 块与 zone 的 allow-update),octoDNS 侧三者必须与之配对:
tsig-keygen -a hmac-sha512 octodns-key

输出的 secret 字段值即 key_secret(hmac-sha512 时 key_algorithm 写 hmac-sha512)。⚠️ TSIG secret 属于系统级密钥,不要把真实值提交进 Git 仓库:上方 YAML 用 __OCTODNS_TSIG_SECRET__ 占位,部署时注入:

export OCTODNS_TSIG_SECRET='tsig-keygen 输出的 secret 字符串'
sed -i "s|__OCTODNS_TSIG_SECRET__|${OCTODNS_TSIG_SECRET}|" /opt/octodns/config/dynamic.yaml
  • update_batch_size(默认 1000):单条 UPDATE 消息打包的最大变更数;超大批量变更时可调小以降低单包失败重试成本。

实测行为:BindProvider 作 target 时增量比对——源与服务器现状 diff 出最小变更集,同步后日志 Rfc2136Provider[bind] apply: making 1 changes to example.com.;二次同步 plan: No changes。BIND 拒绝的更新(如删除 apex NS 引用的 glue A 记录)会抛 Rfc2136ProviderUpdateFailed: Unable to perform update: REFUSED,处理方式见第十一章常见问题。

6.4 sources 与 targets 的声明方式

provider 在 zones 段按名字引用,同一 provider 可同时出现在多个区:

zones:
  example.com.:
    sources:
      - config
    targets:
      - bind
  sub.example.com.:
    sources:
      - config
    targets:
      - bind
  • 区名必须带尾点(example.com.),这是 octoDNS 的规范区名形式;
  • sources 可写多个(如 YAML 仓库 + AXFR 存量合并),targets 也可写多个(同一次同步推送多家服务商,这是 octoDNS 多厂商聚合能力的直接体现)。

七、zones 段与记录文件语法

7.1 zones 声明结构

zones 段把「源 → 处理器 → 目标」连成管线,还可挂接第五章定义的处理器(见 8.1):

zones:
  example.com.:
    sources:
      - config
    processors:
      - only-a
    targets:
      - bind

三个列表键的执行顺序固定:sources 装载期望状态 → processors 流水线加工 → targets 生成计划并执行。

7.2 子域(subzone)管理

子域作为独立 zone 声明,父区放一条委托 NS 记录即可,两层配置各司其职:

父区 zones/example.com.yaml 中的委托记录(其余记录省略):

---
sub:
  ttl: 3600
  type: NS
  values:
    - ns1.example.com.

子区 zones/sub.example.com.yaml:

---
"":
  - ttl: 3600
    type: NS
    values:
      - ns1.example.com.
api:
  ttl: 300
  type: A
  value: 203.0.113.72
app:
  ttl: 300
  type: A
  value: 203.0.113.71

BIND 侧为子区追加同构的 zone 声明后,一次 sync 同时下发两个区。⚠️ 实测踩坑:子区 YAML 的根 NS 记录 TTL 必须与 BIND 侧既有区一致,不一致时 plan 阶段抛根 NS 保护异常(见 9.2),中止时什么都不会下发(安全护栏在 apply 之前生效,计划框只是展示);对齐后干净下发。dig 验证子区记录:

dig @127.0.0.1 api.sub.example.com A +short

实测回显:

203.0.113.72

7.3 记录文件语法(YAML zone 文件)

以实测环境 zones/example.com.yaml 完整示例讲解(覆盖 A/AAAA/CNAME/MX/TXT/CAA/NS 七类):

---
"":
  - ttl: 300
    type: A
    values:
      - 203.0.113.10
      - 203.0.113.11
  - ttl: 300
    type: TXT
    value: v=spf1 ip4:203.0.113.0/24 -all
  - ttl: 3600
    type: CAA
    values:
      - flags: 0
        tag: issue
        value: letsencrypt.org
  - ttl: 3600
    type: NS
    values:
      - ns1.example.com.
_dmarc:
  ttl: 300
  type: TXT
  value: v=DMARC1\; p=none\; rua=mailto:dmarc@example.com
api:
  ttl: 300
  type: CNAME
  value: www.example.com.
mail:
  ttl: 600
  type: MX
  values:
    - exchange: mx1.example.com.
      preference: 10
    - exchange: mx2.example.com.
      preference: 20
ns1:
  ttl: 86400
  type: A
  value: 203.0.113.53
www:
  - ttl: 300
    type: A
    value: 203.0.113.99
  - ttl: 300
    type: AAAA
    value: 2001:db8::20

语法规则逐条说明(前三条为实测踩坑):

  1. 区根记录用空字符串键 "":A/TXT/CAA/NS 等挂在区根本身的记录全部写进 "" 键下的列表,一个键可挂多条不同类型的记录。
  2. 键序强制(enforce_order 默认开):顶层键按字母序;记录字典内键固定 ttl → type → value(s)。实测把记录内 type 写到 ttl 前面触发:
yaml.constructor.ConstructorError: keys out of order: expected ttl got type at /opt/octodns/zones/example.com.yaml, line 26, column 3
  1. TXT 值中的分号必须 \; 转义:DMARC/SPF 值常用分号,漏转义时记录校验失败:
octodns.record.exception.ValidationError: Invalid record "_dmarc.example.com.", /opt/octodns/zones/example.com.yaml, line 3, column 3
  - unescaped ; in "v=DMARC1; p=none; rua=mailto:dmarc@example.com", via: chunked-value-rfc
  1. MX 记录值是 exchange + preference 两键的字典:键名写错(如直接写数字)会报 TypeError: argument of type 'int' is not iterable。
  2. 值结构按类型而定:A/AAAA/CNAME/NS 用纯字符串(多条用 values 列表);CAA 用 flags/tag/value 字典;MX 用 exchange/preference 字典;TXT 直接字符串。
  3. 值合法性有强校验:octodns-validate 对非法值逐条报错,实测把 www 的 A 值写成 not-an-ip:
octodns.record.exception.ValidationError: Invalid record "www.example.com.", /opt/octodns/zones-bad/example.com.yaml, line 55, column 5
  - invalid IPv4 address "not-an-ip", via: ip-value-rfc
  1. 记录名不带区名后缀:写 www 而非 www.example.com.(计划与 dig 里显示的是补全后的 FQDN)。
  2. ttl 省略时用 provider 的 default_ttl:全篇统一 TTL 的仓库可以完全不写 ttl,减少噪声。

八、processors 处理器

8.1 定义位置与挂接方式

处理器在顶层 processors: 段定义、在 zone 的 processors: 列表引用,两级缺一不可。实测把定义误写进 providers 段时:

octodns.manager.ManagerException: Zone example.com., unknown processor: only-a

「unknown processor」即指 zone 引用了名为 only-a 的处理器但顶层定义缺失(或写错位置)。正确结构:

---
processors:
  only-a:
    class: octodns.processor.filter.TypeAllowlistFilter
    allowlist:
      - A
      - AAAA
zones:
  example.com.:
    sources:
      - config
    processors:
      - only-a
    targets:
      - dump

💡 技术拓展:处理器家族命名有两代——1.x 早期叫 TypeAllowlistProcessor 等(*Processor),现版本统一为 *Filter/*Processor 并存但推荐用 octodns.processor.filter.TypeAllowlistFilter 新名,老教程里的旧类名在新版本会 Unknown processor class。内置处理器按功能分三类:类型/名字/值过滤(filter 家族)、TTL 约束(restrict/clamp)、业务治理(ACME 挑战、所有权校验、SPF 查询、模板、元数据等,清单见 8.5)。

8.2 TypeAllowlistFilter:只放行指定类型(实测闭环)

上面 only-a 处理器只放行 A/AAAA,其余类型在进 target 前被过滤。实测 octodns-sync --config-file=config/processor-test.yaml,源区 13 条记录经过滤器后推到 YAML 目标,目标目录沉淀的正是 6 条 A/AAAA:

2026-10-26T04:08:26  [140228198440960] INFO    YamlProvider[config] populate:   found 13 records, exists=True
2026-10-26T04:08:26  [140228198440960] INFO    YamlProvider[dump] plan: desired=example.com.
2026-10-26T04:08:26  [140228198440960] INFO    YamlProvider[dump] populate:   found 6 records, exists=True
2026-10-26T04:08:26  [140228198440960] INFO    YamlProvider[dump] plan:   No changes

「found 6 records」与源 13 条的差值(13 − 7 = 6,滤掉 TXT/CAA/NS/MX/CNAME 各若干)即过滤器生效的直接证据;二次同步 No changes 说明过滤后的目标已与源一致。对应还有 TypeRejectlistFilter(黑名单)、NameAllowlistFilter/NameRejectlistFilter(按记录名)、ValueAllowlistFilter/ValueRejectlistFilter(按值)、NetworkValueAllowlistFilter/NetworkValueRejectlistFilter(按网段)。

8.3 NameRejectlistFilter:按名字剔除(实测闭环)

---
processors:
  no-www:
    class: octodns.processor.filter.NameRejectlistFilter
    rejectlist:
      - www
zones:
  example.com.:
    sources:
      - config
    processors:
      - no-www
    targets:
      - out

实测同步到空目标目录,计划从 13 条变为 11 条(www 的 A 与 AAAA 两条被剔除):

2026-10-26T04:08:27  [132748200292352] INFO    YamlProvider[config] populate:   found 13 records, exists=True
2026-10-26T04:08:27  [132748200292352] INFO    YamlProvider[out] populate:   found 0 records, exists=False
*   Summary: Creates=11, Updates=0, Deletes=0, Existing=0, Meta=False

rejectlist 匹配的是去掉区名后缀的记录名(如 www),适合「同名记录不下发到某些目标」的场景。

8.4 TtlClampProcessor:TTL 钳制(实测闭环,含参数名排障)

把源区 TTL 钳制到 [min_ttl, max_ttl] 区间再下发。实测配置(config/ttl-clamp.yaml,minimum 600、maximum 43200):

---
providers:
  config:
    class: octodns.provider.yaml.YamlProvider
    directory: /opt/octodns/zones
    default_ttl: 300
  clamped:
    class: octodns.provider.yaml.YamlProvider
    directory: /opt/octodns/dump-clamp
    default_ttl: 300
processors:
  clamp-ttl:
    class: octodns.processor.clamp.TtlClampProcessor
    min_ttl: 600
    max_ttl: 43200
zones:
  example.com.:
    sources:
      - config
    processors:
      - clamp-ttl
    targets:
      - clamped

⚠️ 参数名排障实录:该处理器参数是 min_ttl/max_ttl,若按直觉写 minimum/maximum 会在加载期报错(本次实测原文):

TypeError: BaseProcessor.__init__() got an unexpected keyword argument 'minimum'
...
octodns.manager.ManagerException: Incorrect processor config for clamp-ttl, config/ttl-clamp.yaml, line 13, column 5

修正后 dry-run,每条被钳制记录打出一行 原 TTL -> 新 TTL:

2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor __init__: min=600s, max=43200s
2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor process_source_zone: clamping TTL for example.com. (A) 300 -> 600
2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor process_source_zone: clamping TTL for www.example.com. (AAAA) 300 -> 600
2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor process_source_zone: clamping TTL for api.example.com. (CNAME) 300 -> 600
2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor process_source_zone: clamping TTL for mx2.example.com. (A) 300 -> 600
2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor process_source_zone: clamping TTL for ns1.example.com. (A) 86400 -> 43200
2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor process_source_zone: clamping TTL for example.com. (TXT) 300 -> 600
2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor process_source_zone: clamping TTL for mx1.example.com. (A) 300 -> 600
2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor process_source_zone: clamping TTL for www.example.com. (A) 300 -> 600
2026-10-26T04:08:49  [126332584194048] INFO    TtlClampProcessor process_source_zone: clamping TTL for _dmarc.example.com. (TXT) 300 -> 600
2026-10-26T04:08:49  [126332584194048] INFO    YamlProvider[clamped] plan:   Creates=13, Updates=0, Deletes=0, Existing=0, Meta=False

加 --doit 落盘后检查目标文件,验证钳制真实生效(原 300 的记录变 600、原 86400 的 ns1 变 43200,区间内的 3600/600 不动):

grep -A2 "^ns1:" /opt/octodns/dump-clamp/example.com.yaml; grep -A2 "^www:" /opt/octodns/dump-clamp/example.com.yaml

实测回显:

ns1:
  ttl: 43200
  type: A
www:
- ttl: 600
  type: A

闭环结论:processors 的「修改」发生在 plan 之前,dry-run 计划与最终落盘都体现钳制后的值,验证手段就是对比目标文件 TTL。TTL 一致性还有两个配套工具:TtlRestrictionFilter(restrict.py,限制 TTL 只能取指定值集合)与 TtlClampProcessor(本节,区间钳制),前者偏「合规约束」,后者偏「安全网」。

8.5 内置处理器清单(1.22.0 实查)

处理器模块用途
TypeAllowlistFilter / TypeRejectlistFilterfilter.py按记录类型放行/剔除
NameAllowlistFilter / NameRejectlistFilterfilter.py按记录名放行/剔除
ValueAllowlistFilter / ValueRejectlistFilterfilter.py按记录值放行/剔除
NetworkValueAllowlistFilter / NetworkValueRejectlistFilterfilter.py按网段放行/剔除
IgnoreRootNsFilter / ExcludeRootNsChangesfilter.py忽略根 NS 差异 / 排除根 NS 变更(配合 9.2 护栏使用)
ZoneNameFilterfilter.py按区名过滤
AcmeManagingProcessoracme.py管理 ACME(证书)挑战记录的生命周期
OwnershipProcessorownership.py所有权校验(ownership TXT 记录,防止误接管他人记录)
TtlRestrictionFilterrestrict.pyTTL 取值白名单约束
TtlClampProcessorclamp.pyTTL 区间钳制(见 8.4)
SpfDnsLookupProcessorspf.pySPF 记录 DNS 查询次数合规检查
EnsureTrailingDotstrailing_dots.py强制主机名尾点规范
Templatingtemplating.py记录模板化生成
MetaProcessormeta.py维护 octodns_meta 元数据记录

使用方式统一:顶层 processors: 定义(class + 各自参数)→ zone 内 processors: 列表按序引用;顺序即执行顺序。

九、安全护栏参数

BaseProvider 构造函数上的四个参数(inspect.signature(BaseProvider.__init__) 实测:apply_disabled=False, update_pcent_threshold=0.3, delete_pcent_threshold=0.3, strict_supports=True, root_ns_warnings=True)是 octoDNS 的「防误操作」层,可在 provider 实例下覆盖。

9.1 变更比例阈值(30% 默认)

update_pcent_threshold 与 delete_pcent_threshold 默认均为 0.3(30%):一次计划中 Update/Delete 的条数占既有记录数的比例超限时拒绝执行。实测在 12 条既有记录的区里删除 4 条(33.33%)触发:

octodns.provider.plan.TooMuchChange: [example.com.] Too many deletes, 33.33% is over 30.00% (4/12), force required

按提示加 --force(或调高 provider 的 delete_pcent_threshold)才能执行。设计意图:防止单次误操作清空区数据。大迁移场景的正确姿势是分批删除或显式 --force 并人工复核计划。

9.2 根 NS 变更保护

apex NS 记录的任何变更(增/删/改 TTL)默认触发 RootNsChange 异常:

octodns.provider.plan.RootNsChange: Root NS record change, force required

加 --force 后才执行;root_ns_warnings: false 可降级为仅告警。配套的 IgnoreRootNsFilter/ExcludeRootNsChanges 处理器(8.5)可在管线里直接滤掉根 NS 差异,适合「NS 由平台侧另行管理、仓库不负责 NS」的团队。⚠️ 注意 --force 是全计划放行,不会只放行 NS 变更,所以更稳妥的做法是拆分变更(先同步 NS 以外的部分)或用过滤器。

9.3 strict_supports 与 apply_disabled

  • strict_supports(默认 True):源记录类型/TTL/Geo 能力目标不支持时直接抛异常终止(宽松模式置 False 会跳过不支持的记录并告警)。多厂商聚合时建议保持默认,让「能力差异」在计划期暴露而不是上线后静默丢记录。
  • apply_disabled(默认 False):置 True 后该 provider 只出计划、永不执行(apply 直接跳过)。适合把某个 target 作为「预演目标」长期挂在配置里。

十、生产配置模板

10.1 场景 A:Git 仓库 → BIND zone 文件(小型静态区,2C4G 服务器)

适用:记录数百条以内、变更频率低(日级)、无 TSIG 管理成本诉求。完整 /opt/octodns/config/production.yaml:

---
providers:
  config:
    class: octodns.provider.yaml.YamlProvider
    directory: /opt/octodns/zones
    default_ttl: 300
    enforce_order: true
  bind:
    class: octodns_bind.ZoneFileProvider
    directory: /etc/bind/zones
    file_extension: .zone
zones:
  example.com.:
    sources:
      - config
    targets:
      - bind

同步后需 rndc reload <区名>(或 systemctl restart bind9)让 named 重载文件,验证链 named-checkzone → rndc reload → dig 的完整回显见《Ubuntu 22.04 安装 octoDNS 1.22.0 指南》第六章。

10.2 场景 B:Git 仓库 → RFC 2136 动态更新(频繁变更区,2C4G 服务器)

适用:记录频繁变更(分钟级生效诉求)、多区并行管理(含子域)。完整 /opt/octodns/config/dynamic.yaml:

---
manager:
  max_workers: 2
providers:
  config:
    class: octodns.provider.yaml.YamlProvider
    directory: /opt/octodns/zones
    default_ttl: 300
    escaped_semicolons: true
  bind:
    class: octodns_bind.BindProvider
    host: 127.0.0.1
    port: 53
    key_name: octodns-key
    key_secret: __OCTODNS_TSIG_SECRET__
    key_algorithm: hmac-sha512
zones:
  example.com.:
    sources:
      - config
    targets:
      - bind
  sub.example.com.:
    sources:
      - config
    targets:
      - bind

__OCTODNS_TSIG_SECRET__ 注入方式见 6.3。该模板即本篇全程实测所用的形态:增量 Create/Delete 闭环、--force 护栏触发、子区下发均在此配置上验证通过(命令级回显见《octoDNS 1.22.0 常用 CLI 命令详解》)。

十一、常见问题

Q1:顶层键序与记录内键序报错分不清? 两层都要按序:顶层键按字母序(""、_dmarc、api、grafana、mail…),记录字典内按 ttl → type → value(s)。两类报错形态分别是 keys out of order: expected grafana got mail(顶层,见 6.1)与 expected ttl got type(记录内,见 7.3);把新记录插到字母序的正确位置即可,别按「加到文件末尾」的习惯追加。

Q2:processors 定义了却不生效/报 unknown processor? 检查两点:定义必须在顶层 processors: 段而不是 providers 下(报错原文见 8.1);zone 里要用 processors: 列表显式引用。二者都对仍不生效时,确认类名是新版 *Filter 形态(8.5 表)。

Q3:为什么 ZoneFileProvider 的计划永远是全量 Creates? 设计行为:它整文件重写、不做增量比对(见 6.2 行为边界)。想要增量计划请换 BindProvider(RFC 2136)。

Q4:RFC 2136 删除 apex NS 引用的 A 记录报 REFUSED? BIND 的更新后完整性检查会拒绝「摘掉 NS 引用的 glue」:Rfc2136ProviderUpdateFailed: Unable to perform update: REFUSED(named 日志 update rejected: post update name server sanity check failed)。正确顺序是先在 YAML 摘掉该 NS 引用(此步会触发 RootNsChange,需 --force 且分两次 sync),同步后再删对应 A 记录。

Q5:想缩小 apex NS 集合,RFC 2136 改不动? named 会静默忽略「删除全部 apex NS」的更新(日志 attempt to delete all SOA or NS records ignored)。此类变更走文件通道:rndc freeze example.com → 手工编辑 zone 文件 → rndc thaw。

Q6:TXT 里的分号到底要不要转义? 1.22.0 默认必须转义(escaped_semicolons 未显式设置时等效 True,2.0 将翻转默认),建议显式写 escaped_semicolons: true 固化行为(见 6.1)。

十二、参考链接

  1. YamlProvider 源码与参数注释:https://github.com/octodns/octodns/blob/main/octodns/provider/yaml.py(1.22.0)
  2. octodns-bind 包(ZoneFileProvider/BindProvider/AxfrSource):https://github.com/octodns/octodns-bind(1.1.0)
  3. 处理器文档:https://octodns.readthedocs.io/en/latest/(processors 章节,检索日期 2026-10-26)
  4. JSON Schema 生成工具说明:官方文档站 manual 章节(octodns-schema,检索日期 2026-10-26)
  5. 站内系列:《octoDNS 1.22.0 介绍与选型指南》、《Ubuntu 22.04 安装 octoDNS 1.22.0 指南》、《octoDNS 1.22.0 常用 CLI 命令详解》(专栏 octoDNS)
  6. 站内同类工具:《DNSControl 5.7 介绍与选型指南》(专栏 DNSControl)