-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat(annotations): add custom annotation prefix support for split horizon DNS #5889
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(annotations): add custom annotation prefix support for split horizon DNS #5889
Conversation
…izon DNS Add --annotation-prefix flag to allow customizing the annotation prefix used by external-dns. This enables split horizon DNS scenarios where multiple instances process different sets of annotations from the same Kubernetes resources. Changes: - Add AnnotationPrefix field to Config with validation - Convert annotation constants to variables that can be reconfigured - Add SetAnnotationPrefix() function to rebuild annotation keys - Integrate annotation prefix setting in controller startup - Update Helm chart with annotationPrefix value - Add comprehensive split horizon DNS documentation - Update FAQ with annotation prefix examples This maintains full backward compatibility - the default prefix remains "external-dns.alpha.kubernetes.io/". Co-Authored-By: Claude <[email protected]>
|
Welcome @lexfrei! |
|
Hi @lexfrei. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
|
Same behavior already exist Hard to see a reason for very similar flag. |
|
Another option, you could use FQDN https://github.com/kubernetes-sigs/external-dns/blob/master/docs/advanced/fqdn-templating.md#conditional-templating-combined-with-annotations-processing if fine grained behavior is prefered |
|
Thank you for the feedback! I understand the confusion. Let me clarify the difference between
The key difference: With My specific use case that FQDN templating cannot solve: I need to expose
Why? Internal clients shouldn't be routed through the internet (performance, cost, resilience if external connectivity fails). Why FQDN templating doesn't work:
Why apiVersion: v1
kind: Service
metadata:
annotations:
external-dns.alpha.kubernetes.io/hostname: api.service.com
external-dns.alpha.kubernetes.io/target: ??? # Can't specify two different targetsWith # values.yaml for third-party Helm chart (e.g., ArgoCD, Grafana, etc.)
service:
annotations:
# Internal DNS instance (Unifi provider)
internal.company.io/hostname: api.service.com
internal.company.io/target: "10.0.1.50"
# External DNS instance (Cloudflare provider)
external-dns.alpha.kubernetes.io/hostname: api.service.com
external-dns.alpha.kubernetes.io/target: "203.0.113.10"# Internal instance
external-dns --annotation-prefix=internal.company.io/ --provider=rfc2136 ...
# External instance
external-dns --provider=cloudflare ...Additional real-world benefit:
With Does this clarify the use case? |
|
The current implementation of annotation filter requires me to have duplicated services/ingresses/httproutes for each DNS provider I utilize. Having this option would allow me to have one dedicated service and allow me to utilize multiple webhook provider annotations where they currently conflict (different providers can use the same key and conflict, requiring me to setup individual annotation filters for each separate service). @lexfrei Please let me know if you need help with anything to move this forward. |
|
This is a duplicate of a functionality that is currently supported. The described case fully supported with Example how to support public and private routing with https://kubernetes-sigs.github.io/external-dns/latest/docs/sources/traefik-proxy/#support-private-and-public-routing |
Kubernetes offers a well-established and predictable model for working with labels and selectors, as outlined in the official documentation. You can combine --annotation-filter with --label-filter to refine resource selection. Since adding annotations or labels to Kubernetes objects incurs virtually no overhead, this approach is both efficient and scalable. Official docs https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ For edge-cases there is |
Maintaining two different ingress routes, creates several risks and problems related to consistency and overhead. While the --fqdn-template and webhook provider options offer a workaround, they are not a true solution for handling different public and private access rules for the same application. Even with webhook provider specific variables, this template would not be consistent across providers as the annotations contain a hardcoded webhook-* key. I believe there was talks to phase out in-tree providers, but running two identical webhook providers would cause these annotations to clash. Supporting annotationPrefixes would support that movement by allowing users to deploy multiple instances of the provider, (provided they config it). How can this be implemented with fdqn-template to support two separate providers with the same DNS Endpoints with different values in each without having to create two services just to make it available one or the other? |
|
/hold |
|
Kubernetes Design Philosophy: Simplicity & Predictability Kubernetes emphasizes declarative configuration and predictable behavior. Label and annotation selectors are designed to be:
Introducing partial matches (e.g., prefix or regex) adds unnecessary complexity and increases the risk of unintended behavior. Recommended Alternatives
|
|
The PR is currently on hold. Let's wait to hear the perspectives of other maintainers and project owners before drawing conclusions. |
|
As just a user of external-dns, this would make split-dns setups much more clean. |
|
Thank you for pushing this forward, @lexfrei I want to add my support (from real-world usage) and also highlight how this helps us (and others) in split-horizon / hybrid DNS setups. I run external-DNS together with kashall’s unifi webhook project and have faced exactly the pain points that this Why I think this is valuable / needed
Suggestions / clarifications that might strengthen the PR
My endorsementFrom my own deployments (external-DNS + the unifi webhook), I’d definitely use this feature. It would simplify my manifests, avoid resource duplication, and let multiple external-DNS instances coexist cleanly in the same cluster. To me, this is a meaningful usability and architectural improvement. Happy to help test or provide examples if that’s useful! |
|
I'd like to respectfully support this PR and address the concerns raised about functionality overlap. Regarding Why # Internal DNS: api.service.com → 10.0.1.50 (private IP)
# External DNS: api.service.com → 203.0.113.10 (public IP)This cannot be achieved with FQDN templating alone, as it doesn't support same-hostname-different-targets scenarios. Real-world impact on resource management: Addressing the "Kubernetes simplicity" concern: Conclusion: |
|
/hold cancel |
|
/ok-to-test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lexfrei For the Chart, would you please also update the changelog in the UNRELEASED section ?
For the docs, you'll need to add it this advanced page to mkdocs.yml.
Apart from that, it LVGTM. Thanks 👍
…it horizon DNS Signed-off-by: Aleksei Sviridkin <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
|
/lgtm |
|
/easycla |
Question about documentation discoverabilityI noticed that CONTRIBUTING.md at the repository root doesn't reference the detailed developer guides in While working on this PR, I treated CONTRIBUTING.md as the single entry point for contributors and didn't realize the detailed guides existed until later. Would a PR adding a reference to |
Yes, sure. It makes sense 👍 |
Follow-up to kubernetes-sigs#5889 discussion about documentation discoverability. Add a new "Developer Documentation" section in CONTRIBUTING.md that references the detailed developer guides in docs/contributing/. This improves discoverability for contributors and helps avoid split-brain when looking for development guidance. Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Helm chart changes look good to me.
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: stevehipwell The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
From my side also lgtm and I let @ivankatliarchuk review because of the change request, but the fix lgtm. @lexfrei I hope we don't see so often such big PRs, because honestly these are a hell to review. Even if AI makes it simple to write a lot of code, it's not for free and likely contains a lot of bugs, so better less code. 46 files is too huge for the next time. |
|
@szuecs Agreed! I manually review, test, and often edit everything by hand - so I understand the pain you're describing. Lesson learned - I'll keep PRs smaller next time. This one grew beyond my initial expectations. Thanks for reviewing! 🙏 |
Follow-up to #5889 discussion about documentation discoverability. Add a new "Developer Documentation" section in CONTRIBUTING.md that references the detailed developer guides in docs/contributing/. This improves discoverability for contributors and helps avoid split-brain when looking for development guidance. Co-authored-by: Claude <[email protected]>
|
I'll try to execute some tests against my labs this week |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From first look, this not just add support for a use case like split Horizon DNS, but overrides default annotation for external-dns. So before we use to have external-dns.alpha.kubernetes.io/-----xxxx----, now expectation is external-dns to work with any annotation prefix
I'm not sure if blast radius of this change is well understood.
@szuecs are we confident that this what we planning to change?
Replace all hardcoded "external-dns.alpha.kubernetes.io/" strings with annotations.DefaultAnnotationPrefix constant to establish a single source of truth. Changes: - Add DefaultAnnotationPrefix constant in source/annotations/annotations.go - Replace hardcoded string in controller/execute.go with constant reference - Replace hardcoded strings in pkg/apis/externaldns/types.go (2 occurrences) - Add helm unit tests for annotationPrefix value This eliminates string duplication and makes future changes easier. Co-Authored-By: Claude <[email protected]>
|
In addition to |
|
Yes. Create a PR for linter. /lgtm |
What does it do?
This PR adds a new
--annotation-prefixflag that allows customizing the annotation prefix used by external-dns. This enables running multiple external-dns instances against the same Kubernetes resources, with each instance processing only its designated set of annotations.Motivation
There are several real-world scenarios where you need multiple external-dns instances writing to different DNS servers or zones from the same Kubernetes resources:
1. Split Horizon DNS (Internal vs External)
A single Service needs to be accessible both from within the company's internal network and from the public internet, with different DNS records:
api.internal.company.com→ internal LoadBalancer IPapi.company.com→ public LoadBalancer IP2. Multiple API Gateways
When running multiple ingress controllers or API gateways (e.g., Kong for public APIs, internal gateway for private APIs):
public.company.io/hostnameannotationsinternal.company.io/hostnameannotations3. Multi-Region DNS with Different Providers
aws.company.io/prefixcloudflare.company.io/prefix4. Migration Scenarios
When migrating from one DNS provider to another:
legacy.company.io/prefixexternal-dns.alpha.kubernetes.io/prefix5. Corporate Network Architecture
When additional proxying is implemented outside Kubernetes (e.g., hardware load balancers, CDN):
Implementation Details
Changes:
AnnotationPrefixfield to Config with validation (must end with/)SetAnnotationPrefix()function to rebuild all annotation keys at runtimeannotationPrefixparameterBackward Compatibility:
external-dns.alpha.kubernetes.io/Testing:
Example Usage
More
Note: This PR was implemented by Claude Code AI assistant and thoroughly reviewed, tested, and validated in a real Kubernetes cluster environment before submission by the human maintainer.