跳转到主要内容

Pigsty 使用 Barn 时的宿主 DNS / 域名解析方案

以显式 hosts 同步为起点,明确 Pigsty 域名语义、来源替换保护,以及 macOS 与 Linux 的可选按域转发升级路径。
说明

2026-11-11 范围收敛:首期交付改为 固定核心域名与 Pigsty CA 信任。本页保留更广的导出器和解析器研究;通用清单与 split DNS 属于可选扩展,不作为固定配置的实现前提。

当前推荐先做显式启用的 hosts 管理。 Pigsty 计算名称和服务目标,Barn 通过现有 helper 预览并安装一份中性的地址/名称快照。对于地址固定的 Linux 实验环境,这项功能值得做:宿主可以直接打开 portal,通过节点名连接机器,通过集群名或 VIP 名访问数据库。静态地址让重复同步成本很低,记录不变就无需特权操作。但每次真正修改系统 hosts,包括删除记录,仍需 root 权限。 setup 不会永久授权以后的更新;sudo 缓存或免密策略省掉的是密码提示,并没有消除特权。现阶段保留按次授权,等到客机 DNS 入口稳定、命名空间完整后,再增加可选的后缀转发。宿主常驻 DNS 服务则需要前两种方案无法满足的明确需求。

状态:设计日期为 2026-11-10;取证与综合写作跨至 2026-11-11,Asia/Shanghai。核查的 Barn v1.1.0 标签源码 b2cc8da 已支持从已应用节点状态发布 hosts。vm_hosts、hosts install -f、大小写归一化及 Pigsty bin/sandbox-dns 是上述日期核查的 未提交、未发布原型。下文的来源保护、导出模式、事务增强和 DNS 适配器均为 提案。本轮没有验证发布二进制或真实平台行为。迁移文章 提供整体背景;本文独立定义 DNS 部分的实施方案。

先选择成本最低且足够有用的发布方式

方案 覆盖范围与日常操作 权限与故障表现 决定
管理 hosts 有限的短名与 FQDN;显式同步完整快照;客机停止后仍可解析,但连接会失败 每次实际写入/删除需要特权;相同快照无操作;无需常驻服务 首选实现,始终显式启用
按后缀转发至客机 DNS 只覆盖约定域内客机实际提供的记录;客机数据更新无需重写宿主路由 安装路由、修改入口与卸载需要特权;路由不变时,更新记录无需宿主特权;依赖客机 DNS 可选的下一步;分别实现 macOS/Linux 适配器,并处理短名
宿主本机 DNS daemon 可支持高频记录变更、通配符及更多 RR 类型;用户数据可独立于固定系统路由更新 服务/路由的安装和变更需要特权;服务身份、端口、启动、崩溃与升级都需要维护 等实测需求足以承担维护成本后再做
零自动配置/手工模式 使用 IP、已有 DNS,或经审查的应用/系统覆盖配置 Barn 不修改系统状态;用户负责集成与清理 始终保留;普通 setup 和 VM 生命周期默认遵循这一策略

不做自动配置时,Barn 的 SSH 别名和直接 IP 访问仍然可用。但多个 portal 的 Host/TLS 名称、浏览器 URL 和应用设置仍需要已有 DNS 或手工覆盖配置。单个应用的覆盖配置不能提供系统级解析,手工复制的映射也会随着清单变更而过期。

产品边界仍是一名用户的一套 Linux 部署、一种主机清单格式,以及宿主上唯一的 Barn 管理块。更换 BARN_HOME 不会产生独立的 hosts 命名空间。Pigsty 负责 portal、PostgreSQL、VIP 和 MinIO 的含义;Barn 不发现 Patroni leader,也不理解 Pigsty 角色。这符合 Barn 开发契约。

flowchart LR
  I["Pigsty 清单与上下文"] --> P["Pigsty 规则与所选视图"]
  P --> S["all.hosts + vm_hosts 快照"]
  S --> B["Barn 离线计划"]
  B --> H["特权 helper"]
  H --> F["唯一 hosts 管理块"]

先定义名称与视图,再选择解析器

建议默认导出 宿主访问意图:合并所选 portal 入口名称、节点身份、显式记录及服务别名,形成有明确用途的集合。它可以有意包含客机 dnsmasq 中没有的名称。导出报告保留 vm-identity、guest-hosts、infra-dns、portal-access、service-access 分类,以及各条记录的来源、视图和目标类型。guest-dns 视图则按任务条件复现所选 infra 的 DNS 输出。共享计算规则需要统一身份与目标地址的推导,同时允许不同输出策略。

以下表格统一规定名称映射。中间一列描述已审计的 Pigsty 行为,最后一列是拟议的宿主访问发布策略。

名称来源 已核查的含义与目标 宿主访问发布策略
Barn 节点身份与 vm_alias 优先 nodename,其次 pg_cluster-pg_seq,最后 node-末段;别名指向节点地址 发布解析后的 VM 名称/别名。新增服务名使用 vm_hosts,避免改变 VM 规格。Barn 清单解析
node_default_etc_hosts、node_etc_hosts 客机 hosts 记录,受 node_write_etc_hosts 控制;使用该节点有效的 ${admin_ip} 将所选视图中启用的记录归为 guest-hosts,逐物理行解析。节点名称交换属于另一套任务上下文。Node DNS 任务
dns_records 写入 infra hosts 数据文件,并替换 ${admin_ip};dns_enabled 控制服务启动,不控制所有文件生成,也不会自动移除已运行的服务 按期望配置发布显式记录,并标明来源;不能从开关推断 DNS 是否运行。客机 dnsmasq 使用 no-hosts,不会自动提供客机 /etc/hosts 中的记录。Infra 任务、dnsmasq 模板
infra_portal.*.domain/domains Nginx 名称,不会自动成为 DNS 记录。任务要求非空 domain;标准 home/path/endpoint 模板支持别名 将启用的虚拟主机映射到明确选定的入口,通常是其有效 admin_ip。不能使用可能指向 loopback 的后端 endpoint。无法解释的自定义模板应拒绝;只有 domains、被任务跳过的条目不发布,并给出诊断。Portal 任务
PG 实例 pg_cluster-pg_seq 指向清单地址;PG DNS 任务受 PG 节点的 dns_enabled 控制。实例名不附加 pg_dns_suffix 有效实例别名作为 service-access 发布,即使客机 DNS 被禁用,也可明确标注为宿主便利别名;不能据此声称客机已发布该 DNS 记录。PG DNS 任务
PG 集群 pg_cluster + pg_dns_suffix 直接拼接后缀,默认后缀为空。auto:启用的 PG VIP,否则取声明的 primary;primary:声明的 primary;vip:启用的 VIP,未启用则无地址;none:无地址;显式 IP:配置的目标 按这些规则生成 service-access,并标明 DNS 禁用时的便利别名。需要 primary 时必须恰好有一个。拒绝显式 CIDR 目标:当前角色保留掩码,原型却静默剥离;PG VIP 分支本身则明确会剥离 VIP 掩码。PG 默认值、PG 身份
节点 VIP node_cluster + vip_dns_suffix 启用的 vip_address,独立于 PG VIP;依赖有效节点身份规则 发布校验后的裸 VIP 地址。当前 DNS 任务原样输出该值,因此在角色与导出器共同修正前,拒绝这里的 CIDR 输入。Node monitor 任务
MinIO 成员名称 展开的 minio_node 与 minio_cluster-minio_seq 指向成员 IP 发布成员身份。MinIO 服务名须来自 dns_records、启用的节点 hosts、portal 策略或显式 vm_hosts;minio_domain 本身用于证书/客户端命名,不会单独产生 DNS 记录。MinIO 身份、MinIO 配置
显式 all.vars.vm_hosts 仅原型支持的中性 {address, names} 记录 作为显式意图加入,遵循相同的冲突检查;不能静默覆盖与其矛盾的推导记录

Barn VM 名称必须是小写短标签,最长 63 字符。Pigsty 可能把客机改成另一个名字:node_id_from_pg: true 可以覆盖显式 nodename,而 Barn 的回退推导不读取这个开关。若要保持身份一致,应明确设置短 nodename,并按需关闭 Pigsty 的 PG 身份覆盖;FQDN 放入别名。依据:Pigsty 节点身份。

多台 infra 拥有不同的 admin_ip 和 i.pigsty 视图,可能完全合理。宿主必须明确选定一个入口/视图、使用不同名称,或配置稳定的共享入口;不能默认取第一台 infra。只有相关答案和发布代次一致的 DNS 副本,才可作为冗余上游。

复用现有清单形状,明确导出边界

原型可复用的边界是现有清单格式的最小投影。下面的 .100 只是示例,实际使用前须另行配置可达的 VIP。

host-names.yml — 原型兼容形状
all:
  hosts:
    10.10.10.10: {nodename: meta}
  vars:
    vm_hosts:
      - address: 10.10.10.10
        names: [i.pigsty, meta]
      - address: 10.10.10.100
        names: [pg-meta]

vm_hosts 只能位于 all.vars;条目只接受 address 和非空字符串列表 names。来源信息单独放在报告中,不能塞进额外字段。清单至少需要一个托管节点:只有 vm_hosts 的文档当前会报 inventory defines no hosts。all.hosts 提供节点身份和 /24 上下文。这是可丢弃的生成结果,不是让用户维护第二份清单。它可以在 VM 创建前发布,但不能证明节点或服务已经存在。

当前 Barn 适配器要求每个名称只对应一个规范 RFC1918 IPv4 地址,地址位于托管 /24 的 .9–.254。.1 属于宿主,.2–.8 为保留范围,.0 和 .255 不可用。多 A 答案、外部目标、IPv6、通配符及非地址 RR 类型需要明确选择其他方案;hosts 格式或 DNS 协议本身的能力不会自动扩大适配器边界。自定义私有 /24 可以使用,但须同步调整 Pigsty 的 admin_ip、记录与 VIP。DNS 不负责创建路由或 VIP。Barn 网络布局

先交付受限字面模式,再支持完整 Ansible 语义

拟议模式:literal 为声明支持的静态 profile 生成宿主访问意图;rendered 使用正常 Pigsty 控制节点的有效变量与角色规则计算所选视图;observed 则显式采集指定 infra 节点已部署的 DNS 数据及服务观察结果。任务被跳过或失败后,渲染意图可能不同于已安装文件;文件也可能不同于服务实际回答。报告必须写清采集了什么证据、何时采集。任何模式都不等于实时 Patroni 权威信息。

第一阶段的字面模式严格限于:一个 YAML 来源、按角色上下文保留的已知默认值、无歧义继承、支持的标准 portal 模板,以及文档规定的 ${admin_ip}/MinIO 占位符替换。检测并拒绝相邻目录或控制节点侧的 group_vars、host_vars,以及多来源/插件、DNS 相关 Jinja/lookup/facts、同级组歧义和不支持的任务上下文。不能静默忽略变量来源。转义换行与块文本换行必须逐行解析;错误类型和 CIDR 边界应明确拒绝,不能“修复”为另一种角色语义。

先在所有相关 Pigsty 主机上计算身份和目标,包括 vm_skip 的外部 primary/infra,再应用 Barn 的地址限制。在尚未支持这种计算前,应拒绝受影响的 profile,不能漏掉这些角色。VIP 冲突检查必须纳入所有已知外部地址;某台机器不交给 Barn 虚拟化,不代表可以丢弃它与 DNS 有关的配置。

第二阶段引入 Pigsty 共享纯函数与有效变量适配层,并在 各自选定的视图内 验证与角色渲染等价。ansible-inventory --list 能处理清单变量,却不会执行全部角色默认值、set_fact、任务条件或控制节点模板。通用支持需要明确提供这些上下文,并拒绝尚未解析的值。受控的只读导出可以在正常 Pigsty 控制节点执行,再把净化后的投影传给宿主,宿主用户无需安装 Ansible。完整的 VM 创建前导出仍只适用于不依赖客机事实的 profile。Ansible 变量合并规则

校验与提取必须绑定同一代输入,发布前检查相关源文件和默认值文件是否变化。权限为 0600 的临时文件只写节点身份和名称,不持久化完整 hostvars、凭据或共享目录设置。拟议的 --mode、--view、--export 属于 Pigsty,不属于 Barn。默认 --view host-access 要求入口无歧义;host-access:<infra-node> 明确选择其视图,guest-dns:<infra-node> 选择 DNS 输出。第一阶段拒绝尚未支持的选择。observed 初期只支持 guest-dns,不凭空补充便利记录。--export FILE 只写投影,与应用操作互斥。现有 --json 继续表示 Barn 计划。

显式替换来源,防止服务名消失

证据 能说明什么 不能说明什么
当前期望清单/导出结果 本次要发布的名称,可早于 VM 创建 已应用节点、成功执行的 Pigsty 任务或运行中的 DNS
Barn 已应用节点状态 已提交的节点地址、名称与 vm_alias,包括停止的节点 vm_hosts、portal、服务别名或当前 leader
已安装管理块及元数据 宿主文件当前内容,以及记录的来源种类 当前源文件路径、存活客机或最新部署的 DNS

原型替换整个管理块,因此在 hosts install -f 之后运行裸 hosts install,可能删掉只存在于清单中的服务别名。最小保护提案:在现有块内加入一个稳定的普通注释,值为 # source-kind: inventory 或 # source-kind: applied。不能新造 # barn: 标记,当前解析器会拒绝未知标记。这份元数据只保护 CLI 来源选择,与操作系统授权分开处理。

已安装管理块 提案中裸 hosts install 的行为 显式来源选择
不存在、无来源标记的旧块,或 applied 保留标签版本行为:从已应用节点生成快照,照常预览/确认 -f FILE 选择清单;--from-applied 选择已应用状态
inventory 在 sudo 前失败,即使带 --yes 也一样;提示如何保留或替换服务名 -f FILE 用完整清单快照替换;拟议的 --from-applied 明确授权切换为节点快照,并展示删除项
未知/重复来源元数据,或损坏块 失败并给出修复说明 不自动覆盖

-f 与拟议的 --from-applied 互斥。改用另一个 -f 本身就代表明确切换来源。不要记忆源文件路径,尤其不能记忆 Pigsty 临时路径;不增加发布者注册表或项目作用域。下次完整同步中缺席的记录会删除。vm_hosts: [] 保留该来源的节点名/别名。提取失败或非法空清单绝不能清空管理块,完全移除使用 hosts uninstall。删除名称不会销毁 VM。

用于语义 no-op 判断的摘要只依赖发布后的规范记录和来源种类。输入摘要、规则版本、所选视图与详细来源放在普通用户报告中,不写成管理块里的动态时间戳注释。密码、CPU、文件路径或无关清单修改不能导致每次都请求 root。但仍须比较目标实际字节,不能用相同的记录摘要掩盖损坏标记或外部编辑。给旧块增加来源注释属于一次性的特权迁移。

没有来源标记的原型块无法可靠判断是否含清单服务名。升级时先显式重装完整 -f 快照,再使用裸命令。最低要求是实现该保护的 CLI 及配套 helper,具体发布版本号尚待分配。旧 CLI 会无视注释并覆盖整个块,因此不能承诺安全降级。包装脚本应检查所需能力,不能只比较版本字符串。

离线预览,再授权实际变更

审计时的原型已具备以下接口,但接口存在不代表已经满足后文的实施门槛。

已有接口 准确行为
bin/sandbox-dns -f FILE --json 输出 Barn 计划 JSON,不是记录导出;默认文件为 pigsty.yml
bin/sandbox-dns -f FILE --apply 包装脚本先预览,再以 --yes 调用 Barn
barn hosts install -f FILE --json 从清单预览,不应用
barn hosts install -f FILE --yes 应用清单快照;Barn 没有 --apply 参数
barn hosts install -f FILE --json --yes 应用并返回结构化输出;JSON 不等于只读
barn hosts uninstall --json / --yes 预览/显式删除整个 Barn 管理块

第一阶段验收后的拟议工作流:通过 Pigsty 预览并显式应用;portal、节点或 VIP 改动后重复相同步骤。下面两条命令的写法已存在于原型,增强后的安全语义属于提案。

拟议的日常工作流
bin/sandbox-dns -f pigsty.yml --json
bin/sandbox-dns -f pigsty.yml --apply

为了审查或从控制节点向宿主传递结果,拟议导出器生成同样的临时投影。下面只有 --mode、--view、--export 是新增参数。

拟议的显式导出工作流
bin/sandbox-dns -f pigsty.yml --mode literal --view host-access --export host-names.yml
barn hosts install -f host-names.yml --json
barn hosts install -f host-names.yml --yes

切回纯节点发布会有意删除服务别名。拟议的 --from-applied 明确表达这种替换;uninstall 已存在,不要求清单或部署状态。

拟议来源切换,以及独立的清理示例
barn hosts install --from-applied --json
barn hosts install --from-applied --yes
barn hosts uninstall --json
barn hosts uninstall --yes

每次应用都必须 先形成并展示完整计划,再请求 root:新增、修改、删除和保留的名称,旧/新地址,分类、来源种类与具体出处,冲突,原生目标路径,以及记录代次和字节前提条件。即使旧记录没有字段级来源,也要展示从原管理块移除的名称。计划只读取本地文件与状态,不查 DNS、不连接客机、不下载、不安装 helper。观察模式的导出应在计划之前单独采集。不输出秘密或完整 hostvars。

拟议结果契约 结果
预览(--json 且不带 --yes,或无终端且不带 --yes) 计划有效时退出 0,applied: false;即使有变更也不调用 sudo
规范记录未变,且已安装字节有效 退出 0,changed: false,不安装 helper、不调用 sudo
交互文本且不带 --yes 展示计划并询问;Barn install 默认 Yes,uninstall 默认 No;包装脚本未带 --apply 时仍只预览
无终端的显式应用 使用非阻塞授权;权限不足则返回 capability 错误和非零退出码,不等待密码,不写 hosts
非法输入、违规来源切换、冲突或过期代次 写入前以非零退出码失败;要求重新规划,不静默重算并提交另一份数据
写入验证成功/写后验证失败 仅验证成功才退出 0;否则报告失败及可能的部分状态,不谎报回滚成功

保留 Barn 的 {plan, applied} 报告形状。当前 plan 包含 schema、action、target、changed、前后摘要,以及可选的 lines/helper 摘要;来源与差异详情属于新增内容。当前 Python 包装脚本不保证错误也是 JSON,结构化错误对齐列为第一阶段工作。

加固现有特权边界

当前 CLI 的正常规划只改自己的管理块。固定 helper 校验原生目标、调用者/暂存文件的所有者、权限和摘要,原子替换后复核字节以及 uid/gid/mode。但它没有独立证明暂存文件只修改 Barn 块,也没有覆盖检查到 rename 全过程的事务锁。 通过的测试未覆盖这两个缺口。调用者提供的摘要只能证明字节一致,不能证明修改范围被授权;原子 rename 也不是 compare-and-swap。标签版本 helper 实现

拟议写入流程保留原边界:helper 获取 root 所有的宿主级协作锁,重读目标并检查已审查摘要,校验有大小上限的记录、来源元数据及冲突,自行重建允许的替换结果,再比较、原子写入并复核。uninstall 只能移除该块。保留块外字节,首次追加需要补末尾换行的已知例外单独说明;承诺保留更多文件系统元数据前补充测试。其他 root 编辑器未必遵守 Barn 锁,因此仍需旧字节校验。应用期间固定生成源;包装脚本必须将已展示计划绑定到应用请求,或让同一次 Barn 调用展示并应用权威计划,不能在两个子进程之间丢弃之前的预览约束。

按次 sudo 仍为主要方式。setup 安装 root 所有、摘要配对的 helper,真正写入仍以特权执行。--yes 只跳过 Barn 确认。当前非交互授权使用 sudo -n,交互调用则可以要求认证。持久窄权限授权属于可选后续工作,必须先完成 helper 内部范围校验和锁;不能授权任意配置 include,也不能扩展为无限制 sudo。仅授权 helper 的规则还需要专门的能力探测,因为现有 sudo -v/true 探测可能误判这类策略不可用。Sudo 行为、sudoers 命令参数

将名称清理与 VM 生命周期分开负责

事件 拟议职责与残留状态
首次 setup/boot/up 按需准备网络/helper,提示显式 DNS 工作流;仅在用户选择后发布,清单意图可以早于 VM;不隐式同步 hosts
重复同步/客机部署 Pigsty 重新生成所选完整视图,Barn 比较并发布;部署客机不隐式提升宿主权限
stop、启动或重启 保留名称,提示可解析地址可能离线;不因生命周期操作单独请求 root
移除节点、destroy 或清空部署数据 保留管理块;展示残留名称与显式清理命令。有期望来源时显示差异,只有已应用状态时诊断缺席节点,不猜测服务意图
hosts uninstall 只移除 Barn 管理块,保留当前块外内容、VM、磁盘及客机 DNS
删除 BARN_HOME/重装工具 仍可依据原生管理块清理。重装兼容 CLI/helper 后执行 hosts uninstall,不依赖已删除状态或记忆的源路径
卸载 Barn 软件 明确删除二进制会留下宿主记录;先提供独立、显式的清理操作,并保留兼容版本重装或管理员编辑管理块的恢复说明

拟议诊断比较来源种类、规范记录代次与当前字节,不能只看 begin 标记是否存在。它需要区分过期的期望导出、不可用的已应用状态与停止的客机。刚发布的名称也不等于服务健康。

旧 Pigsty Vagrant DNS 使用 逐行 # pigsty dns 注释,没有成对的管理块,并把一组固定别名指向第一台 VM。Barn 必须保留这些外部记录:同地址的重复项会留下,不同地址则冲突。迁移时先盘点标记行,与完整新视图比较,突出只存在于旧记录中的名称。随后由显式 Pigsty 迁移步骤或管理员在重新比较文件后,仅删除已审查的旧记录,再交给 Barn 发布。不能按 .pigsty 后缀删除,也不能复用旧脚本宽泛的子串删除逻辑。Barn 的窄权限 helper 不应取得 Vagrant 行的所有权。最后确认重复记录已清除,以免以后 Barn uninstall 后名称仍然存在。

分别验证服务可达性与高可用

pg_primary_ip 是清单中唯一声明的 primary,计算时应包含相关外部主机;它不是实时 Patroni leader。已核查的 故障切换回调 不会更新 DNS。直连该地址的 PostgreSQL 端口仍具有静态节点语义。同一地址上的 HAProxy 角色端口可以路由到当前后端角色,但代理节点地址本身仍须可达。可达 VIP 或冗余代理入口才适合作为稳定发布目标;vip-manager 可以根据 DCS leader 移动 PG VIP。DNS 服务器冗余、服务目标正确和客户端重连成功需要分别验收;DNS 改变不会迁移已有 TCP 连接。

九个已审计配置路径存在保留区 PG VIP 冲突:demo/debian、demo/el、fat、ha/dual、ha/full、ha/octo、ha/safe、ha/simu、ha/trio。当前 pigsty.yml 另有 .2 冲突。build/dev 与 build/oss 需要明确宿主选择哪个 i.pigsty 入口;demo/demo 需要把 FQDN nodename 改为短 Barn 名。修改时同步调整所有依赖记录、URL 和连接设置。

候选 .100/.101/.102 在原始文本与 YAML 解码扫描中均为零字面命中,扫描范围为 54 个配置路径、当前 pigsty.yml 与 7 个角色默认值文件,共 62 个路径。这只支持在该审计语料内考虑这些地址,不代表 IPAM 预留,也没有检查 DHCP 租约、ARP、外部节点、动态表达式或实际网络。每个目标平台仍需验证 VIP 冲突与切换;放宽 Barn 保留地址校验不能解决网络冲突。

命名空间完整后,再升级为按域转发

默认保留现有 .pigsty。可选的新域建议使用范围更窄的 pigsty.test;.test 为测试保留,.pigsty 则没有特殊用途保留资格。不要使用属于 mDNS 的 .local。更换域名还须同步修改记录、portal URL 和证书,单改路由规则不能给应用改名。IANA 注册表、RFC 6761、RFC 6762

后缀转发不能解决当前短名。 /etc/resolver/pigsty 和 Linux 的 ~pigsty 都不会自动把裸 meta、pg-meta、pg-meta-1 送往 Pigsty。已审计的集群后缀默认为空,实例记录也没有后缀。启用路由前,须先发布对应的节点/实例 FQDN,并为集群显式设置 pg_dns_suffix,例如 .pigsty.test。默认保留有限的 hosts 别名兼容短名。安装 search domain 属于另一项显式选择,且只有补全后的 FQDN 确实存在才有效。本机高端口 daemon 也有完全相同的路由前提。systemd 路由域与搜索域

macOS 使用一个独立管理的 resolver 文件

拟议配置,尚未安装:

/private/etc/resolver/barn.pigsty.test
domain pigsty.test
nameserver 10.10.10.10
port 53

macOS 支持按域选择 resolver 和显式端口。只有省略 domain 时才以文件名作为域名,并按最长后缀匹配。本提案显式写域名,不自动增加 search list。已有同域路由或目标路径冲突时拒绝安装,包括 VPN 配置。只创建缺失且属于自己的文件/目录,使用适当的 root 所有权;备份与暂存内容放在 resolver 目录之外。使用 scutil --dns、dscacheutil 和系统 getaddrinfo() 验证生效。直接运行 dig @server 只能测试 DNS 服务,不能证明 macOS 原生路由正确。重初始化与缓存收敛时间须在目标系统版本验收。Apple resolver 手册、Apple configd 解析器

安装、修改入口和卸载需要特权;路由不变时,客机更新记录无需宿主特权。卸载只删除内容仍匹配的 Barn 文件,并验证路由已消失。保留 VPN/默认 resolver 及用户后续修改,不能恢复整份旧 DNS 配置。

Linux 必须识别实际解析链路及其所有者

检测过程只读:检查 resolved 是否运行、NSS hosts: 顺序、/etc/resolv.conf 指向,以及 NetworkManager 生效的 DNS plugin。若文件直接列出上游,部分客户端会绕过 resolved 的逐链路路由。仅有 NetworkManager 在运行,不能证明支持 split DNS。应探测版本和实际能力,而不是替用户切换整机 DNS 栈。resolved 客户端路径、NetworkManager 插件

拟议支持的适配器 持久安装与激活 卸载及限制
networkd + resolved,且链路归 Barn 独占 为已确认的 Barn .network 创建自有 drop-in:DNS=10.10.10.10、Domains=~pigsty.test、DNSDefaultRoute=no;只 reload/reconfigure 该链路 删除仍匹配的自有 drop-in,重读有效状态;保留其他文件与设置
NetworkManager + resolved 按 UUID 操作 Barn profile,设置 DNS 与 ipv4.dns-search=~pigsty.test,reapply 后核验 resolved 只恢复仍与已应用值匹配的自有属性;不删除共享 profile,不改全局 plugin
NetworkManager 已使用 dnsmasq plugin 利用 Barn profile 的条件转发;自定义端口另行探测 遵循相同的 profile 所有权规则;不自动启用新的全局 plugin
运行态 resolved 仅限活跃、Barn 独占的非 loopback 链路;明确提示不跨重启持久化 只有全部受影响配置都明确属于 Barn 时才可整链路 revert;共享/VPN/物理链路不适用
不支持的解析器或归属不明 说明缺失能力,继续使用 hosts/手工模式 不接管全局 nameserver 或 /etc/resolv.conf

绝不生成 ~.。DNSDefaultRoute=no 无法抵消覆盖所有域的路由。保留优先级和 DHCP/VPN 设置,不用 NetworkManager 负优先级抢占无关域。第一版客机转发以端口 53 为基线,不能把新版 resolved 的自定义端口语法直接复制到旧 NM profile。loopback 不是通用的 resolved 路由作用域,本机 daemon 必须使用受支持的路由机制。最后一台客机关闭后,barn0 可能失去 carrier 或链路本身,导致 DNS scope 失效,查询重新跟随默认路由。因此,严格保证私域不外泄,需要稳定路由、服务端否定响应策略和真机测试。networkd DNS 设置、NM 优先级与搜索域、resolvectl 重置范围、resolved 链路有效性

两个平台都需要放在部署状态之外、由 root 所有的变更日志,记录自有路径/profile UUID、原先是否存在、已应用值和元数据。先准备并验证上游 UDP/TCP 服务,再启用路由;写入前重新比较已审查配置,写入后验证原生解析。回滚只撤销仍归自己的变化;发现漂移或中断时报告部分状态。保存的 ifindex 不能作为跨重启的持久身份。从 hosts 切换时,显式移除重叠的 Barn 记录,并报告外部 hosts 覆盖。NM 的 profile 持久状态和运行态激活需要分别检查。nmcli 持久化与 reapply

常驻服务必须证明其维护成本值得承担

未来 daemon 应只绑定 loopback,优先使用受支持的高端口;仅接受目标用户提交的、有大小限制的记录;完整验证新一代数据后再原子激活,坏输入保留最后成功版本。固定的 root 服务/路由配置不能以 root 执行用户可修改的程序,也不能接受任意 include。安装、服务升级和路由变更仍需要特权。用户 agent 会在注销时退出,系统服务则增加安装和维护成本。须测试启动顺序、退避重启、端口占用及进程身份。主动卸载 daemon 时,应先撤路由并验证,再停止服务。崩溃应可诊断,不能静默把私域转发到公共上游。Apple 高端口实现

hosts 没有通配符行为。未来通配 DNS 只应覆盖明确共享入口的子域,不能笼统覆盖所有 Pigsty 名称。应为未知名称定义 NXDOMAIN,为缺少的记录类型定义 NODATA;dnsmasq 的域匹配与本地域策略需要仔细配置,并同时支持 UDP 和 TCP。AAAA 答案与查询 DNS 时使用的传输协议相互独立,不能编造不可达 IPv6 地址或 ::1。当前 Barn 导出仍限于 IPv4,双栈记录需要另定适配契约。dnsmasq 手册、RFC 3596、RFC 7766

系统、应用和否定缓存都可能保留旧结果;浏览器/SDK 的 DoH 可能绕过原生路由。已有 hosts 记录可能遮蔽 DNS,具体取决于 NSS 路径;VPN 会同时影响地址可达性和域路由选择。应测试这些路径,报告实测收敛情况,不承诺瞬间生效,也不在每次同步时清空全部缓存。DoH 客户端策略

现有证据支持原型,不等于完成平台验收

已记录的离线证据 结果及含义
Barn hosts/config/helper/CLI 测试 16 个顶层测试通过;覆盖临时文件写入与预览,包括损坏块、冲突、保留地址、helper 配对及无部署清单预览
Pigsty 提取器测试 11 项通过;应用子进程使用 mock,覆盖净化投影与预览行为
对抗性样例 21 项观察被复现,含 4 项 Ansible inventory 对照;它们揭示缺口,不是 21 项正确性测试通过
配置语料 54 个路径,包括符号链接别名;53 个通过 Barn VM 校验,42 个被提取器接受。解析器接受不代表角色等价或部署成功
实际原型预览 conf/meta.yml 生成 10 个名称,返回 applied: false;宿主原生 hosts 字节未变

对抗性证据发现了忽略 group_vars/host_vars、同级优先级不同、多行/转义换行导致地址错绑、发布已跳过的虚拟主机、遗漏外部角色及地址冲突检查不完整等问题,也暴露了混合视图歧义、无法表达多地址,以及显式 CIDR 目标被错误规范化。dns_enabled: false 时的 PG 别名应遵循前述明确的宿主便利策略,其存在本身不构成缺陷;静默错误地址,以及把这种结果声称为已部署 DNS 的等价输出,才是缺陷。

离线审查保留了样例、逐模板结果、执行命令和源码指纹。本文不复制私有配置或宿主 hosts 摘要。综合写作时,Barn DNS 相关文件仍与记录的指纹一致,尽管并发工作已将本地 HEAD 推进至 158786a1fee011edf3a1673400b8dd40ba9a7261;Pigsty 核查基线为 1ee6597dd806605b600e90cf01948277748b45f3。未发布证据位于 Barn 的 internal/hostconfig、internal/config、cmd/barn/hosts_inventory_test.go,以及 Pigsty 的 bin/sandbox-dns/tests/test_sandbox_dns.py。这些是文件路径,不代表公开基线链接中已经包含原型。

要用同一候选版本复现定向测试,先将 DNS_AUDIT_DIR 设置为仓库外一个已存在、可丢弃目录的绝对路径;以下命令用它存放全部缓存和状态。以下是 复现说明,不是本次文档综合新增执行的检查:

Barn 工作区——离线复现
export GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off GOENV=off GOWORK=off
export GOFLAGS=-mod=readonly
export GOCACHE="${DNS_AUDIT_DIR:?}/go-cache"
export GOTMPDIR="${DNS_AUDIT_DIR:?}/go-tmp" TMPDIR="${DNS_AUDIT_DIR:?}/tmp"
export BARN_HOME="${DNS_AUDIT_DIR:?}/barn-home"
mkdir -p "$GOCACHE" "$GOTMPDIR" "$TMPDIR" "$BARN_HOME"
go test -count=1 -v \
  -run '^(TestReconcile.*|TestApplyHelper.*|TestInstalledHelperValidation.*|TestCompanionHelperDigest.*|TestHelper.*|TestParseInventoryVMHosts.*|TestHostsInventoryPreviewNeedsNoDeployment)$' \
  ./internal/hostconfig ./internal/config ./cmd/barn-hosts-helper ./cmd/barn
Pigsty 工作区——离线复现
python3 -B -m unittest discover -s tests -p test_sandbox_dns.py -v

记录中的环境为 darwin/arm64 上的 Go 1.27.3、Python 3.14、PyYAML 6.0.3;inventory 对照使用 Ansible 2.21.5。模板统计的复现方法是排序枚举 conf/**/*.yml 路径,保留符号链接入口,逐个运行候选 Barn 的 validate --json,再调用相同提取器。发布前应把保存的对抗样例纳入仓库测试。本轮研究没有执行 sudo、系统配置修改、VM 操作或 playbook。真实 resolver 激活、VPN 行为、缓存时限和 HA 仍待验收;站点检查由主文档流程另行执行。

分阶段实施,每阶段设置明确门槛

阶段与负责人 实施清单 验收门槛
0——Pigsty 语义 拆分输出视图;修复静默解析/覆盖/虚拟主机错误;支持或拒绝外部角色;明确 CIDR 规则;修正保留区 VIP、多 infra 选择及 VM 身份 每个支持的静态 profile 都有经审查的预期记录和来源;不支持的输入明确失败;21 项对抗观察转成预期结果回归测试
1——Pigsty 导出器 + Barn hosts 受限字面导出;复用准确投影格式;来源标记保护与显式 applied 替换;完整离线差异;固定输入;结构化错误;helper 范围校验与协作锁 裸 install 不能丢失清单服务名;no-op 不需要 sudo;每次实际写入都复核;定向测试与仓库要求的检查通过
2——集成与 HA 共享纯规则/有效变量适配层;控制节点侧 rendered/observed 导出;生命周期诊断、迁移和重装清理;真实平台验证 按视图验证角色等价和支持 profile 的覆盖;macOS arm64、Linux amd64 的宿主访问与 VIP 切换通过,并扩展到其他承诺支持的宿主
3——可选 split DNS FQDN 发布、稳定入口、能力探测、所有权日志及平台适配器 后缀隔离、持久化、回滚和故障矩阵通过;短名保持明确约定
需求门槛——本机 daemon 衡量前述方案无法满足的更新频率或 RR 需求;定义服务身份与生命周期 收益足以承担服务维护;停服、注销、端口和升级测试通过
必须测试的领域 具体验收项目
语义 变量覆盖、同级组、默认值/模板、多行数据、portal 条件、PG 目标分支、MinIO 服务名来源、vm_skip、多 infra 与多地址拒绝
来源与文件安全 inventory → 裸命令拒绝;显式 applied 替换/删除;旧块迁移;大小写冲突、尾点、重复/损坏标记;块外编辑;状态缺失;崩溃/并发/过期计划与 helper 范围测试
幂等 重复快照;无关凭据/资源修改;代次漂移;仅来源种类变化的迁移;no-op 不请求 root;非交互权限失败
原生访问与 HA Portal Host/TLS 路由,节点/PG 短名与 FQDN,PG 直连端口与代理端口,VIP 可达性/切换,外部地址冲突,新旧连接差异
解析器集成 macOS 原生解析;Linux NSS/stub/绕行路径;UDP/TCP、A/AAAA/NODATA/NXDOMAIN、域顶点/子域、公共域/VPN 隔离及一致的上游视图
持久化与恢复 重启、注销、客机/DNS 停机、最后客机停止、接口重建、DHCP 更新、VPN 重连、缓存/DoH、部分应用、外部编辑、卸载与重装

为剩余产品选择给出默认答案

产品问题 推荐默认值
是否自动修改宿主? 否;由 Pigsty 显式预览/应用,生命周期只做诊断
选择什么视图/来源? 支持的 profile 默认使用 literal 期望 host-access;rendered/observed 是显式且有标签的替代来源,不推断部署权威性
多 infra 或外部入口怎么办? 拒绝歧义,明确选择入口/视图;网段外地址在另行设计能力前使用手工/已有 DNS
来源迁移与最低版本? 保留裸 legacy/applied 行为,保护 inventory 块;探测首个包含保护及配套 helper 的版本能力;不承诺安全降级
如何规范名称? ASCII 转小写后比较/输出;相同映射去重,冲突地址拒绝;存在节点规范名时将其放在行首。第一阶段拒绝尾点输入,并保守检测块外等价拼写,不接受静默归一化差异
命名空间与短名? 保留 .pigsty,新路由可选 pigsty.test;短别名显式写 hosts,不自动安装 search domain 或改名证书
权限与缓存策略? 按次 sudo,不授予持久权限,不自动清空全局缓存;先测收敛时间,再确定文档承诺
VIP 与服务生命周期? .100/.101/.102 仅为已审计模板的候选,须验证分配;停止/销毁保留名称,状态删除后仍能显式清理
通用导出器与 daemon 何时做? 先交付严格且有用的子集,通过逐视图等价门槛扩展;确认需求和维护归属后再做 daemon

表格阅读