external-dns · 集群 DNS 记录自动同步
external-dns 是集群的自动 DNS 管理组件:它持续监听 Kubernetes 里的 Ingress 和 Service 资源,把上面声明的主机名翻译成对应的 DNS 记录,再通过 Cloudflare API 写进托管的 zone —— 这样新增一个 Ingress 后,公网域名解析会自动跟上,不需要手工去 Cloudflare 后台加记录。它同时为每条记录写一条 TXT 所有权记录(--txt-owner-id=k3s-cluster),用于标记哪些记录是本集群管理的、避免误删非自己创建的记录。
external-dns 命名空间里,而不是 networking 命名空间。它只读集群资源、只写 Cloudflare,本身不承载任何流量。部署形态
- Name
- 命名空间
- Description
- external-dns(独立命名空间,由 manifest 自行创建)
- Name
- 工作负载类型
- Description
- Deployment,单副本,
strategy.type: Recreate(升级时先停旧 Pod 再起新 Pod,避免两个实例同时往 Cloudflare 写)
- Name
- 镜像与版本
- Description
- registry.k8s.io/external-dns/external-dns:v0.21.0,
imagePullPolicy: IfNotPresent
- Name
- 调度
- Description
nodeSelector: workload=infra,落在带 infra 标签的节点(当前为 worker3)
- Name
- 资源
- Description
- requests cpu 50m / memory 128Mi,limits cpu 100m / memory 256Mi
- Name
- 存储
- Description
- 无 PVC,无状态;命名空间的 ResourceQuota 也将 pods 上限设为 5,不申请任何持久卷
配置与依赖
external-dns 的全部行为由容器启动参数定义。它从 --source=ingress 和 --source=service 两类资源里发现要同步的主机名,--provider=cloudflare 指定后端,并用 --domain-filter 限定只管理三个域名:yldm.tech、yldm.ai、dunaifen.games。其中 dunaifen.games 承载 DNF 私服门户(game/dnf-backend 的 Ingress)。
为了消除同名 zone 的歧义,manifest 额外用 --zone-id-filter 把三个 zone 钉死到具体 zone ID:
| 域名 | Zone ID | 说明 |
|---|---|---|
| yldm.tech | 39ad6ae9a224f18eb09fc5200cb4714c | 新账户(Evan@yldm.tech)的 live zone |
| yldm.ai | 48174ca55af42b6125670a1adf7b5475 | 新账户的 live zone |
| dunaifen.games | 1b02ab7f154eef54ba53afbf824b575e | 旧账户(evan),保持不变 |
Cloudflare API token 不进 git,由 ExternalSecret cloudflare-api-token 从 Vault 拉取:secretStoreRef 指向 ClusterSecretStore vault-backend,remoteRef.key: external-dns/cloudflare、property: api-token,刷新间隔 1h,同步成名为 cloudflare-api-token 的 Secret,再以 CF_API_TOKEN 环境变量注入容器。
RBAC 方面,external-dns 用同名 ServiceAccount + ClusterRole:对 services / endpoints / pods / nodes / endpointslices 有 get/watch/list,对 extensions 与 networking.k8s.io 的 ingresses 有 get/watch/list —— 全部只读,符合它"只读集群、只写 Cloudflare"的角色。
访问与监控
external-dns 不暴露任何 Service、Ingress,也没有 ServiceMonitor / PrometheusRule / HPA / VPA / PDB。命名空间内只配了资源治理对象:ResourceQuota(pods 5、requests cpu 200m / memory 256Mi、limits cpu 500m / memory 512Mi)和 LimitRange(容器默认 requests 25m/64Mi、limits 100m/128Mi,并对 Container/Pod 设了 min/max 上下限)。kustomization 里曾有一组 NetworkPolicy(default-deny-ingress、allow-same-namespace、allow-kube-api-access、allow-dns-egress、allow-external-egress),目前已注释禁用(移到 .bak)。
注意事项
--zone-id-filter 这组参数是有来历的:yldm.tech 与 yldm.ai 现在同时存在于旧 "evan" 账户(已移走/失效)和新 "Evan@yldm.tech" 账户里。如果不用 zone ID 锁定,external-dns 会在同名 zone 之间随机挑一个,可能持续往那个失效的旧 zone 写记录,导致线上解析不更新。manifest 里列出的三个 ID 都是 live zone,改动这三行前务必确认。
dunaifen.games 这个 zone 要正常工作有两个前提:Vault 里的 cloudflare-api-token 必须包含该 zone 的 Zone:Read + DNS:Edit 权限;并且该域名要先在 Cloudflare 账户里完成接入(注册商处的 NS 指向 Cloudflare)。少任何一步,这个 zone 的记录就同步不上。