Skip to content

docs(networking): publish Kubernetes API endpoint via external-dns with kuberture#539

Open
lexfrei wants to merge 1 commit into
mainfrom
docs/kuberture-system-package
Open

docs(networking): publish Kubernetes API endpoint via external-dns with kuberture#539
lexfrei wants to merge 1 commit into
mainfrom
docs/kuberture-system-package

Conversation

@lexfrei
Copy link
Copy Markdown
Contributor

@lexfrei lexfrei commented May 14, 2026

What this PR does

Adds documentation for the kuberture system package being introduced in cozystack/cozystack#2647. New page at content/en/docs/next/networking/kuberture.md, weight 26 (slots in right after hairpin-proxy-protocol at weight 25 in the networking section).

The page covers:

  • The problem kuberture solves: external-dns does not support EndpointSlice as a source, so the canonical control-plane endpoint at default/kubernetes cannot be published to DNS without a bridge.
  • How kuberture works: a small in-cluster controller that watches EndpointSlice and stamps annotated headless Services (one per output) for external-dns to consume.
  • Single-instance enabling against the platform cozystack.external-dns with a copy-pasteable Package CR.
  • The cozystack-relevant flexibility: a single kuberture install can serve multiple external-dns instances simultaneously by stamping a different annotationPrefix per output, with the matching external-dns running with --annotation-filter. Includes a worked two-output example.
  • The four addressSource strategies (endpointslice / node-internal / node-external / node-public) and when each fits.
  • Disable path, including the cozystack-operator "no automatic Package garbage collection" wrinkle that's also documented for other optional packages, and the external-dns policy: upsert-only interaction on record retraction.
  • Supply-chain notes: chart and image both live under the maintainer's personal lexfrei/* registry namespace, are pinned by digest in the cozystack package, and air-gapped operators must mirror both into their internal registry.

Style follows networking/hairpin-proxy-protocol.md (the sibling system-addon doc for ouroboros): handwritten, narrative, single-line markdown paragraphs.

Release note

docs(networking): document the kuberture system package for publishing the Kubernetes API endpoint to DNS via external-dns.

Summary by CodeRabbit

  • Documentation
    • Added guide for publishing the Kubernetes API endpoint to DNS via the kuberture component, including configuration examples, setup procedures, and external-dns integration patterns.

Review Change Stack

@netlify
Copy link
Copy Markdown

netlify Bot commented May 14, 2026

Deploy Preview for cozystack ready!

Name Link
🔨 Latest commit b9be839
🔍 Latest deploy log https://app.netlify.com/projects/cozystack/deploys/6a05d34c17fad00008f513f9
😎 Deploy Preview https://deploy-preview-539--cozystack.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

Warning

Rate limit exceeded

@lexfrei has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 31 minutes and 54 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bf28d512-8c0c-4633-85ce-5555e207d9c8

📥 Commits

Reviewing files that changed from the base of the PR and between 4b586a3 and b9be839.

📒 Files selected for processing (1)
  • content/en/docs/next/networking/kuberture.md
📝 Walkthrough

Walkthrough

This PR introduces a comprehensive documentation page for the kuberture component, explaining how to publish the Kubernetes API endpoint to DNS via external-dns. The documentation covers the technical motivation, configuration patterns, operational procedures, and supply chain references.

Changes

kuberture DNS Publishing Documentation

Layer / File(s) Summary
Documentation setup and problem context
content/en/docs/next/networking/kuberture.md (lines 1–17)
Page metadata and overview explaining the limitation of external-dns when consuming Kubernetes EndpointSlice objects directly and the resulting DNS service gap compared to the upstream default/kubernetes slice.
kuberture mechanism and basic deployment
content/en/docs/next/networking/kuberture.md (lines 18–82)
Technical explanation of how kuberture watches EndpointSlice, converts it to annotated headless Service objects that external-dns can read, and documents how to enable kuberture via bundles.enabledPackages with a single output consuming the platform external-dns instance.
Advanced deployment and operations
content/en/docs/next/networking/kuberture.md (lines 83–145)
Multi-instance support using per-output annotationPrefix routing, address source resolution strategies and addressType filtering, procedures for disabling the package, manual cleanup via Package CR deletion, and external-dns record retention behavior.
Supply chain details and related documentation
content/en/docs/next/networking/kuberture.md (lines 146–157)
Chart and controller image sourcing, version pinning guidance, air-gapped environment mirroring instructions, and links to related configuration, component, and package reference documentation.

Estimated Code Review Effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰 A bundle with teeth, that watches so bright,
Converting slices to Services in the night,
kuberture publishes what DNS desires,
Through external-dns it fuels network spires!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding documentation for publishing the Kubernetes API endpoint via external-dns with kuberture. It is specific, concise, and directly reflects the new documentation page and its primary purpose.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/kuberture-system-package

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces documentation for kuberture, a component designed to bridge the gap between Kubernetes EndpointSlices and external-dns by creating annotated headless Services. The review feedback identifies a potential compatibility issue regarding how standard external-dns instances handle custom annotation prefixes for data extraction. Additionally, a suggestion was made to improve the clarity of the configuration documentation by better explaining the default behavior when the annotation prefix is omitted.


## Routing to multiple external-dns instances

A single `kuberture` install can address any number of `external-dns` instances by varying `annotationPrefix` per output. Each `external-dns` instance is configured (via `--annotation-filter`) to act on a specific prefix; `kuberture` stamps the matching prefix on each Service:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Standard external-dns does not support custom prefixes for data annotations like hostname, target, or ttl. It typically expects these keys to be prefixed with external-dns.alpha.kubernetes.io/. While --annotation-filter can be used to filter which Services an instance processes, it does not change the prefix used for data extraction. If kuberture only stamps annotations with a custom prefix, standard external-dns instances will not find the required DNS data. Please clarify if this feature requires a specific external-dns configuration or if kuberture should also stamp the standard annotations alongside the filter annotation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Premise needs a small correction — external-dns does support custom prefixes via --annotation-prefix, which is exactly the flag the Split Horizon DNS pattern uses. Fixed in b9be839: the doc now uses --annotation-prefix=<your-prefix>/ instead of --annotation-filter, so each external-dns instance rebuilds every hostname/target/ttl annotation key under the supplied prefix at startup and reads only the matching Services.


Each Service carries **only** its own prefix's annotations — there is no cross-pollution between outputs.

`annotationPrefix` accepts two forms: omit the field to inherit the controller default `external-dns.alpha.kubernetes.io/`, or set it to a non-empty string ending in `/`. The empty string `""` is rejected by the chart's values schema; omission is the only zero-prefix path.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The term "zero-prefix path" is confusing here. Since omitting the field results in the default prefix (external-dns.alpha.kubernetes.io/) being used, it is not actually a "zero" (empty) prefix. It would be clearer to state that omission is the way to use the default prefix.

Suggested change
`annotationPrefix` accepts two forms: omit the field to inherit the controller default `external-dns.alpha.kubernetes.io/`, or set it to a non-empty string ending in `/`. The empty string `""` is rejected by the chart's values schema; omission is the only zero-prefix path.
`annotationPrefix` accepts two forms: omit the field to inherit the controller default `external-dns.alpha.kubernetes.io/`, or set it to a non-empty string ending in `/`. The empty string `""` is rejected by the chart's values schema; omission is the only way to use the default prefix.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in b9be839 — "omission is the only zero-prefix path" is now "omission is the only way to fall back to the default prefix". Describes the resulting behaviour rather than the (admittedly confusing) "zero prefix" framing.

@lexfrei lexfrei force-pushed the docs/kuberture-system-package branch from ad08b7b to 4b586a3 Compare May 14, 2026 08:46
@lexfrei lexfrei marked this pull request as ready for review May 14, 2026 08:50
@lexfrei lexfrei requested review from kvaps and lllamnyp as code owners May 14, 2026 08:50
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@content/en/docs/next/networking/kuberture.md`:
- Line 40: The phrase "wants published" in the kuberture docs sentence is
awkward; update the sentence in content/en/docs/next/networking/kuberture.md
(the paragraph describing the operator DNS requirement for `kuberture`) to use
clearer wording such as "wants to publish" or "wants to be published" (e.g.,
replace "the DNS hostname the operator actually wants published" with "the DNS
hostname the operator actually wants to publish" or "the DNS hostname the
operator actually wants to be published") so the operator guidance reads
naturally.
- Around line 117-118: The docs incorrectly suggest using
--annotation-filter=internal-dns.example.com to match annotations like
internal-dns.example.com/hostname; update the text to use a full annotation key
(e.g., --annotation-filter=internal-dns.example.com/hostname) or note that
--annotation-filter requires exact annotation key matches, and reference the
example resource name kuberture-internal and the actual annotation keys
(internal-dns.example.com/hostname, internal-dns.example.com/target,
internal-dns.example.com/ttl) so readers know to pick one exact suffixed key for
the filter.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 783947a6-813d-4389-bb83-24d0682751be

📥 Commits

Reviewing files that changed from the base of the PR and between f466d34 and 4b586a3.

📒 Files selected for processing (1)
  • content/en/docs/next/networking/kuberture.md

Comment thread content/en/docs/next/networking/kuberture.md Outdated
Comment thread content/en/docs/next/networking/kuberture.md Outdated
@lexfrei lexfrei self-assigned this May 14, 2026
Copy link
Copy Markdown
Contributor

@Arsolitt Arsolitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Page is well-structured and aligned with the companion package PR. One blocker: the multi-instance routing recipe documents --annotation-filter where external-dns actually needs --annotation-prefix. Please also address the unresolved CodeRabbit/Gemini bot threads — note that the high-priority Gemini one is wrong on its premise (external-dns does support custom annotation prefixes via --annotation-prefix), but its underlying observation that the doc's current flag choice doesn't match standard external-dns behaviour is correct.

This renders two headless Services in `cozy-kuberture`:

- `kuberture-public` carries the default `external-dns.alpha.kubernetes.io/*` annotations and is consumed by the platform `external-dns`.
- `kuberture-internal` carries `internal-dns.example.com/*` annotations and is invisible to the platform `external-dns`; a second `external-dns` instance configured with `--annotation-filter=internal-dns.example.com` consumes it.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The recipe says a second external-dns instance configured with --annotation-filter=internal-dns.example.com consumes kuberture-internal. That flag does not produce the documented behaviour.

--annotation-filter is a label-selector filter on which objects external-dns considers at all; it uses Kubernetes label-selector semantics with exact key matching (source/annotations/filter.go at v0.20.0). A bare key internal-dns.example.com does not match an annotation key internal-dns.example.com/hostname. Even rewriting it as --annotation-filter=internal-dns.example.com/hostname (an existence selector) only filters which services external-dns looks at; the instance still reads hostname/target/ttl under its configured --annotation-prefix (default external-dns.alpha.kubernetes.io/), so the suffixed annotations on kuberture-internal would be invisible to it.

The flag that does what the docs describe is --annotation-prefix=internal-dns.example.com/. external-dns calls annotations.SetAnnotationPrefix(cfg.AnnotationPrefix) on startup (controller/execute.go:66 at v0.20.0) and rebuilds all hostname/target/ttl annotation keys under the supplied prefix. The upstream Split Horizon DNS doc (docs/advanced/split-horizon.md in kubernetes-sigs/external-dns) states verbatim: "To enable split horizon DNS, configure each instance to use a different annotation prefix using the --annotation-prefix flag."

Same wording on line 85 ("via --annotation-filter"). Both occurrences should be --annotation-prefix=<your-prefix>/ (note the trailing slash, matching the chart's values.schema.json pattern: /$).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b9be839. Both occurrences (lines 85 and 117) now use --annotation-prefix=<your-prefix>/, with a link to the upstream Split Horizon DNS doc and an inline note distinguishing the two flags (--annotation-filter is a Kubernetes label-selector on which Services to consider; --annotation-prefix rebuilds the annotation key namespace external-dns reads from).

…th kuberture

Document the kuberture system package: the EndpointSlice-to-Service
bridge that lets external-dns publish the cluster's own API endpoint.
Covers the problem (external-dns does not support EndpointSlice as a
source), the kuberture flow, single-instance enabling against the
platform external-dns, multi-instance routing via annotationPrefix,
the four addressSource strategies, the disable path, and the
maintainer-personal-namespace supply-chain caveat.

Companion to cozystack/cozystack#2647 which adds the package.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
@lexfrei lexfrei force-pushed the docs/kuberture-system-package branch from 4b586a3 to b9be839 Compare May 14, 2026 13:51
@lexfrei
Copy link
Copy Markdown
Contributor Author

lexfrei commented May 14, 2026

@Arsolitt addressed: the multi-instance recipe blocker is fixed in b9be839. Both --annotation-filter occurrences on lines 85 and 117 are replaced with --annotation-prefix=<your-prefix>/, with an inline note that --annotation-filter is a Kubernetes label-selector on which Services to consider (not a way to change the prefix external-dns reads data from) and a link to the upstream Split Horizon DNS doc. The Gemini and CodeRabbit threads on the same flag are addressed by the same commit. The Gemini wording nit on zero-prefix path (line 121) and the CodeRabbit wants published wording (line 40) are also folded in.

@Arsolitt Arsolitt dismissed their stale review May 14, 2026 14:17

Addressed by author in b9be839; re-reviewing.

Copy link
Copy Markdown
Contributor

@Arsolitt Arsolitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocker resolved in b9be839 — both --annotation-filter occurrences (lines 85 and 117) now read --annotation-prefix=<your-prefix>/, with an inline note clarifying that --annotation-filter is a label-selector on which Services an external-dns instance considers, not which prefix it reads data from. The "zero-prefix path" wording flagged by Gemini is also cleaned up in this iteration.

Approving.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants