ExternalDNS 与 AWS Load Balancer Controller 集成实战:ALB/NLB Ingress 的 DNS 自动化管理
云原生【免费下载链接】external-dnsConfigure external DNS servers dynamically from Kubernetes resources项目地址https://gitcode.com/gh_mirrors/ex/external-dns点击查看免费下载ExternalDNS 与 AWS Load Balancer Controller原 ALB Ingress Controller的集成是 Kubernetes 集群中让 ALB/NLB 等 AWS 负载均衡器自动接入 Route53 域名解析的标准实践。本文以 docs/tutorials/aws-load-balancer-controller.md 为骨架结合本仓库源码系统讲解环境搭建、Ingress 示例、双栈Dualstack负载均衡、前端 NLB 及已知问题的规避方案帮助你掌握从部署 echoserver 应用到为多个域名创建 ALIAS 记录的完整链路并能处理内部 ALB 与前端 NLB 并存时的 DNS 指向问题。环境准备ExternalDNS 与 AWS Load Balancer Controller 的部署1. 先决条件完成 AWS 基础教程在开始本教程之前需要先完成 AWS 教程 中的基础设置确保 ExternalDNS 能够在 EKS 集群中运行并访问 Route53。该教程覆盖了IAM Policy 创建为 ExternalDNS 授予route53:ChangeResourceRecordSets、route53:ListResourceRecordSets、route53:ListTagsForResources、route53:ListHostedZones等权限集群与权限绑定提供 Node IAM Role、静态凭据、IRSAIAM Roles for Service Accounts、EKS Pod Identity 等四种凭据注入方式托管区域Hosted Zone创建例如为example.com创建 Route53 zone并记录对应的 nameserversExternalDNS 部署通过 Helm 或原生 Deployment 清单--provideraws、--registrytxt、--txt-owner-idmy-hostedzone-identifier等参数完成部署。[!NOTE] 本文示例默认使用--sourceingress参数使 ExternalDNS 从 Ingress 对象的spec.rules[].host字段提取主机名。该参数在 pkg/apis/externaldns/types.go 中定义Ingress 源的具体实现位于 source/ingress.go。2. ExternalDNS 侧的关键参数在 AWS ALB 场景下ExternalDNS 的参数配置要点如下参数说明推荐值/默认值--sourceingress将 Ingress 作为 DNS 记录的来源必选--provideraws指定 AWS Route53 provider必选--domain-filterexample.com只处理匹配后缀的托管区域按需--policyupsert-only只增不改不删防止误删记录生产推荐--policysync才会删除记录--registrytxt使用 TXT 记录记录所有权ownership信息推荐--txt-owner-idmy-hostedzone-identifierTXT 记录的 owner 标识必须唯一--aws-zone-typepublic仅处理公有托管区域public/private/ 不设置两者都处理--exclude-record-typesAAAA禁止创建 AAAA 记录详见下文双栈章节可选此外如果你希望只让 ExternalDNS 处理特定ingressClassName的 Ingress可以通过--ingress-classalb参数注意这与 AWS Load Balancer Controller 自身的--ingress-classalb参数是两码事或--ingress-class-names参数进行过滤。从 source/ingress.go 的源码可以看到Ingress 源会通过ingressClassNames列表筛选匹配的 Ingress 对象未匹配的会被记录 Debug 日志后丢弃。3. AWS Load Balancer Controller 侧的前提AWS Load Balancer Controller 的安装请参考其官方 Setup Guide。在本文的示例中假设你已为它配置了--ingress-classalb参数这样控制器只会处理spec.ingressClassName字段为alb的 Ingress 对象注意区分这是 AWS 控制器的参数不是 ExternalDNS 的--ingress-class。另外一个容易踩坑的细节AWS Load Balancer Controller 使用与 Kubernetes AWS 云提供商相同的子网自动发现标签subnet auto-discovery。这意味着如果你在 EKS 之外自建集群需要确保 VPC 子网带有正确的标签例如kubernetes.io/cluster/cluster-name: shared和kubernetes.io/role/elb: 1否则控制器无法为 ALB 分配子网。部署一个示例应用echoserver创建以下 echoserver 示例应用用于演示 ExternalDNS 与 ALB Ingress 的协同工作apiVersion: apps/v1 kind: Deployment metadata: name: echoserver spec: replicas: 1 selector: matchLabels: app: echoserver template: metadata: labels: app: echoserver spec: containers: - image: gcr.io/google_containers/echoserver:1.4 imagePullPolicy: Always name: echoserver ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: echoserver spec: ports: - port: 80 targetPort: 8080 protocol: TCP type: NodePort selector: app: echoserver[!NOTE] Service 的类型是NodePort而非LoadBalancer。因为我们使用 Ingress 来创建 ALB并不需要一个额外的LoadBalancerService —— 如果同时创建会在 AWS 上多出一个多余的 ELB白白产生费用。Ingress 示例从 Host 规则到 ALIAS 记录1. 基于host规则创建 ALB创建下面的 Ingress将 echoserver 暴露到公网apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/scheme: internet-facing name: echoserver spec: ingressClassName: alb rules: - host: echoserver.mycluster.example.org http: echoserver_root paths: - path: / backend: service: name: echoserver port: number: 80 pathType: Prefix - host: echoserver.example.org http: *echoserver_root部署后AWS 会创建一个IPv4 的 ALB并将流量转发到 echoserver。此时如果 ExternalDNS 使用--sourceingress它会根据 Ingress 规则中的 host 字段创建 DNS 记录对echoserver.mycluster.example.org和echoserver.example.org两个域名各创建一条 A 和一条 AAAA ALIAS 记录共 4 条全部指向与该 Ingress 关联的 ALB由于 ALB 是 IPv4-only 的AAAA 记录实际上不会生效但对解析无害。这段逻辑对应 source/ingress.go 中的endpoints构建过程Ingress 源会先提取rule.Host列表再结合从 Ingress StatusALB 的 hostname或target注解解析出的 targets调用endpoint.EndpointsForHostname生成包含 A/AAAA 记录的 Endpoint 集合。2. 禁止创建 AAAA 记录如果你希望 ExternalDNS 完全不创建 AAAA 记录可以添加命令行参数--exclude-record-typesAAAA该参数在 pkg/apis/externaldns/types.go 中定义为--exclude-record-types可多次指定例如--exclude-record-typesTXT等其校验与默认值见 internal/config/config.go实际过滤逻辑在 controller/controller.go 中通过ExcludeRecordTypes字段传递给执行层controller/execute.go。[!WARNING] 请注意这个参数是全局生效的即使负载均衡器启用了 dualstack双栈能力也会一并禁止 AAAA 记录的创建。如果你的 ALB 是 IPv4-only推荐加上该参数以保持 DNS 区域干净。3. 利用 YAML anchor 与hostname注解上面的例子使用了 YAML anchorechoserver_root/*echoserver_root避免多个 host 重复书写相同的 http 段。如果这个 Ingress 只服务一个后端 Service还可以用更简洁的写法——通过external-dns.kubernetes.io/hostname注解直接指定多个域名apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/scheme: internet-facing external-dns.kubernetes.io/hostname: echoserver.mycluster.example.org, echoserver.example.org name: echoserver spec: ingressClassName: alb rules: - http: paths: - path: / backend: service: name: echoserver port: number: 80 pathType: Prefix这里创建了一个适用于任何主机名的默认路径并通过external-dns.kubernetes.io/hostname注解为产生的 ALB 创建多个别名记录。从源码看source/annotations/annotations.go 中定义了注解前缀external-dns.kubernetes.io/旧版本为external-dns.alpha.kubernetes.io/而 source/annotations/processors.go 中的HostnamesFromAnnotations负责把逗号分隔的主机名拆成列表SplitHostnameAnnotation会先移除空格再按逗号切分。在 source/ingress.go 中注解主机名会被合并进最终端点列表并根据external-dns.kubernetes.io/ingress-hostname-source注解可选决定只使用注解主机名annotation-only还是只使用 Ingress 规则中定义的主机名defined-hosts-only。双栈Dualstack负载均衡器AWS 同时支持 IPv4 与 dualstack同时提供 IPv4 和 IPv6两种接口的 ALB 与 NLB。AWS Load Balancer Controller 通过alb.ingress.kubernetes.io/ip-address-type注解决定地址类型默认值为ipv4。无论该注解取何值ExternalDNS 默认都会同时创建 A 和 AAAA 两条 ALIAS 记录。若只想创建 A 记录使用参数--exclude-record-typesAAAA。双栈示例apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/ip-address-type: dualstack name: echoserver spec: ingressClassName: alb rules: - host: echoserver.example.org http: paths: - path: / backend: service: name: echoserver port: number: 80 pathType: Prefix上面的 Ingress 会创建一个具有 dualstack 接口的 ALB此时 A 与 AAAA 记录都能真正生效。提示在 AWS 教程 中还可以看到Route53 对非双栈负载均衡器创建 AAAA 记录时返回空结果集这样的记录是无害的IPv4 解析照常工作。这也解释了为什么默认同时创建 A/AAAA不会破坏 IPv4-only 场景。前端网络负载均衡器NLB及其已知问题AWS Load Balancer Controller 支持用 NLB 作为 ALB 的前端frontend NLB以获得更好的性能和静态 IP 地址。启用该特性后控制器会同时创建一个 ALB 和一个 NLB导致 Ingress Status 中出现两个 hostname。已知问题内部 ALB 与前端 NLB当使用内部 ALBalb.ingress.kubernetes.io/scheme: internal配合 frontend NLB 时ExternalDNS 可能因为字母排序而把 DNS 记录指向 ALB 而不是 NLB。原因如下内部 ALB hostname 形如internal-k8s-myapp-alb.us-east-1.elb.amazonaws.comNLB hostname 形如k8s-myapp-nlb-123456789.elb.us-east-1.amazonaws.com当存在多个目标时Route53 会按字母顺序选择第一个而internal-...前缀在字母顺序上排在前面因此错误地选中了内部 ALB。相关细节见 issue #5661。从 source/ingress.go 的targetsFromIngressStatus可以看到Ingress 源会把status.loadBalancer.ingress[]中的全部 hostname 都收集为 targets再为每个 hostname 生成端点当 ALB 与 NLB 同时出现在 Status 中时两个目标都会被使用这正是该问题产生的根源。方案 1结合负载均衡器命名与 target 注解推荐使用alb.ingress.kubernetes.io/load-balancer-name生成可预测的 hostname然后通过external-dns.kubernetes.io/target注解显式指定 NLB 作为目标apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/scheme: internal alb.ingress.kubernetes.io/enable-frontend-nlb: true alb.ingress.kubernetes.io/frontend-nlb-scheme: internal alb.ingress.kubernetes.io/load-balancer-name: myapp-alb external-dns.kubernetes.io/target: k8s-myapp-nlb.elb.us-east-1.amazonaws.com name: echoserver spec: ingressClassName: alb rules: - host: echoserver.example.org http: paths: - path: / backend: service: name: echoserver port: number: 80 pathType: Prefix优点负载均衡器命名在跨环境中可预测、一致对 ExternalDNS 使用哪个目标有显式控制与内部 ALB 配合可靠无需去查询自动生成的 NLB 名称。hostname 规律设置load-balancer-name: myapp-alb后NLB hostname 变为k8s-myapp-nlb.elb.region.amazonaws.com注意-nlb后缀对应 ALB 内部 hostname 变为internal-myapp-nlb.region.elb.amazonaws.com注意internal-前缀。从源码看external-dns.kubernetes.io/target注解由 source/annotations/annotations.go 中的TargetKey定义解析逻辑在 source/annotations/processors.go 的TargetsFromTargetAnnotation中实现它同样按逗号切分、去除末尾句点然后将这些目标覆盖掉从 Ingress Status 提取的负载均衡器 hostname。方案 2仅使用 target 注解如果无法控制负载均衡器名称可以显式指定 NLB hostnameapiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/scheme: internal alb.ingress.kubernetes.io/enable-frontend-nlb: true alb.ingress.kubernetes.io/frontend-nlb-scheme: internal external-dns.kubernetes.io/target: k8s-myapp-nlb-123456789.elb.us-east-1.amazonaws.com name: echoserver spec: ingressClassName: alb rules: - host: echoserver.example.org http: paths: - path: / backend: service: name: echoserver port: number: 80 pathType: Prefix[!NOTE] 使用此方案时你需要先等控制器创建出 NLB再去查询自动生成的 NLB hostname 填入注解。相较方案 1它缺少可预测命名的优势但仍然能确保 DNS 指向正确的 NLB。方案 3使用 DNSEndpoint 自定义资源如果你希望独立于 Ingress 资源管理 DNS 记录可以创建DNSEndpoint自定义资源apiVersion: externaldns.k8s.io/v1alpha1 kind: DNSEndpoint metadata: name: echoserver-dns spec: endpoints: - dnsName: echoserver.example.org recordType: CNAME targets: - k8s-myapp-nlb-123456789.elb.us-east-1.amazonaws.comDNSEndpoint是 ExternalDNS 官方 CRD 机制其 API 定义见 apis/v1alpha1/dnsendpoint.goCRD 清单位于 config/crd/standard/dnsendpoints.externaldns.k8s.io.yaml。使用该方案时需要额外在 ExternalDNS 启动参数中加上--sourcecrd或--sourcecrds详见 CRD 源文档。这样echoserver.example.org就会以 CNAME 方式指向指定的 NLB 目标不受 Ingress Status 排序问题的干扰。更多相关注解与参数速查结合 AWS 教程 与本仓库源码ALB/NLB 场景下常用的 ExternalDNS 注解还包括注解 / 参数作用external-dns.kubernetes.io/ttl自定义 DNS 记录 TTL默认 300 秒external-dns.kubernetes.io/alias在目标也是 ALIAS 时创建 A/AAAA ALIAS 记录可设为A或AAAA只创建一种当前仅 AWS Route53 provider 支持external-dns.kubernetes.io/aws-target-hosted-zone创建 ALIAS 目标时强制使用指定 Route53 hosted zone 的 IDexternal-dns.kubernetes.io/aws-hosted-zone-id将记录固定到指定 ID 的托管区域适用于同名重叠区域场景未配置该区域时跳过记录--aws-zone-match-parent配合--domain-filterx.example.com,example.com时允许在父区域内管理子域记录--aws-zone-typepublic只处理public或private类型的托管区域--aws-prefer-cname--txt-prefixGovcloud 等不允许 ALIAS 的场景下改用 CNAME 并给 TXT 记录加前缀总结将 ExternalDNS 与 AWS Load Balancer Controller 集成核心链路是Ingress 对象 → AWS 控制器创建 ALB/NLB → Ingress Status 暴露负载均衡器 hostname → ExternalDNS--sourceingress读取 hostname 并在 Route53 创建 A/AAAA ALIAS 记录。实践要点如下环境先按 AWS 教程 完成 IAM、托管区域与 ExternalDNS 部署再安装 AWS Load Balancer Controller域名生成既可通过spec.rules[].host自动生成也可用external-dns.kubernetes.io/hostname注解批量指定记录类型默认同时创建 A 与 AAAAIPv4-only 时可用--exclude-record-typesAAAA关闭 AAAA前端 NLB 陷阱内部 ALB frontend NLB 会因字母排序导致记录指向 ALB推荐可预测命名 external-dns.kubernetes.io/target组合方案或改用 DNSEndpoint 独立管理验证通过aws route53 list-resource-record-sets、dig与curl三步验证记录创建与解析结果。赞分享云原生【免费下载链接】external-dnsConfigure external DNS servers dynamically from Kubernetes resources项目地址https://gitcode.com/gh_mirrors/ex/external-dns点击查看免费下载相关推荐5分钟免费解锁Wand全部高级功能Wand-Enhancer本地补丁完整指南5分钟免费解锁Wand全部高级功能Wand Enhancer本地补丁完整指南 Wand Enhancer 是一个完全开源的本地增强工具免费解锁 Wand原桌面应用前端external-dns 与 kube-ingress-aws-controller 集成指南在 AWS 上为 ALB/NLB Ingress 自动管理 Route53 记录external dns 与 kube ingress aws controller 集成指南在 AWS 上为 ALB/NLB Ingress 自动管理 Ro云原生终极指南如何使用ExternalDNS与kube-ingress-aws-controller实现Kubernetes Ingress自动化DNS管理终极指南如何使用ExternalDNS与kube ingress aws controller实现Kubernetes Ingress自动化DNS管理 Ext云原生上一篇突破LLOneBot权限壁垒椰奶插件权限获取全解析与解决方案下一篇 终极解决Windows环境下TinyLlama模型NPU部署全攻略含7大痛点修复方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考