external-dns · 集群 DNS 记录自动同步

external-dns 是集群的自动 DNS 管理组件:它持续监听 Kubernetes 里的 Ingress 和 Service 资源,把上面声明的主机名翻译成对应的 DNS 记录,再通过 Cloudflare API 写进托管的 zone —— 这样新增一个 Ingress 后,公网域名解析会自动跟上,不需要手工去 Cloudflare 后台加记录。它同时为每条记录写一条 TXT 所有权记录(--txt-owner-id=k3s-cluster),用于标记哪些记录是本集群管理的、避免误删非自己创建的记录。

部署形态

  • 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.techyldm.aidunaifen.games。其中 dunaifen.games 承载 DNF 私服门户(game/dnf-backend 的 Ingress)。

为了消除同名 zone 的歧义,manifest 额外用 --zone-id-filter 把三个 zone 钉死到具体 zone ID:

域名Zone ID说明
yldm.tech39ad6ae9a224f18eb09fc5200cb4714c新账户(Evan@yldm.tech)的 live zone
yldm.ai48174ca55af42b6125670a1adf7b5475新账户的 live zone
dunaifen.games1b02ab7f154eef54ba53afbf824b575e旧账户(evan),保持不变

Cloudflare API token 不进 git,由 ExternalSecret cloudflare-api-token 从 Vault 拉取:secretStoreRef 指向 ClusterSecretStore vault-backendremoteRef.key: external-dns/cloudflareproperty: api-token,刷新间隔 1h,同步成名为 cloudflare-api-token 的 Secret,再以 CF_API_TOKEN 环境变量注入容器。

RBAC 方面,external-dns 用同名 ServiceAccount + ClusterRole:对 services / endpoints / pods / nodes / endpointslices 有 get/watch/list,对 extensionsnetworking.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.techyldm.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 的记录就同步不上。

评论