octoDNS 1.22.0 常用 CLI 命令详解
octoDNS 1.22.0 全部 7 个 CLI 入口逐个实测:octodns-sync 预览/--doit/--force 与加删记录到 dig 验证的完整闭环、octodns-dump 单文件与 --split 导出、compare/report(csv/json)/validate/schema/versions,全部 --help 参数表与回显逐行照录。
octoDNS 1.22.0 常用 CLI 命令详解
> 目标:把 octoDNS 1.22.0 安装后自带的全部 7 个 CLI 入口(octodns-sync、octodns-dump、octodns-compare、octodns-report、octodns-validate、octodns-schema、octodns-versions)逐一讲透——真实参数表、可独立执行的示例与实测回显,并以「加记录 → dry-run 预览 → --doit 下发 → dig 验证 → 删记录」的完整闭环演示 octodns-sync 的日常工作流。全部输出为实机逐行照录。
一、环境信息
实测服务器环境如下,本篇所有命令与回显均在此环境逐条验证:
| 项目 | 值 |
|---|---|
| 操作系统 | 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(RFC 2136 目标,TSIG 密钥 octodns-key) |
| 管理配置 | /opt/octodns/config/dynamic.yaml(YAML 源 → RFC 2136 目标,含主区与子区) |
| 记录源目录 | /opt/octodns/zones/(example.com.yaml、sub.example.com.yaml) |
| 版本获取日期 | 2026-10-26(PyPI 实查 1.22.0 为最新稳定版) |
管理配置 dynamic.yaml 内容(TSIG secret 以占位符表示,注入方式见《octoDNS 1.22.0 配置参数详解》6.3):
---
providers:
config:
class: octodns.provider.yaml.YamlProvider
directory: /opt/octodns/zones
default_ttl: 300
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 1.22.0 共提供 7 个 CLI 入口,安装后在虚拟环境 bin/ 下。实测清单:
ls /opt/octodns/venv/bin/ | grep octodns
实测回显:
octodns-compare
octodns-dump
octodns-report
octodns-schema
octodns-sync
octodns-validate
octodns-versions
| 命令 | 用途 | 高频场景 |
|---|---|---|
| octodns-sync | 计划并(可选)执行同步 | 日常预览 + 下发,核心命令 |
| octodns-dump | 从任意 source 导出区数据为 YAML | 迁移导入、生成规范格式 |
| octodns-compare | 比对两个数据源的差异 | 变更前核对、漂移检测 |
| octodns-report | 向指定解析器逐条查询并报表 | 变更后核验、多解析器一致性检查 |
| octodns-validate | 校验配置与记录合法性 | 提交前自检、CI 门禁 |
| octodns-schema | 生成配置/记录的 JSON Schema | 编辑器校验辅助 |
| octodns-versions | 打印各 provider 包的实际版本 | 环境盘点、排障第一步 |
💡 说明:老教程中出现的
octodns-verify在 1.22.0 已不存在(上方实测目录可见),记录校验能力由octodns-validate承担、计划校验由octodns-sync预览承担。另注意本组命令的版本查询是全局参数:任意入口加--version均回显octoDNS 1.22.0。
七个命令共享一组通用日志参数(每个 --help 末尾都有):--log-stream-stdout(日志改投 stdout,默认 stderr)、--log-syslog(日志同时发 syslog)、--syslog-device、--syslog-facility、--debug(提级详细日志)、--quiet(降级只看告警/错误与计划)、--logging-config(YAML 定义日志格式)、--version。下文各命令详解只展开各自专属参数。
三、前置条件
- 已安装 octoDNS 1.22.0 与 octodns-bind 1.1.0(安装全流程见《Ubuntu 22.04 安装 octoDNS 1.22.0 指南》),下文命令统一用虚拟环境绝对路径
/opt/octodns/venv/bin/<命令>调用,也可先export PATH=/opt/octodns/venv/bin:$PATH简写; - 有一份可用的管理配置(本篇为
/opt/octodns/config/dynamic.yaml,结构见第一章);octodns-schema与octodns-validate之外,各命令都要传--config-file; - 除 octodns-schema(无需源数据)外,示例均假定记录源目录已有
example.com.yaml(13 条记录);涉及 sync 下发的两节需要目标 BIND9 已按配置授权 TSIG 更新。
四、octodns-sync:同步(核心命令)
octodns-sync 读取管理配置,逐区「populate 装载源 → plan 生成计划 → apply 执行」。1.22.0 没有 --dry-run 旗标:只输出计划不落数据就是默认行为,真正执行必须显式加 --doit。这是它区别于很多工具的安全设计:预览零成本、执行显式确认。
4.1 语法与全部参数
octodns-sync --help
实测回显(全量):
usage: octodns-sync [-h] --config-file CONFIG_FILE [--doit] [--force]
[--checksum CHECKSUM] [--source SOURCE] [--target TARGET]
[--version] [--log-stream-stdout] [--log-syslog]
[--syslog-device SYSLOG_DEVICE]
[--syslog-facility SYSLOG_FACILITY] [--debug] [--quiet]
[--logging-config LOGGING_CONFIG]
[zone ...]
Octo-DNS Multiplexer
positional arguments:
zone Limit sync to the specified zone(s)
options:
-h, --help show this help message and exit
--config-file CONFIG_FILE
The Manager configuration file to use
--doit Whether to take action or just show what would change,
ignored when Manager.enable_checksum is used
--force Acknowledge that significant changes are being made
and do them
--checksum CHECKSUM Provide the expected checksum, apply will only
continue if it matches the plan's computed checksum
--source SOURCE Limit sync to zones with the specified source(s) (all
sources will be synchronized for the selected zones)
--target TARGET Limit sync to the specified target(s)
--version Print octoDNS version and exit
--log-stream-stdout Log to stdout instead of stderr
--log-syslog Send logging data to syslog in addition to stderr
--syslog-device SYSLOG_DEVICE
Syslog device
--syslog-facility SYSLOG_FACILITY
Syslog facility
--debug Increase verbosity to get details and help track down
issues
--quiet Decrease verbosity to show only warnings, errors, and
the plan
--logging-config LOGGING_CONFIG
Configure logging with a YAML file, see https://docs.p
ython.org/3/library/logging.config.html#logging-
config-dictschema for schema details
参数速读:--config-file 必填;zone 位置参数可限定一个或多个区;--doit 从「预览」切到「执行」;--force 放行大比例变更与根 NS 变更两类护栏(见 4.7/4.8);--source/--target 按名字筛选本次参与的 provider;--checksum 配合 manager.enable_checksum: true 做「计划校验和确认后才执行」的强管控。
4.2 预览计划(默认行为,无变更)
先看无变更时的标准形态——源与目标一致,只输出计划框:
octodns-sync --config-file=/opt/octodns/config/dynamic.yaml
实测回显(日志尾部节选,前半为逐区 populate/plan 日志):
2026-10-26T04:17:26 [127248227450880] INFO YamlProvider[config] populate: found 14 records, exists=True
2026-10-26T04:17:26 [127248227450880] INFO Rfc2136Provider[bind] plan: No changes
...
2026-10-26T04:17:27 [127248227450880] INFO Plan
********************************************************************************
No changes were planned
********************************************************************************
「No changes were planned」即预览结论;此时不加任何旗标也不会写任何数据。
4.3 新增记录 → 预览 → 下发 → dig 验证(Create 闭环)
在源文件 zones/example.com.yaml 中按字母序插入一条新记录(grafana 插在 api 与 mail 之间):
grafana:
ttl: 300
type: A
value: 203.0.113.77
再次预览,实测回显(关键行节选):
2026-10-26T04:17:26 [127248227450880] INFO YamlProvider[config] populate: found 14 records, exists=True
2026-10-26T04:17:26 [127248227450880] INFO Rfc2136Provider[bind] populate: found 13 records
2026-10-26T04:17:26 [127248227450880] INFO Rfc2136Provider[bind] plan: Creates=1, Updates=0, Deletes=0, Existing=13, Meta=False
2026-10-26T04:17:27 [127248227450880] INFO Plan
********************************************************************************
* example.com.
********************************************************************************
* bind (Rfc2136Provider)
* Create <ARecord A 300, grafana.example.com., ['203.0.113.77']> (config)
* Summary: Creates=1, Updates=0, Deletes=0, Existing=13, Meta=False
********************************************************************************
计划框逐行解读:区名行(* example.com.)→ 目标与 provider 类(* bind (Rfc2136Provider))→ 逐条变更(行尾 (config) 表示新值来自名为 config 的源)→ Summary 统计(新建 1 条、既有 13 条)。注意增量比对的证据:populate 显示源 14 条、目标 13 条,计划只含差额 1 条 Create——这正是 RFC 2136 目标与 zone 文件目标(整文件重写、计划恒为全量 Creates)的行为差异。
确认计划无误后加 --doit 执行:
octodns-sync --config-file=/opt/octodns/config/dynamic.yaml --doit
实测回显(执行日志节选):
2026-10-26T04:11:42 [131529151401984] INFO Rfc2136Provider[bind] apply: making 1 changes to example.com.
2026-10-26T04:11:42 [131529151401984] INFO Manager sync: 1 total changes
dig 验证记录真实生效(RFC 2136 动态更新即时生效,无需 reload):
dig @127.0.0.1 grafana.example.com A +short
实测回显:
203.0.113.77
4.4 删除记录 → 预览 → 下发 → dig 验证(Delete 闭环)
从源文件删掉 grafana 记录块后预览,实测回显(关键行节选):
2026-10-26T04:11:49 [136961256718336] INFO YamlProvider[config] populate: found 13 records, exists=True
2026-10-26T04:11:49 [136961256718336] INFO Rfc2136Provider[bind] populate: found 14 records
* Delete <ARecord A 300, grafana.example.com., ['203.0.113.77']>
* Summary: Creates=0, Updates=0, Deletes=1, Existing=14, Meta=False
执行并验证(删除比例 1/14 ≈ 7.1%,低于 30% 阈值,无需 --force):
octodns-sync --config-file=/opt/octodns/config/dynamic.yaml --doit
dig @127.0.0.1 grafana.example.com A +short
实测回显(dig 无输出即记录已删除):
2026-10-26T04:11:49 [135327783968768] INFO Rfc2136Provider[bind] apply: making 1 changes to example.com.
2026-10-26T04:11:49 [135327783968768] INFO Manager sync: 1 total changes
4.5 zone 位置参数:只同步指定区
配置里声明了多个区时,把区名作为位置参数可只跑指定区(多区全量同步是默认):
octodns-sync --config-file=/opt/octodns/config/dynamic.yaml "sub.example.com."
实测回显(尾部节选,只有子区被处理):
2026-10-26T04:08:04 [135460420648960] INFO Rfc2136Provider[bind] populate: found 3 records
2026-10-26T04:08:04 [135460420648960] INFO Rfc2136Provider[bind] plan: No changes
2026-10-26T04:08:04 [135460420648960] INFO Plan
********************************************************************************
No changes were planned
********************************************************************************
⚠️ 区名带尾点时注意 shell 引用:"sub.example.com." 建议加引号,避免个别 shell 补全/展开干扰。
4.6 --quiet:只看计划与告警
日常巡检不需要 populate 细节日志时用 --quiet(输出降为告警、错误与计划):
octodns-sync --config-file=/opt/octodns/config/dynamic.yaml --quiet
实测回显(全量输出就这四行):
2026-10-26T04:08:04 [128476810354688] INFO Plan
********************************************************************************
No changes were planned
********************************************************************************
CI 流水线里解析计划结果建议固定用 --quiet,输出面最小、最稳。
4.7 --force:放行根 NS 变更护栏
apex NS 记录的任何变更默认被拒绝(防止误改委派)。实测当源文件中子区根 NS 的 TTL 与服务器现状不一致时,预览直接抛异常:
octodns.provider.plan.RootNsChange: Root NS record change, force required
按官方语义加 --force 后该计划才会执行。⚠️ 两个实测确认的细节:一是护栏在 apply 之前生效,被拒时什么都没有下发(计划框只是展示,不代表已执行);二是 --force 放行的是整个计划(包括同批次的其他变更),所以更稳妥的做法是把根 NS 变更单独成批次执行。若团队约定根 NS 一律不由 octoDNS 管理,可在配置里挂 IgnoreRootNsFilter/ExcludeRootNsChanges 处理器直接滤掉此类差异(见《octoDNS 1.22.0 配置参数详解》8.5)。
4.8 --force:放行 30% 变更比例护栏
Update/Delete 条数占既有记录比例超过 30%(update_pcent_threshold/delete_pcent_threshold 默认 0.3)时同样拒绝执行。实测在 12 条既有记录中区删除 4 条(33.33%)触发:
octodns.provider.plan.TooMuchChange: [example.com.] Too many deletes, 33.33% is over 30.00% (4/12), force required
处理方式二选一:加 --force 人工确认后执行;或大迁移分批删除(每批控制在 30% 以内)。批量换服务商场景建议后者,每一批预览一次、下发一次、report 核验一次。
4.9 --source / --target:按 provider 名筛选
--target bind 只向名为 bind 的目标同步(多目标配置下做灰度下发很有用):
octodns-sync --config-file=/opt/octodns/config/dynamic.yaml --target bind
实测回显(当前无差异,尾部节选):
No changes were planned
********************************************************************************
--source config 同理,把本次同步限定在由 config 源驱动的区上。二者都接受多次传参(如 --target bind --target backup)。
4.10 调试与日志落 syslog
排障时加 --debug 提升日志级别,能看到每个 provider 的 populate 细节与记录比对过程;需要把日志交给 rsyslog 集中采集时加 --log-syslog(可用 --syslog-device 指定 socket、--syslog-facility 指定 facility),或用 --logging-config 传一份 YAML 日志配置(格式遵循 Python logging.config dictSchema)。日志默认走 stderr,流水线采集建议加 --log-stream-stdout 改投 stdout。
五、octodns-dump:导出区数据为 YAML
octodns-dump 从任意已配置的 source 拉取区数据,写成 YamlProvider 规范格式的 YAML——迁移入库(把现网记录导入 Git 仓库)和「重新格式化」都靠它。
5.1 语法与全部参数
octodns-dump --help
实测回显(全量):
usage: octodns-dump [-h] --config-file CONFIG_FILE --output-dir OUTPUT_DIR
[--output-provider OUTPUT_PROVIDER] [--lenient] [--split]
[--version] [--log-stream-stdout] [--log-syslog]
[--syslog-device SYSLOG_DEVICE]
[--syslog-facility SYSLOG_FACILITY] [--debug] [--quiet]
[--logging-config LOGGING_CONFIG]
zone source [source ...]
Octo-DNS Dumper
positional arguments:
zone Zone to dump, '*' (single quoted to avoid expansion)
for all configured zones
source Source(s) to pull data from
options:
-h, --help show this help message and exit
--config-file CONFIG_FILE
The Manager configuration file to use
--output-dir OUTPUT_DIR
The directory into which the results will be written
(Note: will overwrite existing files)
--output-provider OUTPUT_PROVIDER
The configured provider to use when dumping records.
Must support copy() and directory
--lenient Ignore record validations and do a best effort dump
--split Split the dumped zone into a YAML file per record
--version Print octoDNS version and exit
--log-stream-stdout Log to stdout instead of stderr
--log-syslog Send logging data to syslog in addition to stderr
--syslog-device SYSLOG_DEVICE
Syslog device
--syslog-facility SYSLOG_FACILITY
Syslog facility
--debug Increase verbosity to get details and help track down
issues
--quiet Decrease verbosity to show only warnings, errors, and
the plan
--logging-config LOGGING_CONFIG
Configure logging with a YAML file, see https://docs.p
ython.org/3/library/logging.config.html#logging-
config-dictschema for schema details
要点:zone 传 '*'(单引号防 shell 展开)可导出配置里的全部区;--output-dir 会覆盖既有文件;--lenient 在源记录有轻微不规范时尽力导出。
5.2 单文件导出(实测)
mkdir -p /opt/octodns/dump-d1
octodns-dump --config-file=/opt/octodns/config/dynamic.yaml \
--output-dir=/opt/octodns/dump-d1 "example.com." config
实测回显(日志尾部节选):
2026-10-26T04:07:39 [129975178948608] INFO Manager dump: zone=example.com., output_dir=/opt/octodns/dump-d1, output_provider=None, lenient=False, split=False, sources=['config']
2026-10-26T04:07:39 [129975178948608] INFO YamlProvider[config] populate: found 13 records, exists=True
2026-10-26T04:07:39 [129975178948608] INFO YamlProvider[dump] populate: found 0 records, exists=False
2026-10-26T04:07:39 [129975178948608] INFO YamlProvider[dump] plan: Creates=13, Updates=0, Deletes=0, Existing=0, Meta=False
2026-10-26T04:07:39 [129975178948608] INFO YamlProvider[dump] apply: making 13 changes to example.com.
生成文件与内容(头部节选):
ls /opt/octodns/dump-d1/
example.com.yaml
---
? ''
: - ttl: 300
type: A
values:
- 203.0.113.10
- 203.0.113.11
- type: CAA
value:
flags: 0
tag: issue
value: letsencrypt.org
- type: NS
value: ns1.example.com.
- ttl: 300
type: TXT
value: v=spf1 ip4:203.0.113.0/24 -all
_dmarc:
导出格式两点解读:区根记录键被写成 ? ''(YAML 显式空键的标准写法,与手写的 "" 等价);TTL 等于导出 provider 默认 default_ttl=3600 的记录(CAA、NS)省略 ttl 键,其余保留——这是「规范格式」的一部分,直接可被 YamlProvider 重新加载。
5.3 --split:每条记录一个文件(实测)
mkdir -p /opt/octodns/dump-d1-split
octodns-dump --config-file=/opt/octodns/config/dynamic.yaml \
--output-dir=/opt/octodns/dump-d1-split --split "example.com." config
实测回显(日志尾部节选,注意 provider 名变为 SplitYamlProvider):
2026-10-26T04:07:39 [125574253019136] INFO YamlProvider[config] populate: found 13 records, exists=True
2026-10-26T04:07:39 [125574253019136] INFO SplitYamlProvider[dump] populate: found 0 records, exists=False
2026-10-26T04:07:39 [125574253019136] INFO SplitYamlProvider[dump] plan: Creates=13, Updates=0, Deletes=0, Existing=0, Meta=False
2026-10-26T04:07:39 [125574253019136] INFO SplitYamlProvider[dump] apply: making 13 changes to example.com.
ls /opt/octodns/dump-d1-split/example.com./
实测回显(目录名即区名,每记录一个文件):
$example.com.yaml
_dmarc.yaml
api.yaml
mail.yaml
mx1.yaml
mx2.yaml
ns1.yaml
sub.yaml
www.yaml
$example.com.yaml 是兜底文件(split_catchall 默认开),收纳区根(空键)等特殊记录;其余文件名即记录名。拆分形态适合超大区(单文件数千行难评审),对应 YamlProvider 的 split_extension: true 加载形态。
5.4 --output-provider:用配置里已有的 provider 落盘
默认用内置 YamlProvider 写出;--output-provider <名字> 可改用配置里声明的任意支持 copy() 与 directory 的 provider 实例落盘(例如配置里已定义的拆分 provider),避免为导出单独建目录参数。
六、octodns-compare:两数据源差异比对
octodns-compare 不生成计划、不落数据,只回答「两个数据源之间有没有差异、差在哪」——变更前核对、漂移检测(怀疑有人绕过 octoDNS 手工改了 DNS)都适用。
6.1 语法与全部参数
octodns-compare --help
实测回显(全量):
usage: octodns-compare [-h] --config-file CONFIG_FILE --a A [A ...] --b B
[B ...] --zone ZONE [--ignore-prefix IGNORE_PREFIX]
[--version] [--log-stream-stdout] [--log-syslog]
[--syslog-device SYSLOG_DEVICE]
[--syslog-facility SYSLOG_FACILITY] [--debug] [--quiet]
[--logging-config LOGGING_CONFIG]
[zone ...]
Octo-DNS Comparator
options:
-h, --help show this help message and exit
--config-file CONFIG_FILE
The Manager configuration file to use
--a A [A ...] First source(s) to pull data from
--b B [B ...] Second source(s) to pull data from
--zone ZONE Zone to compare
--ignore-prefix IGNORE_PREFIX
Record prefix to ignore from list of changes
--version Print octoDNS version and exit
--log-stream-stdout Log to stdout instead of stderr
--log-syslog Send logging data to syslog in addition to stderr
--syslog-device SYSLOG_DEVICE
Syslog device
--syslog-facility SYSLOG_FACILITY
Syslog facility
--debug Increase verbosity to get details and help track down
issues
--quiet Decrease verbosity to show only warnings, errors, and
the plan
--logging-config LOGGING_CONFIG
Configure logging with a YAML file, see https://docs.p
ython.org/3/library/logging.config.html#logging-
config-dictschema for schema details
--a/--b 各接受一个或多个 provider 名;--ignore-prefix 忽略指定前缀的记录(如临时对比时排除 _acme-challenge 类记录)。
6.2 实测:YAML 源 vs BIND 服务器现状
octodns-compare --config-file=/opt/octodns/config/dynamic.yaml \
--a config --b bind --zone example.com.
实测回显(尾部两行为结论):
2026-10-26T04:07:07 [133641294356480] INFO Manager compare: a=['config'], b=['bind'], zone=example.com.
2026-10-26T04:07:07 [133641294356480] INFO YamlProvider[config] populate: found 13 records, exists=True
2026-10-26T04:07:07 [133641294356480] INFO Rfc2136Provider[bind] populate: found 13 records
[]
结论 [] 表示两源完全一致(Python 列表字面量,无差异元素)。验证其灵敏度:若在 BIND 侧手工多建一条记录,输出会变成列出该记录变更详情的非空列表,退出码亦随差异变化,可直接做巡检脚本断言。
七、octodns-report:解析结果报表
octodns-report 把配置里的每条记录向指定 DNS 解析器逐条真实查询,输出「配置值 vs 实际应答」的一致性报表——下发后的最终核验、多解析器一致性审计都靠它。
7.1 语法与全部参数
octodns-report --help
实测回显(全量):
usage: octodns-report [-h] --config-file CONFIG_FILE --zone ZONE --source
SOURCE [--concurrency CONCURRENCY] [--timeout TIMEOUT]
[--output-format {csv,json}] [--lenient] [--version]
[--log-stream-stdout] [--log-syslog]
[--syslog-device SYSLOG_DEVICE]
[--syslog-facility SYSLOG_FACILITY] [--debug] [--quiet]
[--logging-config LOGGING_CONFIG]
server [server ...]
Octo-DNS Reporter
positional arguments:
server DNS resolver to query
options:
-h, --help show this help message and exit
--config-file CONFIG_FILE
The Manager configuration file to use
--zone ZONE Zone to dump
--source SOURCE Source(s) to pull data from
--concurrency CONCURRENCY
Maximum number of concurrent DNS queries
--timeout TIMEOUT Number seconds to wait for an answer
--output-format {csv,json}
Output format
--lenient Ignore record validations and do a best effort dump
--version Print octoDNS version and exit
--log-stream-stdout Log to stdout instead of stderr
--log-syslog Send logging data to syslog in addition to stderr
--syslog-device SYSLOG_DEVICE
Syslog device
--syslog-facility SYSLOG_FACILITY
Syslog facility
--debug Increase verbosity to get details and help track down
issues
--quiet Decrease verbosity to show only warnings, errors, and
the plan
--logging-config LOGGING_CONFIG
Configure logging with a YAML file, see https://docs.p
ython.org/3/library/logging.config.html#logging-
config-dictschema for schema details
位置参数 server 是要查询的解析器地址(可传多个做横向比对);并发与超时的实际生效值会在日志行中打印(本环境实测 report concurrency=4 timeout=1)。
7.2 实测:CSV 报表
octodns-report --config-file=/opt/octodns/config/dynamic.yaml \
--zone example.com. --source config --output-format csv 127.0.0.1
实测回显(日志头部节选 + 全部数据行):
2026-10-26T04:07:30 [132141501915136] INFO report concurrency=4 timeout=1
2026-10-26T04:07:30 [132141501915136] INFO YamlProvider[config] populate: found 13 records, exists=True
2026-10-26T04:07:30 [132141501915136] INFO report server=127.0.0.1
Name,Type,TTL,127.0.0.1,Consistent
example.com.,A,300,203.0.113.10 203.0.113.11,True
example.com.,CAA,3600,0 issue "letsencrypt.org",True
example.com.,NS,3600,ns1.example.com.,True
example.com.,TXT,300,"v=spf1 ip4:203.0.113.0/24 -all",True
_dmarc.example.com.,TXT,300,"v=DMARC1; p=none; rua=mailto:dmarc@example.com",True
api.example.com.,CNAME,300,www.example.com.,True
mail.example.com.,MX,600,10 mx1.example.com. 20 mx2.example.com.,True
mx1.example.com.,A,300,203.0.113.61,True
mx2.example.com.,A,300,203.0.113.62,True
ns1.example.com.,A,86400,203.0.113.53,True
sub.example.com.,NS,3600,ns1.example.com.,True
www.example.com.,A,300,203.0.113.99,True
www.example.com.,AAAA,300,2001:db8::20,True
13 条记录全部 Consistent=True(配置值与 127.0.0.1 的实际应答一致)。任何一行 False 即配置与该解析器的现实存在漂移,行内并列展示双方值。
7.3 实测:JSON 报表
octodns-report --config-file=/opt/octodns/config/dynamic.yaml \
--zone example.com. --source config --output-format json 127.0.0.1
实测回显(日志数据部分,JSON 单行原样照录):
{"example.com.": {"A": {"127.0.0.1": ["203.0.113.10", "203.0.113.11"], "consistent": true}, "CAA": {"127.0.0.1": ["0 issue \"letsencrypt.org"], "consistent": true}, "NS": {"127.0.0.1": ["ns1.example.com."], "consistent": true}, "TXT": {"127.0.0.1": ["v=spf1 ip4:203.0.113.0/24 -all"], "consistent": true}}, "_dmarc.example.com.": {"TXT": {"127.0.0.1": ["v=DMARC1; p=none; rua=mailto:dmarc@example.com"], "consistent": true}}, "api.example.com.": {"CNAME": {"127.0.0.1": ["www.example.com."], "consistent": true}}, "mail.example.com.": {"MX": {"127.0.0.1": ["10 mx1.example.com.", "20 mx2.example.com."], "consistent": true}}, "mx1.example.com.": {"A": {"127.0.0.1": ["203.0.113.61"], "consistent": true}}, "mx2.example.com.": {"A": {"127.0.0.1": ["203.0.113.62"], "consistent": true}}, "ns1.example.com.": {"A": {"127.0.0.1": ["203.0.113.53"], "consistent": true}}, "sub.example.com.": {"NS": {"127.0.0.1": ["ns1.example.com."], "consistent": true}}, "www.example.com.": {"A": {"127.0.0.1": ["203.0.113.99"], "consistent": true}, "AAAA": {"127.0.0.1": ["2001:db8::20"], "consistent": true}}}
结构按「记录名 → 类型 → 解析器 → 应答值与 consistent 结论」三层嵌套,程序化断言读各记录的 consistent 字段即可(CSV 与 JSON 的记录集合、consistent 结论完全一致)。
八、octodns-validate:配置与记录校验
octodns-validate 把管理配置里所有区的记录全部构建一遍(含强类型校验),但不生成计划、不触碰任何目标——提交前自检与 CI 门禁的标准工具。
8.1 语法与全部参数
octodns-validate --help
实测回显(全量):
usage: octodns-validate [-h] --config-file CONFIG_FILE [--all] [--version]
[--log-stream-stdout] [--log-syslog]
[--syslog-device SYSLOG_DEVICE]
[--syslog-facility SYSLOG_FACILITY] [--debug]
[--quiet] [--logging-config LOGGING_CONFIG]
Octo-DNS Validator
options:
-h, --help show this help message and exit
--config-file CONFIG_FILE
The Manager configuration file to use
--all Validate records in lenient mode, printing warnings so
that all validation issues are shown
--version Print octoDNS version and exit
--log-stream-stdout Log to stdout instead of stderr
--log-syslog Send logging data to syslog in addition to stderr
--syslog-device SYSLOG_DEVICE
Syslog device
--syslog-facility SYSLOG_FACILITY
Syslog facility
--debug Increase verbosity to get details and help track down
issues
--quiet Decrease verbosity to show only warnings, errors, and
the plan
--logging-config LOGGING_CONFIG
Configure logging with a YAML file, see https://docs.p
ython.org/3/library/logging.config.html#logging-
config-dictschema for schema details
8.2 实测:合法配置零输出通过
octodns-validate --config-file=/opt/octodns/config/production.yaml; echo "exit=$?"
实测回显(无任何输出,退出码 0 即全部合法):
exit=0
8.3 实测:非法记录的报错定位
把 www 的 A 记录值故意写成 not-an-ip 后校验(zones-bad 目录的坏记录示例,管理配置 bad.yaml 指向它):
octodns-validate --config-file=/opt/octodns/config/bad.yaml; echo "exit=$?"
实测回显(错误定位行 + 堆栈节选):
Traceback (most recent call last):
...
File "/opt/octodns/venv/lib/python3.10/site-packages/octodns/manager.py", line 1350, in validate_configs
source.populate(zone, lenient=zone_lenient)
...
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
exit=1
错误首行给出文件、行号、列号,次行给出原因与校验器名(ip-value-rfc),退出码 1 可直接做 CI 失败信号。
8.4 --all:宽松模式尽量多报问题
--all 以 lenient 方式校验并打印告警,适合「一次看清全部问题」:
octodns-validate --config-file=/opt/octodns/config/bad.yaml --all
实测回显(节选:先打 WARNING 行,随后仍因硬错误终止):
2026-10-26T04:07:07 [132077689778176] WARNING Record 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
Traceback (most recent call last):
...
ipaddress.AddressValueError: Expected 4 octets in 'not-an-ip'
exit=1
九、octodns-schema:生成 JSON Schema
octodns-schema 输出记录文件(zone)或管理配置(config)的 JSON Schema,配合编辑器插件实现「保存即校验」。它只做静态输出,不读源数据。
9.1 语法与全部参数
octodns-schema --help
实测回显(全量):
usage: octodns-schema [-h] [--kind {zone,config}] [--indent INDENT]
[--output OUTPUT] [--version] [--log-stream-stdout]
[--log-syslog] [--syslog-device SYSLOG_DEVICE]
[--syslog-facility SYSLOG_FACILITY] [--debug] [--quiet]
[--logging-config LOGGING_CONFIG]
octoDNS JSON Schema generator for zone or config YAML files
options:
-h, --help show this help message and exit
--kind {zone,config} Which schema to emit: zone (default) or config
--indent INDENT Number of spaces to indent the JSON output (default:
2)
--output OUTPUT Write schema to this file instead of stdout
--version Print octoDNS version and exit
--log-stream-stdout Log to stdout instead of stderr
--log-syslog Send logging data to syslog in addition to stderr
--syslog-device SYSLOG_DEVICE
Syslog device
--syslog-facility SYSLOG_FACILITY
Syslog facility
--debug Increase verbosity to get details and help track down
issues
--quiet Decrease verbosity to show only warnings, errors, and
the plan
--logging-config LOGGING_CONFIG
Configure logging with a YAML file, see https://docs.p
ython.org/3/library/logging.config.html#logging-
config-dictschema for schema details
9.2 实测:config Schema 的顶层键
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']
9.3 实测:zone Schema 头部与落盘
octodns-schema --kind zone | head -12
实测回显(zone Schema 定义了每类记录的值结构,含 octodns_meta 元数据定义):
{
"$defs": {
"octodns_meta": {
"additionalProperties": true,
"properties": {
"excluded": {
"items": {
"type": "string"
},
"type": "array"
},
落盘给编辑器使用:octodns-schema --kind zone --indent 2 --output /opt/octodns/zone-schema.json。
十、octodns-versions:provider 版本盘点
打印配置里每个 provider 实际加载的包与版本——排障第一步(确认「跑的是哪个版本的什么包」)。
10.1 语法与实测
octodns-versions --help
实测回显(全量):
usage: octodns-versions [-h] --config-file CONFIG_FILE [--version]
[--log-stream-stdout] [--log-syslog]
[--syslog-device SYSLOG_DEVICE]
[--syslog-facility SYSLOG_FACILITY] [--debug]
[--quiet] [--logging-config LOGGING_CONFIG]
octoDNS Versions
options:
-h, --help show this help message and exit
--config-file CONFIG_FILE
The Manager configuration file to use
--version Print octoDNS version and exit
--log-stream-stdout Log to stdout instead of stderr
--log-syslog Send logging data to syslog in addition to stderr
--syslog-device SYSLOG_DEVICE
Syslog device
--syslog-facility SYSLOG_FACILITY
Syslog facility
--debug Increase verbosity to get details and help track down
issues
--quiet Decrease verbosity to show only warnings, errors, and
the plan
--logging-config LOGGING_CONFIG
Configure logging with a YAML file, see https://docs.p
ython.org/3/library/logging.config.html#logging-
config-dictschema for schema details
octodns-versions --config-file=/opt/octodns/config/production.yaml
实测回显(节选:Manager 初始化日志 + 逐 provider 版本行):
2026-10-26T04:07:07 [134883902816256] INFO Manager __init__: config_file=config/production.yaml, (octoDNS 1.22.0)
2026-10-26T04:07:07 [134883902816256] INFO Manager _config_executor: max_workers=1
2026-10-26T04:07:07 [134883902816256] INFO Manager _config_include_meta: include_meta=False
2026-10-26T04:07:07 [134883902816256] INFO Manager _config_enable_checksum: enable_checksum=False
2026-10-26T04:07:07 [134883902816256] INFO Manager _config_auto_arpa: auto_arpa=False
2026-10-26T04:07:07 [134883902816256] INFO Manager __init__: provider=config (octodns.provider.yaml 1.22.0)
2026-10-26T04:07:07 [134883902816256] INFO Manager __init__: provider=bind (octodns_bind 1.1.0)
2026-10-26T04:07:07 [134883902816256] INFO Manager _configure_validators: enabling sets ['legacy']
版本行即 provider=<配置名> (<包> <版本>);顺带能看到 manager 四参数的实际生效值(本环境 max_workers=1 为单核下的自动值)。
十一、注意事项
- 预览与执行的边界:octodns-sync 不加
--doit永不写数据;1.22.0 无--dry-run旗标,预览就是默认行为,脚本里判断「是否执行」只认--doit是否出现。 - 计划框是展示、护栏在 apply 前:
RootNsChange/TooMuchChange被拒时什么都没下发(4.7/4.8 实测),不要把计划框误读为已生效。 - --force 放行整个计划:把大变更拆小批次,别用
--force一把梭。 - 目标形态决定计划形态:RFC 2136 目标出增量计划(Create/Update/Delete),ZoneFileProvider 文件目标恒为全量 Creates + 整文件重写(需
rndc reload),对比与排障时先确认目标类型。 - octodns-dump 会覆盖输出目录中的同名文件(help 原文注明),导出前确认目录用途。
- report 的 consistent 是逐解析器结论:多解析器审计要逐个 server 跑或一次传多个 server,单次
True不代表全网一致。 - zone 名带尾点:sync 位置参数与 compare 的
--zone都要传example.com.规范形式,建议加引号。
十二、常见问题
Q1:执行 octodns-sync 提示命令不存在? 八成在系统 Python 里找了。octoDNS 装在虚拟环境,用绝对路径 /opt/octodns/venv/bin/octodns-sync,或先 export PATH=/opt/octodns/venv/bin:$PATH。
Q2:预览有 Create/Update 计划,--doit 后记录没生效? 先看 --doit 输出有没有 apply: making N changes:没有说明护栏拦截(往上翻 RootNsChange/TooMuchChange 异常);有 making N changes 但 dig 查不到,检查 dig 指向的解析器是否为目标服务器本身(RFC 2136 即时生效,zone 文件目标则要先 rndc reload)。
Q3:octodns-validate 报 keys out of order? YAML 键序校验(enforce_order 默认开),顶层键按字母序、记录字典内 ttl → type → value(s),按报错行列号把键挪到正确位置;批量重排用 octodns-dump 重新导出规范格式最省事。
Q4: octodns-report 全部 False? 多为 server 参数指错(应答的不是配置里那个目标),或查询的区在解析器侧未加载;先 dig @<server> <区 SOA> 确认解析器认识该区再跑 report。
Q5:迁移老 BIND 服务器记录从哪条命令入手? 把该服务器配成 AXFR source(octodns-bind 包 AxfrSource)或临时 ZoneFileProvider source,先 octodns-compare 摸底、再 octodns-dump 导出 YAML 入库,之后按《octoDNS 1.22.0 配置参数详解》的 provider 配置接入正式同步。
十三、参考链接
- octoDNS 官方文档(工具总览):
https://octodns.readthedocs.io/en/latest/(检索日期 2026-10-26) - octodns-bind 包(ZoneFileProvider/BindProvider/AxfrSource):
https://github.com/octodns/octodns-bind(1.1.0) - PyPI 项目页:
https://pypi.org/project/octodns/(1.22.0,检索日期 2026-10-26) - 站内系列:《octoDNS 1.22.0 介绍与选型指南》、《Ubuntu 22.04 安装 octoDNS 1.22.0 指南》、《octoDNS 1.22.0 配置参数详解》(专栏 octoDNS)
- 站内同类工具(Go 形态 CLI 对照):《DNSControl 5.7 介绍与选型指南》、《Ubuntu 22.04 安装 DNSControl 5.7 指南》(专栏 DNSControl)