labdns helps ExternalDNS publish DNS records for Kubernetes applications.
Kubernetes does not always provide an address that ExternalDNS can publish for an Ingress or Gateway API route. For example, an ingress controller may run on every Node as a DaemonSet and have only a ClusterIP Service, rather than a LoadBalancer address. labdns fills this gap by using addresses you assign to the Nodes that can serve each application.
It watches opted-in Ingresses and, when enabled, HTTPRoute, TCPRoute, and
UDPRoute resources. For each hostname, labdns follows the backend Service to
the Nodes that are serving it, reads the publishable IP addresses from Node
labels, and creates an ExternalDNS DNSEndpoint object.
ExternalDNS reads those objects and updates your DNS service. You install and manage ExternalDNS separately.
- You define a
DNSProvider. Despite its name, this is only a labdns settings object. It says which DNS zones and Node address labels to use. - You add labdns annotations to an Ingress or Gateway API route and choose one or more
DNSProviderobjects. - labdns finds the ready backend endpoints and the Nodes that host them.
- labdns creates one
DNSEndpointfor each selectedDNSProvider. - A separately installed ExternalDNS deployment reads the matching
DNSEndpointobjects and publishes them.
You can use different DNSProvider objects and ExternalDNS deployments to
publish different answers for the same hostname. For example, public DNS can
use public Node addresses while private DNS uses private addresses.
labdns requires Kubernetes 1.35 or newer (although it's been verified to work with 1.34),
the ExternalDNS DNSEndpoint CRD, and separately managed ExternalDNS deployment(s).
- Follow the quick start to publish an existing Ingress.
- Follow the installation guide for a production setup or to enable Gateway API support.
- Read the configuration guide for annotations,
DNSProvidersettings, address selection, record removal, and metrics. - Use the
labdnscommand to check controller health, inspect generated records, and optionally compare them with a DNS resolver.
Development requires Go 1.27.3 and Helm. The Makefile installs its Go tools and
Kubernetes test assets in bin/; Helm must already be available on PATH.
Run the required checks before submitting a change:
make manifests generate build lint test check-generated check-packagingDo not edit generated CRDs, RBAC, or zz_generated.* files by hand. Update
them with the Makefile targets instead.
Maintainer and release commands also require
just on PATH:
just --list
just check
just release patchjust release accepts patch, minor, or major. It checks that main is
clean and up to date, runs the release checks, updates the chart version,
creates a commit and tag, and asks before pushing them. Live end-to-end tests
are a separate just test-e2e command and require Kind plus Docker or Podman.
Docker remains the default. To build images and run E2E with rootless Podman:
CONTAINER_TOOL=podman make test-e2eKind requires cgroup v2 and delegated controllers for rootless providers; see its rootless provider guide.
Apache License 2.0. Copyright 2026 Konstantinos Kalyvas.