- 云原生
【免费下载链接】external-dns
Configure external DNS servers dynamically from Kubernetes resources
本篇指南聚焦 external-dns 的pod数据源(Source),讲解它如何将 KubernetesPod资源转换为 DNS 记录,涵盖--pod-source-domain默认域名机制、--ignore-non-host-network-pods过滤行为、基于注解(annotation)的 FQDN 解析,以及面向无 SNAT 本地集群的“全量 Pod + PTR 反解”实战配置组合。读完本文,你将掌握 pod source 的全部核心命令行参数、底层端点生成逻辑与可复用的部署方案。
什么是 Pod Source
Pod source 是 external-dns 内置的数据源之一,其职责是根据 KubernetesPod资源生成 DNS 记录。启用方式很简单,在 external-dns 启动参数中通过--source=pod指定:
./external-dns --source=pod --provider=...从源码结构看,pod source 的实现位于 source/pod.go,其中podSource结构体同时维护了 Pod 与 Node 两个 informer(source/pod.go)。Pod informer 负责读取 Pod 列表及其注解,Node informer 则在需要把记录解析到节点地址时使用。该 source 标注的能力维度(source/pod.go)包括:
- 资源类型:
Pod - 过滤方式:annotation、label
- 命名空间:支持 all(全部)与 single(单个)
- 支持 FQDN 模板(fqdn-template)、事件驱动(events)
- 不涉及 provider 特有逻辑(provider-specific=false)
也就是说,pod source 是纯粹的 Kubernetes 核心资源驱动型数据源,不依赖任何特定 DNS 厂商。
默认行为:仅考虑使用 host networking 的 Pod
Pod source 的默认行为有一个重要前提:只处理启用了 host networking(hostNetwork: true)的 Pod。这是因为 Pod 自身的 IP 在集群内部网络中往往不可被外部 DNS 直接引用,而 host networking 模式下 Pod 共享节点网络栈,其地址才具有集群外的可达性。
你可以通过--ignore-non-host-network-pods选项覆盖这一默认行为——加上该选项后,非 host networking 的 Pod 将被忽略。该参数在 pkg/apis/externaldns/types.go 中注册,默认值为false,完整定义见 docs/flags.md:
--[no-]ignore-non-host-network-pods Ignore pods not running on host network when using pod source (default: false)在实现层面,这个开关的判定逻辑位于addPodEndpointsToEndpointMap函数(source/pod.go):
if ps.ignoreNonHostNetworkPods && !pod.Spec.HostNetwork { log.Debugf("skipping pod %s. hostNetwork=false", pod.Name) return }即只有当ignoreNonHostNetworkPods=true且pod.Spec.HostNetwork=false时才跳过该 Pod,并输出skipping pod ... hostNetwork=false的调试日志。source/pod_test.go 中的测试用例(如"mixed valid and hostNetwork=false pods"、"when ignoreNonHostNetworkPods=false, no skip logs should be generated")验证了两种开关状态下的行为差异。
三种行为模式对比
| 配置 | hostNetwork=true 的 Pod | hostNetwork=false 的 Pod |
|---|---|---|
| 默认(不加任何选项) | 被处理 | 被处理 |
--ignore-non-host-network-pods | 被处理 | 被忽略(产生 skip 日志) |
为 Pod 指定 FQDN 的三种途径
Pod source 生成 DNS 记录时,目标域名(FQDN)可以来自三个互不冲突的来源,最终端点会通过endpoint.MergeEndpoints合并去重(source/pod.go):
注解(annotation):默认情况下,pod source 从 Pod 注解中查找关联的 FQDN,相关注解键定义于 source/annotations/annotations.go:
external-dns.alpha.kubernetes.io/hostname:为该 Pod 注册指定主机名。若未设置target注解,记录将解析到该 Pod 所在节点的地址(见下文“节点地址解析”);若设置了target注解,则解析到 target 指定的地址。external-dns.alpha.kubernetes.io/internal-hostname:注册内部主机名,默认解析到 Pod 自身的 IP(pod.Status.PodIP)。external-dns.alpha.kubernetes.io/target:显式指定记录的目标地址(可多个,逗号分隔)。external-dns.alpha.kubernetes.io/ttl:指定记录 TTL。 注解整体说明可参考 docs/annotations/annotations.md。
--pod-source-domain默认域名:为所有 Pod 统一生成 FQDN(见下一节)。FQDN 模板(fqdn-template):通过模板引擎批量生成,对应
podSource.templateEngine(source/pod.go),支持{{.Name}}等占位符。
节点地址解析规则
当使用hostname注解且未指定target时,记录解析到节点地址。addPodNodeEndpointsToEndpointMap(source/pod.go)通过 Node informer 读取pod.Spec.NodeName对应节点,遍历node.Status.Addresses,遵循如下规则:
NodeExternalIP类型的地址直接采用;NodeInternalIP类型的地址仅在记录类型为 AAAA(IPv6)时采用——源码注释解释了原因:IPv6 地址虽被标记为 NodeInternalIP,但同样可被外部使用(source/pod.go)。
记录类型由endpoint.SuitableType(address)根据地址是 IPv4(A)还是 IPv6(AAAA)自动判定。
使用默认域名:--pod-source-domain
默认情况下 pod source 依赖 Pod 注解来发现 FQDN,这对于大规模、无需逐个打注解的场景并不友好。此时可以使用--pod-source-domain选项,为所有 Pod 自动构建 FQDN。
例如启动参数:
./external-dns --source=pod --pod-source-domain=example.org名为test-pod的 Pod 会被注册为test-pod.example.org。该选项注册于 pkg/apis/externaldns/types.go,默认值为空字符串,完整定义见 docs/flags.md:
--pod-source-domain="" Domain to use for pods records (optional)其底层实现位于addPodSourceDomainEndpoints(source/pod.go),核心逻辑即为字符串拼接:
domain := pod.Name + "." + ps.podSourceDomain在未设置target注解时,<podName>.<podSourceDomain>解析到 Pod 自身的 IP(pod.Status.PodIP),记录类型根据 IP 版本自动判定;若 Pod 带有target注解,则优先解析到注解指定的目标地址。
值得注意的一个细节:--pod-source-domain与注解机制可以同时生效。addPodEndpointsToEndpointMap中依次处理 internal-hostname、hostname、kops 兼容注解与 pod-source-domain 四类端点(source/pod.go),最终所有记录都会被合并输出,因此同一个 Pod 可以同时拥有注解定义的 FQDN 与默认域名生成的 FQDN。
实战场景:全量注册 Pod 及其 PTR 记录
文档 docs/sources/pod.md 给出了一个将这些选项组合使用的典型场景:
当你在本地(on-premise)Kubernetes 集群中运行,且 Pod 网络未启用 SNAT时,外部流量到达集群后无法通过 Pod IP 快速回溯到对应工作负载。此时可以把所有 Pod 连同其 PTR 记录一起注册到 DNS,使集群外的流量来源可以通过
nslookup或dig命令对 Pod IP 做反向解析,迅速定位到对应的工作负载。这在运行大量 Kubernetes 集群时尤其有用。
反向解析(PTR)的原理:Pod IP 形如10.0.0.5,其 PTR 记录位于5.0.0.10.in-addr.arpa。因此要让全部 Pod 支持反解,需要同时把正向域名与反向 in-addr.arpa 域名都纳入 DNS 管辖。完整配置组合如下:
./external-dns \ --domain-filter=example.org \ --domain-filter=10.0.0.in-addr.arpa \ --source=pod \ --pod-source-domain=example.org \ --create-ptr \ --rfc2136-zone=example.org \ --rfc2136-zone=10.0.0.in-addr.arpa各参数职责拆解
| 参数 | 作用 |
|---|---|
--domain-filter=example.org | 只管理example.org域下的记录,过滤掉无关域名 |
--domain-filter=10.0.0.in-addr.arpa | 同时管理10.0.0.0/24网段对应的反向查询域 |
--source=pod | 启用 pod source |
--pod-source-domain=example.org | 为每个 Pod 生成<podName>.example.org正向记录 |
--create-ptr | 为每条记录同时创建对应的 PTR 反向记录 |
--rfc2136-zone=example.org | 指定正向记录写入的 RFC2136(BIND 等)DNS 区域 |
--rfc2136-zone=10.0.0.in-addr.arpa | 指定反向 PTR 记录写入的反向区域 |
其中--create-ptr与--rfc2136-zone属于 rfc2136 provider 的能力:--create-ptr让 external-dns 在生成 A/AAAA 记录的同时派生 PTR 记录,而重复声明两个--rfc2136-zone则保证正向与反向记录被正确路由到对应的 zone 文件。有关 rfc2136 provider 的部署细节可参考 docs/tutorials/rfc2136.md 与 docs/advanced/ptr-records.md。
运行效果示意
假设集群中有名为web-0、Pod IP 为10.0.0.5的 Pod,上述配置生效后 DNS 中会同时出现:
- 正向记录:
web-0.example.org. A 10.0.0.5 - 反向记录:
5.0.0.10.in-addr.arpa. PTR web-0.example.org.
此时在集群外执行:
nslookup 10.0.0.5 dig -x 10.0.0.5即可将来源 IP 反解为具体的工作负载名,快速完成流量溯源。
从源码看端点的生成链路
理解 pod source 的完整工作流有助于排障与二次开发,其核心链路如下(source/pod.go):
启动阶段:
NewPodSource创建共享 informer factory,注册 Pod 与 Node informer,并为 Pod informer 挂载注解过滤器(IndexSelectorWithAnnotationFilter)、标签选择器(IndexSelectorWithLabelSelector)与控制器匹配条件(IndexSelectorWithConditions),同时注册事件处理器,等待本地缓存同步完成后返回podSource(source/pod.go)。端点收集阶段:
Endpoints从 informer indexer 中列出全部 Pod,对每个 Pod 依次执行:endpointsFromPodAnnotations:解析 Pod 注解(internal-hostname / hostname / kops 兼容注解 / pod-source-domain)生成端点(source/pod.go);templateEngine.ApplyFQDNTargetTemplate:应用 FQDN/目标模板;templateEngine.CombineWithEndpoints:合并模板生成的端点;endpoint.AttachRefObject:为端点附加对象引用,供事件系统使用(source/pod.go)。
合并去重:
endpoint.MergeEndpoints汇总所有 Pod 的端点,交由后续 plan/registry/provider 阶段处理。
在生成端点时,TTL 统一通过annotations.TTLFromAnnotations(pod.Annotations, fmt.Sprintf("pod/%s", pod.Name))从注解读取(source/pod.go),未设置时采用 provider 的默认 TTL。
此外,pod source 还保留了对kops-dns-controller兼容模式的支持:当--compatibility=kops-dns-controller时,会额外读取 kops 风格的 hostname 注解并生成对应记录(source/pod.go)。
小结与验证建议
Pod source 是 external-dns 中唯一直接以工作负载资源(而非负载均衡/路由资源)为驱动的核心数据源,适用于需要为每个 Pod 建立可解析身份的场景。使用时把握三条主线即可:
- 过滤:用
--ignore-non-host-network-pods控制是否只关注 host networking Pod; - 命名:注解(
external-dns.alpha.kubernetes.io/hostname/internal-hostname)逐 Pod 定制,--pod-source-domain全局兜底; - 组合:结合
--create-ptr与反向 zone 实现 Pod IP 的反向溯源。
如需验证行为,可直接运行仓库中的单元测试,例如 source/pod_test.go 的TestPodSource覆盖了注解解析、节点地址解析、ignoreNonHostNetworkPods跳过逻辑与 skip 日志输出;pkg/apis/externaldns/types_test.go 则验证了--ignore-non-host-network-pods与--pod-source-domain=example.org等命令行参数的解析。建议在测试环境先用 inmemory provider(--provider=inmemory)验证生成的记录集合,再切换到真实 DNS provider。
- 云原生
【免费下载链接】external-dns
Configure external DNS servers dynamically from Kubernetes resources
相关推荐
微信聊天记录永久保存:3步打造你的数字记忆保险箱
微信聊天记录永久保存:3步打造你的数字记忆保险箱 你是否曾因手机丢失、系统升级或误操作而丢失珍贵的微信聊天记录?那些与家人的温馨对话、朋友的重要约定、工作的关键
云原生终极界面字体解决方案:Source Sans 3 专业使用指南
终极界面字体解决方案:Source Sans 3 专业使用指南 还在为现代用户界面字体选择而烦恼吗?面对琳琅满目的字体库,你是否曾因字体渲染不清晰、字重选择有限
云原生构建专属数字人交互平台:从零到一的轻量化实现方案
构建专属数字人交互平台:从零到一的轻量化实现方案 你是否曾想过拥有一个能与用户实时对话、表情生动的数字人助手?在AI技术快速发展的今天,打造个性化的数字人交互平
云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考