Skip to content

[feat] Add IPv6 public backends for NodeBalancers#545

Merged
komer3 merged 1 commit intomainfrom
ipv6-backend-support
Mar 27, 2026
Merged

[feat] Add IPv6 public backends for NodeBalancers#545
komer3 merged 1 commit intomainfrom
ipv6-backend-support

Conversation

@komer3
Copy link
Copy Markdown
Contributor

@komer3 komer3 commented Mar 12, 2026

Summary

  • add IPv6 public backend support for NodeBalancer services using each node's node.k8s.linode.com/public-ipv6 annotation
  • make backend-family selection explicit through a global controller flag plus a per-service override, without implying VPC IPv6 backend support
  • add controller, chart, docs, CAPL workflow, and e2e coverage for the IPv6 backend path

Behavior

  • introduces --enable-ipv6-for-nodebalancer-backends as a global controller flag
  • introduces service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-backends as a per-service override
  • resolves backend family per service by honoring the service annotation first and then falling back to the global flag
  • programs NodeBalancer backends with node public IPv6 addresses when IPv6 backends are enabled
  • does not add VPC IPv6 backend support and does not apply IPv4 subnet IDs to IPv6 backend nodes
  • can migrate existing eligible services from IPv4 to IPv6 backends during reconcile when the global flag is enabled
  • returns an error instead of silently falling back to IPv4 when a selected backend node does not expose the required public IPv6 address
  • uses IPv6-safe host:port formatting for backend node addresses
  • falls back to the Service's current status if a fresh LoadBalancer status lookup fails during reconcile

Code Changes

  • add the new service annotation constant in cloud/annotations/annotations.go
  • add the new controller option in cloud/linode/options/options.go and register the flag in main.go
  • update cloud/linode/loadbalancers.go to:
    • resolve IPv6 backend selection from the service annotation first, then the global flag
    • choose backend addresses through a dedicated backend-IP path that switches between the existing IPv4/VPC flow and the new public IPv6 flow
    • omit IPv4 subnet IDs and VPC backend programming when IPv6 backends are selected
    • rebuild backend node configs with IPv6-safe address formatting
    • reuse existing NodeBalancer node IDs when possible during config rebuilds
    • fall back to the Service's current status when a fresh status lookup fails
  • add Helm chart support for the new controller flag in deploy/chart/templates/daemonset.yaml and deploy/chart/values.yaml
  • document the feature and backend behavior in docs/configuration/loadbalancer.md, docs/configuration/environment.md, and docs/configuration/annotations.md
  • ignore generated local cluster artifacts in .gitignore

CAPL And E2E Changes

  • add hack/patch-capl-manifest.sh to centralize generated manifest patching for:
    • .image.repository / .image.tag
    • image.pullPolicy: Always
    • LINODE_API_VERSION=v4beta
    • preserving the routeController.vpcNames template value
    • optional SUBNET_NAME injection for subnet test flows
    • removing reused LinodeVPC objects from the second subnet-test manifest when needed
  • update the Makefile/devbox flow to:
    • use repo-managed clusterctl
    • generate a dedicated dual-stack CAPL cluster for the IPv6 backend scenario
    • run the IPv6 backend Chainsaw case separately from the rest of e2e
    • route regular and subnet CAPL manifest generation through the shared patch script
  • add a new Chainsaw scenario under e2e/test/lb-with-ipv6-backends/
  • deploy a dual-stack LoadBalancer service annotated with linode-loadbalancer-enable-ipv6-backends: "true"
  • verify NodeBalancer backend node addresses returned by the Linode API are IPv6
  • verify traffic still reaches both backend pods through the service

Tests

Unit

  • extend cloud/linode/loadbalancers_test.go with coverage for:
    • IPv4 backend selection for the existing path
    • IPv6 backend selection from node.k8s.linode.com/public-ipv6
    • preserving the expected NodeBalancer create request shape while selecting IPv6 backends via annotation or global flag
    • omitting VPC config and subnet IDs from IPv6 backend requests
    • failing when IPv6 backends are requested and a node lacks the required public IPv6 address
    • global flag and service annotation precedence
    • IPv6-safe backend address formatting

E2E

  • add a dedicated lb-with-ipv6-backends Chainsaw scenario for the public IPv6 backend path
  • require a dual-stack workload cluster and dual-stack Service definition for the scenario
  • verify both backend programming and end-to-end traffic through the NodeBalancer

@github-actions github-actions bot added the new-feature for new features in the changelog. label Mar 12, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 86.95652% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.62%. Comparing base (c023298) to head (e9cf6a1).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
cloud/linode/loadbalancers.go 86.95% 6 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #545      +/-   ##
==========================================
+ Coverage   73.43%   73.62%   +0.19%     
==========================================
  Files          19       19              
  Lines        2906     2927      +21     
==========================================
+ Hits         2134     2155      +21     
  Misses        523      523              
  Partials      249      249              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@komer3 komer3 marked this pull request as draft March 12, 2026 06:03
@komer3 komer3 requested a review from Copilot March 13, 2026 20:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for selecting public IPv6 addresses as NodeBalancer backend node targets (with global flag + per-Service annotation), including for VPC-backed NodeBalancers, and extends unit/e2e/docs/chart coverage around the new behavior.

Changes:

  • Add --enable-ipv6-for-nodebalancer-backends and service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-backends to control IPv6 backend selection.
  • Update NodeBalancer reconciliation to build backend node addresses using IPv6-safe host:port formatting and preserve VPC config when IPv6 backends are enabled.
  • Add Helm/docs and unit + Chainsaw e2e coverage for IPv6 backend behavior.

Reviewed changes

Copilot reviewed 14 out of 16 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
main.go Registers new controller flag for IPv6 NodeBalancer backends.
cloud/annotations/annotations.go Adds the per-service annotation constant for enabling IPv6 backends.
cloud/linode/options/options.go Adds a global options field to enable IPv6 NodeBalancer backends.
cloud/linode/loadbalancers.go Core logic: resolves IPv6-backend enablement, selects node backend IPs, preserves VPC config, and formats backend addresses safely for IPv6.
cloud/linode/loadbalancers_test.go Adds unit tests for IPv6 backend selection, precedence rules, VPC preservation, and address formatting.
deploy/chart/templates/daemonset.yaml Plumbs the new flag into the Helm chart DaemonSet args.
deploy/chart/values.yaml Documents the new Helm value for enabling IPv6 NodeBalancer backends.
docs/configuration/loadbalancer.md Documents frontend vs backend IPv6 behavior and operational requirements for IPv6 backends.
docs/configuration/environment.md Documents the new controller flag and its behavior/requirements.
docs/configuration/annotations.md Documents the new service annotation for IPv6 backends.
e2e/test/lb-with-ipv6-backends/create-pods-services.yaml Adds an e2e workload + dual-stack Service annotated to enable IPv6 backends.
e2e/test/lb-with-ipv6-backends/chainsaw-test.yaml Adds a Chainsaw scenario validating backend node addresses are IPv6 and traffic still reaches pods.
devbox.json Pins clusterctl version in the devbox environment.
devbox.lock Updates the devbox lockfile to reflect the pinned clusterctl version.
Makefile Updates cluster-api related versions and ensures clusterctl is used via a configured path.
.gitignore Ignores local generated cluster artifacts/kubeconfigs.

What:
- add the `service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-backends` annotation and the `--enable-ipv6-for-nodebalancer-backends` controller flag, including Helm values and docs
- resolve the backend address family per service so the service annotation overrides the global default when needed
- program NodeBalancer backends from `node.k8s.linode.com/public-ipv6` when IPv6 backends are enabled, format IPv6 backend addresses correctly, and omit IPv4 subnet IDs from IPv6 backend nodes
- avoid applying VPC backend configuration during IPv6 backend creation while preserving the existing IPv4/VPC path for non-IPv6 services
- fall back to the Service's current status when a fresh LoadBalancer status lookup fails during reconcile
- add unit coverage for backend IP selection, annotation-vs-flag resolution, IPv6 address formatting, and the VPC/subnet behavior around IPv6 backends
- add a dedicated Chainsaw test and CAPL workflow support for validating IPv6 public backends end to end in a dual-stack cluster
- centralize CAPL manifest patching for image overrides, `LINODE_API_VERSION=v4beta`, VPC/subnet mutations, and subnet-specific test setup
- document the feature, its dual-stack requirement, and its current limitation to node public IPv6 backends rather than VPC IPv6 backend addresses

Why:
- support NodeBalancer services that need IPv6 backend targets instead of the existing IPv4-only backend programming
- make the backend selection logic explicit so IPv6 public backends do not inherit IPv4/VPC assumptions such as subnet IDs
- validate the feature in CI and local CAPL flows using a dual-stack workload cluster that can actually serve IPv6 NodePort traffic
- keep the rollout understandable for operators by documenting the opt-in controls, migration behavior, and failure mode when nodes do not expose public IPv6 addresses

How:
- factor backend-family handling into helpers for backend-state resolution, subnet lookup, backend node construction, backend address formatting, and node backend IP selection
- read IPv6 backend addresses from the node public IPv6 annotation, return a clear reconcile error when a selected node lacks one, and continue using the existing private/VPC address path when IPv6 backends are disabled
- create a dedicated IPv6 CAPL cluster path and `ipv6-backends` Chainsaw selector, run that test separately from the rest of e2e, and use a dual-stack service definition to exercise the public IPv6 backend datapath
- patch generated CAPL manifests through `hack/patch-capl-manifest.sh` so the CCM image repo/tag, pull policy, beta API env var, VPC template values, and optional subnet override are applied consistently across regular, IPv6, and subnet test flows
- route `clusterctl` usage through repo-managed tooling/devbox configuration and ignore generated local manifest and kubeconfig artifacts from dev workflows
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for programming Linode NodeBalancer backend nodes using each Kubernetes node’s public IPv6 annotation, with an explicit global flag and per-service override, plus corresponding docs and e2e coverage.

Changes:

  • Introduces --enable-ipv6-for-nodebalancer-backends and the service.beta.kubernetes.io/linode-loadbalancer-enable-ipv6-backends annotation to control backend address family selection.
  • Updates NodeBalancer reconciliation to build backend node addresses via an IPv6-safe host:port formatter and to omit VPC/subnet backend programming when IPv6 backends are selected.
  • Adds CAPL manifest patch tooling and a dedicated Chainsaw e2e scenario to validate IPv6 backend programming and connectivity.

Reviewed changes

Copilot reviewed 15 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
main.go Registers the new controller flag for IPv6 NodeBalancer backends.
cloud/linode/options/options.go Adds a new global option to enable IPv6 NodeBalancer backends.
cloud/annotations/annotations.go Adds the new service annotation constant for enabling IPv6 backends.
cloud/linode/loadbalancers.go Implements IPv6 backend selection, backend IP resolution, and IPv6-safe backend address formatting.
cloud/linode/loadbalancers_test.go Adds unit tests for backend-family selection, IPv6 backend IP parsing, and request shape expectations.
deploy/chart/templates/daemonset.yaml Wires the Helm value into the new controller flag.
deploy/chart/values.yaml Documents Helm configuration for IPv6 NodeBalancer backends.
docs/configuration/loadbalancer.md Documents IPv6 backend behavior and recommended Service configuration.
docs/configuration/environment.md Documents the new controller flag.
docs/configuration/annotations.md Documents the new per-service annotation.
e2e/test/lb-with-ipv6-backends/* Adds a new Chainsaw test scenario validating IPv6 backend programming and traffic.
hack/patch-capl-manifest.sh Centralizes CAPL manifest patching for e2e workflows.
Makefile Adds dual-stack CAPL cluster generation and a dedicated IPv6-backend e2e target; routes manifest generation through the patch script.
devbox.json Adjusts devbox packages and adds convenience scripts for the new Makefile targets.
devbox.lock Updates pinned clusterctl package metadata.
.gitignore Ignores locally generated cluster manifest/kubeconfig artifacts.


.PHONY: e2e-test
e2e-test:
# Run ipv6 tests first and then the rest
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

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

In the e2e-test recipe, the comment line is indented with spaces instead of a tab. In Makefiles, every recipe line (including comments) must start with a tab, otherwise make fails with "missing separator" and the target won’t run. Convert the leading spaces on this line to a tab (or move the comment outside the recipe).

Suggested change
# Run ipv6 tests first and then the rest
# Run ipv6 tests first and then the rest

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-feature for new features in the changelog.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants