资讯动态

ExternalDNS OpenShift Route Source 实战指南:将 OpenShift Route 自动同步为 DNS 记录

发布时间:2026/9/25 15:48:25 来源:尧图企业网站定制
云原生【免费下载链接】external-dnsConfigure external DNS servers dynamically from Kubernetes resources项目地址https://gitcode.com/gh_mirrors/ex/external-dns点击查看免费下载OpenShift Route 是 OpenShift 平台面向外部的流量入口本文基于当前仓库中的 docs/sources/openshift.md 编写完整讲解 ExternalDNS 如何使用openshift-route数据源把 Route 的spec.host与路由器router的 canonical hostname 自动转换为 CNAME 记录并同步到 AWS 等 DNS 提供方。读完本文你将掌握 OCP 4.x 与 OCP 3.11 两种集群形态下的部署清单、--openshift-router-name等关键参数的语义、以及从源码层验证目标选择逻辑的方法。OpenShift Route Source 是什么openshift-route是 ExternalDNS 众多数据源中的一个负责监听集群中的Route.route.openshift.io资源Category 为 OpenShift支持 annotation/label 过滤、单命名空间或全命名空间监听、FQDN 模板与 provider-specific 注解。它的核心工作方式是主机名Hostname取自 Route 的spec.host字段目标Target取自 Routestatus中被选定路由器的RouterCanonicalHostname字段记录类型生成 CNAME 记录将spec.host指向该 canonical hostname。在 source/openshift_route.go 的源码注释中对该数据源的功能定义非常明确The Route implementation will use the Route spec.host field for the hostname, and the Route status canonicalHostname field as the target. The annotations.TargetKey can be used to explicitly set an alternative endpoint, if desired.也就是说默认情况下每个被 admit 的 Route 都会产生一条host - routerCanonicalHostname的 CNAME 记录如果想要覆盖目标可以显式使用external-dns.kubernetes.io/target注解。数据源实现原理源码级解析从 informer 到 Endpoints 的调用链NewOcpRouteSource在 source/openshift_route.go 中完成初始化使用 OpenShift client-go 的SharedInformerFactory监听 Route 资源resync 周期设为0即只有资源真正变化时才触发处理通过 informer 转换器transformers剔除managedFields与kubectl.kubernetes.io/last-applied-configuration注解避免脏数据干扰注册三类索引器indexersAnnotationFilter--annotation-filter、LabelFilter--label-filter以及annotations.IsControllerMatchexternal-dns.kubernetes.io/controller匹配这意味着 OpenShift Route 数据源同样遵循 ExternalDNS 统一的过滤语义调用informerFactory.Start并等待本地缓存同步完成。Endpoints()方法在 source/openshift_route.go 中遍历索引出的全部 Route对每个 Route 执行通过模板引擎CombineWithEndpoints合并两种生成路径直接从 Route 提取的 endpointsendpointsFromOcpRoute与基于--fqdn-template模板生成的 endpointsendpointsFromTemplate跳过空 endpoints并为每个 endpoint 挂载资源引用route/namespace/name格式的 ResourceLabel最终调用endpoint.MergeEndpoints合并去重后返回。路由器router选择的核心逻辑多路由器集群下目标选择的判定集中在getTargetsFromRouteStatus见 source/openshift_route.go。其遍历status.ingress的逻辑可以归纳为跳过未被 admit 的 ingressRouteAdmitted条件不等于True或没有RouterCanonicalHostname的 ingress若指定了--openshift-router-name即ocpRouterName且与某个 ingress 的RouterName匹配则返回该路由器的 canonical hostname若未指定 router name则返回status.ingress列表中第一个被 admit的路由器若没有任何路由器 admit 该 Route则不生成目标返回空。这与文档在「For OCP 4.x」一节中的说明完全一致不指定 router name 时取status.ingress中的第一个路由器且该路由器必须已经 admit 了这条 Route。测试用例的印证source/openshift_route_test.go 中的表格驱动测试完整覆盖了这些分支可作为理解行为边界的参考测试场景期望结果基本 hostname status target已 admit生成my-domain.com - apps.my-domain.com的 CNAME指定ocpRouterName: default且匹配使用router-default.my-domain.com作为目标两个路由器、指定default只选择default对应目标指定的 router 未 admit 该 Route不生成 endpoint没有任何 router admit不生成 endpoint第一个匹配的 router admit选择第一个 admit 的路由器controller注解为其他值如foo不生成 endpoint使用external-dns.kubernetes.io/target注解以注解值my.site.foo.com作为目标label 过滤器匹配 / 不匹配仅匹配的路由生成 endpointprovider-specific 注解如external-dns.kubernetes.io/aws-weight: 10作为 ProviderSpecific 属性透传给 provider在 OCP 4.x 中使用 OpenShift Route 数据源多 ingress controller 场景必须指定 router name在 OCP 4.x 中如果集群中存在多个 OpenShift ingress controllerrouter就必须通过--openshift-router-name指定目标路由器名称。该名称可以从 Route 的status.ingress[*].routerName字段获取。若不指定ExternalDNS 会选用status.ingress中的第一个路由器该路由器必须已经 admit 这条 Route否则该 Route 不会生成记录。一旦确定了路由器ExternalDNS 就会用该路由器的 canonical hostname 作为 CNAME 记录的目标。--openshift-router-name参数的官方定义位于 pkg/apis/externaldns/types.goif source is openshift-route then you can pass the ingress controller name. Based on this name external-dns will select the respective router from the route status and map that routerCanonicalHostname to the route host while creating a CNAME record.该参数最终会经 source/store.go 中的Config.OCPRouterName字段传入ocpRouteSource。通过 ExternalDNS Operator 管理OCP 4.10从 OCP 4.10 开始可以使用 OpenShift 官方的 ExternalDNS Operator 来管理 ExternalDNS 实例。以 AWS provider 为例其自定义资源Custom Resource写法如下apiVersion: externaldns.olm.openshift.io/v1alpha1 kind: ExternalDNS metadata: name: sample spec: provider: type: AWS source: openshiftRouteOptions: routerName: default type: OpenShiftRoute zones: - Z05387772BD5723IZFRX3提交该 CR 后Operator 会在external-dns命名空间下创建 ExternalDNS Pod其容器参数等价于spec: containers: - args: - --metrics-address127.0.0.1:7979 - --txt-owner-idexternal-dns-sample - --provideraws - --sourceopenshift-route - --policysync - --registrytxt - --log-leveldebug - --zone-id-filterZ05387772BD5723IZFRX3 - --openshift-router-namedefault - --txt-prefixexternal-dns-从这份生成的参数列表可以看出Operator 把 CR 中的routerName: default映射为--openshift-router-namedefault把zones映射为--zone-id-filter其余为常规的 provider/registry/policy 参数。在 OCP 3.11 环境中部署准备 ROUTER_CANONICAL_HOSTNAMEOCP 3.11 的部署前提是让 router 具备 canonical hostname需要参考 OpenShift 文档「Finding the Host Name of the Router」一节在 default/router deployment 中配置ROUTER_CANONICAL_HOSTNAME。重要限制如果未设置ROUTER_CANONICAL_HOSTNAME则必须为每条 Route 手工添加external-dns.kubernetes.io/target注解否则 ExternalDNS 无法从 status 中解析出目标也就不会生成记录。Manifest无 RBAC 集群对于未启用 RBAC 的集群可以直接部署如下 DeploymentapiVersion: apps/v1 kind: Deployment metadata: name: external-dns spec: strategy: type: Recreate selector: matchLabels: app: external-dns template: metadata: labels: app: external-dns spec: containers: - name: external-dns image: registry.k8s.io/external-dns/external-dns:v0.23.0 args: - --sourceopenshift-route - --domain-filterexternal-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones - --provideraws - --policyupsert-only # prevents ExternalDNS from deleting any records, set --policysync to enable full synchronization (including deletions) - --aws-zone-typepublic # only look at public hosted zones (valid values are public, private or no value for both) - --registrytxt - --txt-owner-idmy-identifier各参数说明--sourceopenshift-route启用 OpenShift Route 数据源--domain-filterexternal-dns-test.my-org.com只处理与该域名匹配的 hosted zone省略则处理全部可用 hosted zone--provideraws使用 AWS Route53 provider具体参数可参考 AWS 教程--policyupsert-only只新增/更新、不删除记录改为--policysync可启用包含删除的完整同步--aws-zone-typepublic只处理 public hosted zone可选值为public、private或不填两者都处理--registrytxt--txt-owner-idmy-identifier使用 TXT registry 做所有权标记避免记录被误删。Manifest启用 RBAC 的集群启用 RBAC 的集群需要额外创建 ServiceAccount、ClusterRole 与 ClusterRoleBinding其中必须包含对route.openshift.io/routes的get/watch/list权限apiVersion: v1 kind: ServiceAccount metadata: name: external-dns --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: external-dns rules: - apiGroups: [] resources: [services,pods] verbs: [get,watch,list] - apiGroups: [discovery.k8s.io] resources: [endpointslices] verbs: [get,watch,list] - apiGroups: [extensions,networking.k8s.io] resources: [ingresses] verbs: [get,watch,list] - apiGroups: [] resources: [nodes] verbs: [list] - apiGroups: [route.openshift.io] resources: [routes] verbs: [get,watch,list] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: external-dns-viewer roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: external-dns subjects: - kind: ServiceAccount name: external-dns namespace: default --- apiVersion: apps/v1 kind: Deployment metadata: name: external-dns spec: strategy: type: Recreate selector: matchLabels: app: external-dns template: metadata: labels: app: external-dns spec: serviceAccountName: external-dns containers: - name: external-dns image: registry.k8s.io/external-dns/external-dns:v0.23.0 args: - --sourceopenshift-route - --domain-filterexternal-dns-test.my-org.com # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones - --provideraws - --policyupsert-only # prevents ExternalDNS from deleting any records, set --policysync to enable full synchronization (including deletions) - --aws-zone-typepublic # only look at public hosted zones (valid values are public, private or no value for both) - --registrytxt - --txt-owner-idmy-identifier注意deployment.spec.template.spec.serviceAccountName: external-dns这一行它让 Pod 以刚创建的 ServiceAccount 身份运行从而获得读取 Route 等资源的权限。Route 数据源支持的注解根据 docs/annotations/annotations.md 的注解支持矩阵OpenShift 数据源支持以下注解前缀默认为external-dns.kubernetes.io/v0.22.0 之前为external-dns.alpha.kubernetes.io/注解作用external-dns.kubernetes.io/controller若值不是dns-controller则该 Route 被忽略不生成记录external-dns.kubernetes.io/hostname为 Route 追加额外的域名逗号分隔多个与spec.host并存external-dns.kubernetes.io/target显式指定 DNS 记录目标优先级高于从 route status 解析出的 canonical hostname未配置ROUTER_CANONICAL_HOSTNAME时必须使用external-dns.kubernetes.io/ttl自定义记录的 TTLprovider-specific 注解如 AWS 的external-dns.kubernetes.io/aws-weight透传给 provider 的额外属性其中external-dns.kubernetes.io/target的优先级在 source/openshift_route.go 中体现先尝试读取注解目标仅在注解目标为空时才回退到 route status 解析的目标。hostname注解的读取位于endpointsFromOcpRoute并且可以通过--ignore-hostname-annotation关闭。另外该数据源支持--fqdn-template模板fqdn-templatetrue当 Route 缺少spec.host时可以用模板如{{.Name}}.example.com派生主机名相关验证逻辑见 source/openshift_route_fqdn_test.go。端到端验证hello-openshift 示例下面的验证步骤基于 OpenShift 官方的 hello-openshift 示例应用。安装示例服务并通过 Route 暴露$ oc apply -f - EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: hello-openshift name: hello-openshift spec: replicas: 1 selector: matchLabels: app: hello-openshift template: metadata: labels: app: hello-openshift spec: containers: - image: openshift/hello-openshift name: hello-openshift --- apiVersion: v1 kind: Service metadata: labels: app: hello-openshift name: hello-openshift spec: ports: - port: 8080 protocol: TCP targetPort: 8080 selector: app: hello-openshift sessionAffinity: None type: ClusterIP --- apiVersion: route.openshift.io/v1 kind: Route metadata: name: hello-openshift spec: host: hello-openshift.example.com to: kind: Service name: hello-openshift weight: 100 wildcardPolicy: None EOFRoute 的spec.host: hello-openshift.example.com就是 ExternalDNS 要写入 DNS 的域名目标则来自 router 的 canonical hostname。用 curl 访问验证Route 被 admit 且 DNS 记录生效后访问该域名应得到应用响应$ curl -i http://hello-openshift.example.com HTTP/1.1 200 OK Date: Fri, 10 Apr 2020 09:36:41 GMT Content-Length: 17 Content-Type: text/plain; charsetutf-8 Hello OpenShift!如果 curl 返回 200 与Hello OpenShift!说明 Route 的 DNS 记录已经正确解析到 router 并完成流量转发。关键参数速查以下参数在 OpenShift Route 数据源的两种部署形态直接 Deployment 与 Operator 生成的 Pod中最为常用参数说明--sourceopenshift-route启用 OpenShift Route 数据源--openshift-router-namename多 ingress controller 时指定路由器名称取值来自status.ingress[*].routerName--domain-filterdomain限定处理的 hosted zone 域名--zone-id-filterzone-id限定处理的 hosted zone IDOperator 示例中使用--providerawsDNS provider 类型与具体 provider 教程配合--policyupsert-only/--policysync前者只增改不删后者完整同步含删除--aws-zone-typepublic/private只处理对应类型的 hosted zone--registrytxt使用 TXT registry 记录所有权--txt-owner-ididTXT 记录的所有者标识--txt-prefixprefixTXT 记录前缀Operator 示例中使用延伸阅读OpenShift Route 数据源完整实现目标选择、informer 初始化与 Endpoints 生成逻辑OpenShift Route 数据源测试多路由器、注解目标、label/annotation 过滤等行为的表格化验证FQDN 模板测试Route 缺省 host 时的模板派生行为支持的 Sources 总览openshift-route 在全部数据源中的能力矩阵注解总览target、hostname、ttl、controller等注解的通用语义AWS Provider 教程与本文 Deployment 清单配套的 provider 配置步骤赞分享云原生【免费下载链接】external-dnsConfigure external DNS servers dynamically from Kubernetes resources项目地址https://gitcode.com/gh_mirrors/ex/external-dns点击查看免费下载相关推荐微信聊天记录永久保存3步打造你的数字记忆保险箱微信聊天记录永久保存3步打造你的数字记忆保险箱 你是否曾因手机丢失、系统升级或误操作而丢失珍贵的微信聊天记录那些与家人的温馨对话、朋友的重要约定、工作的关键云原生终极界面字体解决方案Source Sans 3 专业使用指南终极界面字体解决方案Source Sans 3 专业使用指南 还在为现代用户界面字体选择而烦恼吗面对琳琅满目的字体库你是否曾因字体渲染不清晰、字重选择有限云原生终极指南如何在macOS上使用eqMac专业音频均衡器提升音质体验终极指南如何在macOS上使用eqMac专业音频均衡器提升音质体验 你是否厌倦了macOS系统单调的音频效果想要为你的音乐、电影和游戏带来专业级的音质提升云原生上一篇Mealie 备份与恢复实战指南内置备份机制、文件结构与 Postgres 恢复要点下一篇FanControl 识别不到风扇按四层逐一排查让风扇重新回来创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑