- 云原生
【免费下载链接】external-dns
Configure external DNS servers dynamically from Kubernetes resources
本指南讲解如何在 Kubernetes 集群中让 ExternalDNS 以 F5 Networks 的VirtualServer自定义资源(CRD)为数据源,自动把虚拟服务器的域名与地址同步到 DNS 提供商。读完本文,你将掌握--source=f5-virtualserver的启用方式与 RBAC 配置、spec.host/spec.hostAliases/spec.virtualServerAddress/status.vsAddress的取值逻辑、目标(Target)优先级与 TTL 注解,以及基于注解/标签过滤和 FQDN 模板(fqdn-template)的进阶用法。
背景:F5 VirtualServer 是什么
VirtualServer是 k8s-bigip-ctlr 项目定义的 CRD,用于描述 F5 BIG-IP 上的虚拟服务器:它声明一个对外提供服务的host域名、绑定的后端服务(Pool)以及 BIG-IP 上监听该服务的虚拟服务器地址。ExternalDNS 把这类 CRD 当作一种"负载均衡器"类型的源(在源码注释中标注为category=Load Balancers),从中提取 DNS 记录并交给所选 provider 去发布,从而实现"F5 虚拟服务器 → DNS 记录"的全自动同步。
说明:
VirtualServerCRD 由 k8s-bigip-ctlr 随控制器一并下发,CRD 的完整字段定义以该项目文档为准;本文只聚焦 ExternalDNS 从这些字段中读取并生成 DNS 记录的行为。
一、启用 F5 VirtualServer 源
1. 前置条件
在把该源接入 ExternalDNS 之前,需要保证集群中已安装k8s-bigip-ctlr控制器,因为VirtualServer所需的 CRD 就捆绑在控制器中(apiVersion: cis.f5.com/v1、kind: VirtualServer)。ExternalDNS 通过动态客户端(dynamic client)监听该 GVR——source/f5_virtualserver.go 中声明的 GVR 为:
var f5VirtualServerGVR = schema.GroupVersionResource{ Group: "cis.f5.com", Version: "v1", Resource: "virtualservers", }2. 通过 Helm 启用
在 ExternalDNS 的 Helmvalues.yaml中,把f5-virtualserver追加到sources列表:
sources: - ... - f5-virtualserver - ...3. 通过 Deployment 参数启用
如果不使用 Helm,直接在 Deployment 的容器args中追加参数:
args: - --source=f5-virtualserver该值对应 source/types/types.go 中定义的源类型名F5VirtualServer = "f5-virtualserver",并由 source/store.go 分派到buildF5VirtualServerSource,最终调用NewF5VirtualServerSource构建源实例(见 source/store.go)。
4. RBAC 授权
不以 Helm 安装时,需要为 ExternalDNS 的 ServiceAccount 所绑定的ClusterRole增加对virtualservers资源的读取权限,否则源无法list/watch到 CR 对象:
- apiGroups: - cis.f5.com resources: - virtualservers verbs: - get - list - watch从源码看,源使用动态 informer 监听virtualservers,并在启动时通过WaitForDynamicCacheSync等待本地缓存就绪(source/f5_virtualserver.go),因此上述list/watch权限是运行的基本前提。
二、工作原理:从哪些字段生成 DNS 记录
f5VirtualServerSource实现Source接口(Endpoints、AddEventHandler等)。每次同步时,它遍历命名空间内所有VirtualServer对象,将其转换为f5.VirtualServer结构体后按以下字段生成 Endpoint(source/f5_virtualserver.go):
| 字段 | 作用 |
|---|---|
spec.host | 虚拟服务器的主域名,生成一条主 DNS 记录 |
spec.hostAliases | 附加域名列表,每个非空别名生成一条指向相同目标的记录 |
spec.virtualServerAddress | 虚拟服务器 IP(BIG-IP 上监听地址),作为目标 IP |
status.vsAddress | 控制器回写的虚拟服务器地址,作为目标 IP 的兜底来源 |
对应地,Endpoint 的DNSName取自spec.host与spec.hostAliases中的每个非空条目,Targets按下述优先级解析,RecordType固定为 A 记录(测试用例中均断言RecordTypeA,见 source/f5_virtualserver_test.go)。
示例:带 hostAliases 的 VirtualServer
apiVersion: cis.f5.com/v1 kind: VirtualServer metadata: name: example-vs namespace: default spec: host: www.example.com hostAliases: - alias1.example.com - alias2.example.com virtualServerAddress: 192.168.1.100该配置将生成三条 DNS A 记录:
www.example.com→192.168.1.100alias1.example.com→192.168.1.100alias2.example.com→192.168.1.100
对应源码中的处理逻辑:先为spec.host调用EndpointsForHostname生成主记录,再遍历spec.HostAliases,对每个非空别名追加一条记录(source/f5_virtualserver.go);别名含空字符串时会被跳过(测试用例 "F5 VirtualServer with hostAliases containing empty strings" 验证了这一点,见 source/f5_virtualserver_test.go)。
三、目标(Target)解析优先级
当spec.host/spec.hostAliases有值、且虚拟服务器具有有效 IP 时,目标按以下优先级确定(source/f5_virtualserver.go):
- target 注解
external-dns.kubernetes.io/target:优先级最高,注解值直接作为目标; - spec 地址
spec.virtualServerAddress:未设置注解时使用; - status 地址
status.vsAddress:注解与 spec 地址均缺失时使用。
若三者都不可用,该VirtualServer会被跳过,并输出日志F5 VirtualServer <ns>/<name> is missing a valid IP address, skipping endpoint creation.(source/f5_virtualserver.go)。
"有效 IP"的判断细节
hasValidVirtualServerIP会把status.vsAddress转为小写后与"none"、""比较(source/f5_virtualserver.go),因此:
- 当
status.vsAddress为"None"(k8s-bigip-ctlr 在未分配地址时的回写值)或空字符串时,视为无有效 IP,即使spec.host存在也不生成记录——测试用例 "F5 VirtualServer with missing IP address and OK status"(VSAddress: "None",期望结果为nil)即验证了这一点(source/f5_virtualserver_test.go); - 目标解析只发生在
hasValidVirtualServerIP为真之后。注意:判断依据是status.vsAddress是否为有效值,而实际使用的目标仍按上文优先级取 target 注解 →spec.virtualServerAddress→status.vsAddress; status.Status为"ERROR"时只要存在有效 IP,记录仍会生成(测试用例 "F5 VirtualServer with error status but valid IP" 验证,见 source/f5_virtualserver_test.go)。
四、TTL 支持
可以为单个VirtualServer自定义 DNS 记录 TTL(秒),在metadata.annotations中设置:
metadata: name: example-vs namespace: default annotations: external-dns.kubernetes.io/ttl: "300"源码通过annotations.TTLFromAnnotations读取该注解并应用到该对象生成的所有 Endpoint(source/f5_virtualserver.go)。测试用例 "F5 VirtualServer TTL annotation" 使用external-dns.kubernetes.io/ttl: "600"并断言生成的记录RecordTTL: 600(见 source/f5_virtualserver_test.go);"F5 VirtualServer with hostAliases and TTL annotation" 则验证了 TTL 会同时作用于主域名与全部别名(source/f5_virtualserver_test.go)。未设置时RecordTTL为 0,表示由 provider 侧使用默认 TTL。
五、注解过滤与标签过滤
你可以通过--annotation-filter只处理带特定注解的VirtualServer:
--annotation-filter=foo=bar也可以配合--label-filter按资源标签过滤。过滤并非在 Endpoints 生成后才进行,而是在 informer 建立索引(Indexer)时就生效:NewF5VirtualServerSource为 informer 注册了三个索引器(source/f5_virtualserver.go):
informers.MustAddIndexers(virtualServerInformer.Informer(), informers.IndexerWithOptions*unstructured.Unstructured, informers.IndexSelectorWithLabelSelector(cfg.LabelFilter), informers.IndexSelectorWithConditions(annotations.IsControllerMatch[*unstructured.Unstructured]), ))对应测试:
- 注解过滤命中(
foo=bar匹配)时生成记录,未命中时结果为nil(见 source/f5_virtualserver_test.go); - 标签过滤命中/未命中同样有完整用例(source/f5_virtualserver_test.go);
- 索引器测试覆盖"注解 + 标签组合过滤"以及"controller 注解不匹配时被排除"(source/f5_virtualserver_test.go)。
注:控制器注解
external-dns.kubernetes.io/controller由annotations.IsControllerMatch统一处理,用于多控制器共存时按--controller-id归属资源,行为与其他源一致。
六、结合 FQDN 模板(fqdn-template)的进阶用法
f5-virtualserver源支持 ExternalDNS 的模板机制(+externaldns:source:fqdn-template=true),通过--fqdn-template、--target-template与--fqdn-target-template在无有效 IP 时也能生成记录,或为已有记录追加模板记录。模板引擎对每个VirtualServer应用模板(source/f5_virtualserver.go),测试见 source/f5_virtualserver_fqdn_test.go。
6.1 无有效 IP 时生成 CNAME
当status.vsAddress为空、且存在--fqdn-template与--target-template时,可基于对象元数据生成记录,例如:
--fqdn-template={{.Name}}.example.com --target-template=lb.example.com测试用例验证:my-vs对象(无 IP)将生成my-vs.example.com→lb.example.com(CNAME)记录(source/f5_virtualserver_fqdn_test.go)。
6.2 无有效 IP 时生成 A 记录
--fqdn-target-template格式为域名:目标,可为无 IP 的对象生成 A 记录:
--fqdn-target-template={{.Name}}.example.com:1.2.3.4对应测试生成my-vs.example.com→1.2.3.4(A 记录)(source/f5_virtualserver_fqdn_test.go)。
6.3 模板可引用的字段
模板上下文是完整的VirtualServer对象(含 TypeMeta),因此除.Name、.Namespace外还可引用.Kind、.APIVersion等。测试中有两个示例:
{{.Kind | toLower}}.{{.Name}}.example.com→virtualserver.my-vs.example.com(source/f5_virtualserver_fqdn_test.go);{{.Name}}.{{replace "/" "." .APIVersion}}.example.com→my-vs.cis.f5.com.v1.example.com(source/f5_virtualserver_fqdn_test.go)。
6.4 与基于 IP 的记录共存(combine)
开启--combine-fqdn-template(或--combine-fqdn-target-template)后,模板生成的记录会与基于 IP 生成的记录同时保留:
- 测试 "fqdn-template with combine adds template endpoint alongside IP-based endpoint" 验证:
my-vs.example.com(CNAME)与www.example.com(A)同时存在(source/f5_virtualserver_fqdn_test.go); - 未开启 combine 时,只要存在基于 IP 的记录,模板生成的记录会被忽略(source/f5_virtualserver_fqdn_test.go);
- combine 同样适用于 hostAliases 场景,别名记录与模板记录可并存(source/f5_virtualserver_fqdn_test.go)。
七、记录合并与事件关联
源在返回 Endpoint 前会调用endpoint.MergeEndpoints合并同名记录,并调用endpoint.AttachRefObject为每个 Endpoint 附加所属资源引用(events.NewObjectReference(virtualServer, types.F5VirtualServer)),对应测试断言中的resource标签格式为f5-virtualserver/<namespace>/<name>(例如f5-virtualserver/virtualserver/test-vs,见 source/f5_virtualserver_test.go)。这些引用信息在资源删除时可被 registry 用于准确清理对应 DNS 记录。
八、完整接线一览
- 源注册:
--source=f5-virtualserver→ source/store.go 分派 →buildF5VirtualServerSource(source/store.go)→NewF5VirtualServerSource(source/f5_virtualserver.go); - 记录生成:
Endpoints→ 遍历 informer 索引结果 → 按 source/f5_virtualserver.go 的endpointsFromVirtualServers生成并合并 Endpoint; - 行为验证:表驱动测试覆盖目标优先级、TTL、注解/标签过滤、无效 IP 跳过、hostAliases 等全部路径(source/f5_virtualserver_test.go),模板相关行为见 source/f5_virtualserver_fqdn_test.go。
常见问题
- VirtualServer 存在但没有任何 DNS 记录被创建:最常见原因是
status.vsAddress为空或为"None"且未配置 target 注解/spec.virtualServerAddress。可先检查 BIG-IP 控制器是否已将地址回写到 status;若确认不需要 IP 目标,可改用 fqdn-template 或 target-template 生成记录。 --annotation-filter生效但某台服务器仍被处理:确认注解键值拼写完全一致(如foo=bar),并注意该过滤器在 informer 索引阶段即生效,修改过滤条件后需要 ExternalDNS 重建索引(通常表现为重启后生效)。- 是否需要额外 RBAC:除
cis.f5.com/virtualservers的get/list/watch外,无需为该源配置其他资源权限;若使用了 fqdn-template,也无需额外权限,因为模板只消费已 watch 到的对象元数据。
- 云原生
【免费下载链接】external-dns
Configure external DNS servers dynamically from Kubernetes resources
相关推荐
7种场景下的ComfyUI-Custom-Scripts深度解析:掌握AI绘画工作流增强的3层架构方案
7种场景下的ComfyUI Custom Scripts深度解析:掌握AI绘画工作流增强的3层架构方案 ComfyUI Custom Scripts是一个专注于
云原生3个核心技巧:如何让智能家居能耗计算更精准?
3个核心技巧:如何让智能家居能耗计算更精准? 你是否好奇家中智能设备的真实能耗?是否曾疑惑为什么智能灯在调暗时耗电没有明显减少?智能家居的能耗监控一直是技术爱好
云原生Bebas Neue 免费商用标题字体:安装、字重、排版一次讲透
Bebas Neue 免费商用标题字体:安装、字重、排版一次讲透 找标题字体翻遍免费库,是不是总差点意思?Bebas Neue 字体免费商用,是专为标题而生的无
云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考