octoDNS 1.22.0 配置参数详解
octoDNS 1.22.0 管理配置逐项详解:manager/providers/zones/processors 顶层键、YamlProvider 与 ZoneFileProvider/BindProvider 全参数默认值(inspect 实查)、记录 YAML 语法与强校验、处理器闭环实测、30% 阈值与根 NS 护栏、双场景生产模板。
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) |
| Python | 3.10.12 |
| octoDNS | 1.22.0(pip 虚拟环境 /opt/octodns/venv) |
| octodns-bind | 1.1.0 |
| BIND9 | 9.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 动态更新目标)沿用安装指南篇的实测环境,正文给出完整内容。
二、前置条件
- 已按安装指南完成 octoDNS 1.22.0 与 octodns-bind 1.1.0 的安装(
pip install octodns==1.22.0 octodns-bind),octodns-sync --version回显octoDNS 1.22.0; - BIND9 已运行并加载了待管理的权威区(
systemctl is-active bind9回显active);以 zone 文件为目标只需目录可写,以 RFC 2136 动态更新为目标还需在 BIND 侧配置 TSIG 密钥与allow-update; - 本篇是配置专题篇,不重复安装全文,但每个示例命令与配置块都可独立执行;安装全流程见《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 | 默认值 | 说明 |
|---|---|---|---|
directory | YamlProvider / ZoneFileProvider | 必填 | YAML 记录目录 / zone 文件目录 |
default_ttl | 两者 | 3600 | 记录未写 ttl 时的缺省 TTL |
enforce_order | YamlProvider | true | YAML 键序校验 |
order_mode | YamlProvider | natural | 键序比较方式 |
populate_should_replace | YamlProvider | false | populate 时是否替换整个区数据 |
supports_root_ns | YamlProvider | true | 是否支持区根 NS |
split_extension / split_catchall | YamlProvider | false / true | 拆分文件模式的扩展名与兜底文件名 |
shared_filename | YamlProvider | false | 多区共用同一文件 |
disable_zonefile | YamlProvider | false | 跳过标准 zonefile 兼容加载 |
escaped_semicolons | YamlProvider | None(当前等效 True) | TXT 值分号转义开关 |
ignore_missing_zones | YamlProvider | false | 源目录缺区文件是否报错 |
file_extension | ZoneFileProvider | . | 生成的 zone 文件扩展名 |
check_origin | ZoneFileProvider | true | 校验 zone 文件 $ORIGIN 与区名一致 |
hostmaster_email | ZoneFileProvider | webmaster | 自动生成 SOA 的管理员邮箱 |
refresh / retry / expire / nxdomain | ZoneFileProvider | 3600 / 600 / 604800 / 3600 | 自动生成 SOA 的四个计时器 |
host | BindProvider | 必填 | RFC 2136 目标服务器地址 |
port | BindProvider | 53 | 更新与传送端口 |
ipv6 | BindProvider | false | 是否按 IPv6 连接 |
timeout | BindProvider | 15 | 网络超时秒数 |
key_name / key_secret / key_algorithm | BindProvider | None | TSIG 更新密钥三元组 |
update_batch_size | BindProvider | 1000 | 单条 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
语法规则逐条说明(前三条为实测踩坑):
- 区根记录用空字符串键
"":A/TXT/CAA/NS 等挂在区根本身的记录全部写进""键下的列表,一个键可挂多条不同类型的记录。 - 键序强制(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
- 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
- MX 记录值是
exchange+preference两键的字典:键名写错(如直接写数字)会报TypeError: argument of type 'int' is not iterable。 - 值结构按类型而定:A/AAAA/CNAME/NS 用纯字符串(多条用
values列表);CAA 用flags/tag/value字典;MX 用exchange/preference字典;TXT 直接字符串。 - 值合法性有强校验:
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
- 记录名不带区名后缀:写
www而非www.example.com.(计划与 dig 里显示的是补全后的 FQDN)。 - 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 / TypeRejectlistFilter | filter.py | 按记录类型放行/剔除 |
| NameAllowlistFilter / NameRejectlistFilter | filter.py | 按记录名放行/剔除 |
| ValueAllowlistFilter / ValueRejectlistFilter | filter.py | 按记录值放行/剔除 |
| NetworkValueAllowlistFilter / NetworkValueRejectlistFilter | filter.py | 按网段放行/剔除 |
| IgnoreRootNsFilter / ExcludeRootNsChanges | filter.py | 忽略根 NS 差异 / 排除根 NS 变更(配合 9.2 护栏使用) |
| ZoneNameFilter | filter.py | 按区名过滤 |
| AcmeManagingProcessor | acme.py | 管理 ACME(证书)挑战记录的生命周期 |
| OwnershipProcessor | ownership.py | 所有权校验(ownership TXT 记录,防止误接管他人记录) |
| TtlRestrictionFilter | restrict.py | TTL 取值白名单约束 |
| TtlClampProcessor | clamp.py | TTL 区间钳制(见 8.4) |
| SpfDnsLookupProcessor | spf.py | SPF 记录 DNS 查询次数合规检查 |
| EnsureTrailingDots | trailing_dots.py | 强制主机名尾点规范 |
| Templating | templating.py | 记录模板化生成 |
| MetaProcessor | meta.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)。
十二、参考链接
- YamlProvider 源码与参数注释:
https://github.com/octodns/octodns/blob/main/octodns/provider/yaml.py(1.22.0) - octodns-bind 包(ZoneFileProvider/BindProvider/AxfrSource):
https://github.com/octodns/octodns-bind(1.1.0) - 处理器文档:
https://octodns.readthedocs.io/en/latest/(processors 章节,检索日期 2026-10-26) - JSON Schema 生成工具说明:官方文档站 manual 章节(
octodns-schema,检索日期 2026-10-26) - 站内系列:《octoDNS 1.22.0 介绍与选型指南》、《Ubuntu 22.04 安装 octoDNS 1.22.0 指南》、《octoDNS 1.22.0 常用 CLI 命令详解》(专栏 octoDNS)
- 站内同类工具:《DNSControl 5.7 介绍与选型指南》(专栏 DNSControl)