Kubernetes Source¶
The Kubernetes source extracts hostnames from Kubernetes networking resources. It works with the Kubernetes watcher to automatically detect DNS-relevant hostnames from your cluster workloads.
How It Works¶
flowchart LR
A["K8s API Server"] -->|"Informer Watch"| B["Resource Converters"]
B -->|"Ingress/IngressRoute/<br/>HTTPRoute/Service"| C["Workload Builder"]
C -->|"workload.Hostnames"| D["K8s Source"]
D -->|"+ Annotations"| E["source.Hostname[]"]
E --> F["Reconciler → DNS"]
- Informer-based watcher monitors K8s resources via the API server
- Resource converters extract hostnames from each resource type's spec
- K8s source reads the pre-extracted hostnames and applies annotation-based RecordHints
- Reconciler matches hostnames to DNS providers and creates/updates records
Supported Resources¶
| Resource | API Group | Version | Hostname Source |
|---|---|---|---|
| Ingress | networking.k8s.io |
v1 |
.spec.rules[].host |
| IngressRoute | traefik.io |
v1alpha1 |
Host() matcher in .spec.routes[].match |
| HTTPRoute | gateway.networking.k8s.io |
v1 |
.spec.hostnames[] |
| Service | (core) | v1 |
LoadBalancer ingress hostnames, ExternalName |
Configuration¶
Enable the Kubernetes source in your config:
platform: kubernetes # or "both" for Docker + K8s
sources:
- name: dnsweaver # Native dnsweaver.dev/* annotation labels
- name: kubernetes # K8s hostname extraction from resource specs
Or via environment variables:
Auto-registration
When platform is set to kubernetes or both, the kubernetes source is
automatically registered even if not listed in sources or DNSWEAVER_SOURCES.
You only need to list it explicitly if you want to control source ordering.
Annotations¶
The Kubernetes source reads dnsweaver.dev/* annotations from resources to override DNS record behavior:
Reference¶
| Annotation | Type | Default | Description |
|---|---|---|---|
dnsweaver.dev/enabled |
bool |
true |
Set to "false" to skip this resource entirely |
dnsweaver.dev/record-type |
string |
(from provider) | Override record type: A, AAAA, CNAME, SRV, TXT |
dnsweaver.dev/target |
string |
(from provider) | Override DNS target (IP or hostname) |
dnsweaver.dev/ttl |
int |
(from provider) | Override TTL in seconds |
dnsweaver.dev/provider |
string |
(auto-matched) | Route to a specific DNS provider by name |
dnsweaver.dev/proxied |
bool |
(from provider) | Enable Cloudflare proxy for this record |
Behavior¶
- Annotations are optional — resources without annotations are processed normally using provider defaults
dnsweaver.dev/enableddefaults totruewhen absent; explicitly set"false"to exclude a resource- RecordHints are per-hostname — all hostnames from a resource inherit the same annotations
- Provider matching — if
dnsweaver.dev/provideris set, only that provider handles the record; otherwise, normal domain-matching applies - Multiple sources — if both
dnsweaverandkubernetessources are enabled, annotations are processed by both (the dnsweaver source convertsdnsweaver.dev/*annotations to its native label format)
Examples¶
Standard Ingress (no annotations needed)¶
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
dnsweaver automatically extracts app.example.com and creates a DNS record using the matching provider's defaults.
Override Target and Provider¶
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: internal-app
annotations:
dnsweaver.dev/target: "10.0.0.100"
dnsweaver.dev/provider: "internal-dns"
dnsweaver.dev/record-type: "A"
spec:
entryPoints:
- websecure
routes:
- match: Host(`app.internal.home.example.com`)
kind: Rule
services:
- name: internal-app
port: 80
Disable for a Specific Resource¶
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: excluded-app
annotations:
dnsweaver.dev/enabled: "false"
spec:
rules:
- host: skip.example.com
# ...
Cloudflare Proxy¶
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: public-app
annotations:
dnsweaver.dev/provider: "cloudflare"
dnsweaver.dev/proxied: "true"
dnsweaver.dev/record-type: "CNAME"
dnsweaver.dev/target: "lb.example.com"
spec:
rules:
- host: public.example.com
# ...
Router Attribution¶
Each extracted hostname includes a router identifier for debugging and ownership tracking:
| Resource Type | Router Format | Example |
|---|---|---|
| Ingress | Ingress:namespace/name |
Ingress:default/my-app |
| IngressRoute | IngressRoute:namespace/name |
IngressRoute:traefik/dashboard |
| HTTPRoute | HTTPRoute:namespace/name |
HTTPRoute:gateway/api-route |
| Service | Service:namespace/name |
Service:default/my-svc |
Filtering¶
Namespace Filter¶
Limit watching to specific namespaces:
Label Selector¶
Only process resources matching a label selector:
Annotation Filter¶
Only process resources with a specific annotation:
Annotation filter vs dnsweaver.dev/enabled
The annotation_filter config filters at the watcher level (resources without the annotation are never seen). The dnsweaver.dev/enabled annotation filters at the source level (resources are watched but skipped during extraction). Use annotation_filter for hard opt-in; use dnsweaver.dev/enabled: "false" for selective opt-out.