- Authors

- Name
- Phillip Pham
- @ddppham
TL;DR
external-dns beobachtet Ingress-Ressourcen und Services in deinem Kubernetes-Cluster und erstellt automatisch DNS-Einträge beim DNS-Provider. Kein manuelles Pflegen von DNS-Zonen mehr. Dieses Tutorial zeigt die Einrichtung mit Cloudflare und AWS Route53.
external-dns: Nie wieder manuell DNS pflegen
Neuen Ingress erstellt, DNS-Eintrag vergessen — kennst du das? external-dns macht Schluss damit. Das Tool überwacht deinen Cluster und synchronisiert Hostnamen aus Ingress- und Service-Annotationen direkt mit deinem DNS-Provider.
Der Ablauf ist simpel:
Ingress mit host: app.example.com
│
▼
external-dns erkennt neuen Host
│
▼
DNS A-Record wird automatisch erstellt
│
▼
app.example.com → LoadBalancer-IP
Voraussetzungen
- Kubernetes-Cluster mit Ingress-Controller (z.B. nginx-ingress)
- DNS-Zone bei einem unterstützten Provider (Cloudflare, Route53, Google Cloud DNS, Azure DNS, u.v.m.)
- API-Token/-Key für den DNS-Provider
- Helm v3
kubectl get nodes
helm version --short
Installation mit Cloudflare
Cloudflare ist einer der beliebtesten DNS-Provider. Hier die komplette Einrichtung.
API-Token erstellen
Erstelle in Cloudflare unter "My Profile" > "API Tokens" einen Token mit diesen Berechtigungen:
- Zone / DNS / Edit
- Zone / Zone / Read
Beschränke den Token auf die Zonen, die external-dns verwalten soll.
Secret mit API-Token anlegen
kubectl create namespace external-dns
kubectl create secret generic cloudflare-api-token \
--namespace external-dns \
--from-literal=cf-api-token=DEIN-CLOUDFLARE-API-TOKEN
Helm-Installation
helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
helm repo update
helm install external-dns external-dns/external-dns \
--namespace external-dns \
--set provider.name=cloudflare \
--set env[0].name=CF_API_TOKEN \
--set env[0].valueFrom.secretKeyRef.name=cloudflare-api-token \
--set env[0].valueFrom.secretKeyRef.key=cf-api-token \
--set policy=sync \
--set txtOwnerId=k8s-cluster-01 \
--set domainFilters[0]=example.com
Prüfe ob der Pod läuft:
kubectl get pods -n external-dns
kubectl logs -n external-dns deployment/external-dns
Values-Datei für Cloudflare
Für mehr Kontrolle nutze eine Values-Datei:
# values-external-dns-cloudflare.yaml
provider:
name: cloudflare
env:
- name: CF_API_TOKEN
valueFrom:
secretKeyRef:
name: cloudflare-api-token
key: cf-api-token
# Nur diese Domains verwalten
domainFilters:
- example.com
- staging.example.com
# sync = Einträge erstellen, updaten UND löschen
# upsert-only = nur erstellen/updaten, nie löschen
policy: sync
# Identifier, damit mehrere Cluster sich nicht gegenseitig überschreiben
txtOwnerId: "k8s-cluster-01"
# Wie oft external-dns nach Änderungen schaut
interval: 1m
# Nur Ingress-Ressourcen beobachten (nicht Services)
sources:
- ingress
# Log-Level für Debugging
logLevel: info
helm upgrade --install external-dns external-dns/external-dns \
--namespace external-dns \
-f values-external-dns-cloudflare.yaml
Installation mit AWS Route53
Für AWS brauchst du IAM-Berechtigungen statt eines API-Tokens.
IAM Policy erstellen
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/DEINE-HOSTED-ZONE-ID"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListResourceRecordSets",
"route53:ListTagsForResource"
],
"Resource": ["*"]
}
]
}
Option A: IRSA (EKS — empfohlen)
Wenn du EKS mit IRSA nutzt:
# ServiceAccount mit IAM-Role verknüpfen
eksctl create iamserviceaccount \
--name external-dns \
--namespace external-dns \
--cluster dein-cluster-name \
--attach-policy-arn arn:aws:iam::ACCOUNT-ID:policy/ExternalDNSPolicy \
--approve
Option B: Secret mit AWS Credentials
kubectl create secret generic aws-credentials \
--namespace external-dns \
--from-literal=aws_access_key_id=AKIAXXXXXXXX \
--from-literal=aws_secret_access_key=DEIN-SECRET-KEY
Helm Values für Route53
# values-external-dns-route53.yaml
provider:
name: aws
env:
- name: AWS_DEFAULT_REGION
value: eu-central-1
# Nur bei Option B (Secret):
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: aws-credentials
key: aws_access_key_id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: aws-credentials
key: aws_secret_access_key
# Bei IRSA: ServiceAccount ist bereits erstellt
serviceAccount:
create: false # true bei Option B
name: external-dns
domainFilters:
- example.com
policy: sync
txtOwnerId: "k8s-cluster-01"
sources:
- ingress
- service
helm upgrade --install external-dns external-dns/external-dns \
--namespace external-dns \
-f values-external-dns-route53.yaml
Testen: Ingress mit automatischem DNS
Jetzt der spannende Teil — deploye einen Ingress und beobachte, wie der DNS-Eintrag erscheint:
# test-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-app
namespace: default
annotations:
# Optional: external-dns spezifische Annotationen
external-dns.alpha.kubernetes.io/hostname: test.example.com
external-dns.alpha.kubernetes.io/ttl: "300"
spec:
ingressClassName: nginx
rules:
- host: test.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-app
port:
number: 80
kubectl apply -f test-ingress.yaml
# Logs beobachten — external-dns sollte den Record erstellen
kubectl logs -n external-dns deployment/external-dns -f
Nach 1-2 Minuten (je nach interval-Einstellung) sollte in den Logs stehen:
level=info msg="Desired change: CREATE test.example.com A"
level=info msg="Desired change: CREATE test.example.com TXT"
Prüfe den DNS-Eintrag:
dig test.example.com +short
# oder
nslookup test.example.com
DNS für Services (LoadBalancer)
external-dns kann auch Services vom Typ LoadBalancer überwachen:
apiVersion: v1
kind: Service
metadata:
name: my-api
namespace: production
annotations:
external-dns.alpha.kubernetes.io/hostname: api.example.com
external-dns.alpha.kubernetes.io/ttl: "120"
spec:
type: LoadBalancer
selector:
app: my-api
ports:
- port: 443
targetPort: 8443
Damit das funktioniert, muss service in der sources-Liste stehen:
sources:
- ingress
- service
Mehrere Cluster, eine DNS-Zone
Wenn mehrere Cluster DNS-Einträge in derselben Zone verwalten, ist der txtOwnerId entscheidend. Jeder Cluster braucht eine eindeutige ID:
| Cluster | txtOwnerId | Beschreibung |
|---|---|---|
| Production | k8s-prod-01 | Verwaltet *.example.com |
| Staging | k8s-staging-01 | Verwaltet *.staging.example.com |
external-dns erstellt TXT-Records als "Ownership-Marker". Cluster A löscht keine Records, die Cluster B erstellt hat.
Troubleshooting
Keine DNS-Einträge werden erstellt:
# 1. Logs prüfen
kubectl logs -n external-dns deployment/external-dns --tail=100
# 2. Häufigste Ursachen:
# - API-Token hat nicht die richtigen Berechtigungen
# - domainFilter passt nicht zum Ingress-Hostname
# - source: ingress fehlt in der Config
# 3. Dry-Run testen
helm upgrade external-dns external-dns/external-dns \
--namespace external-dns \
-f values-external-dns-cloudflare.yaml \
--set dryRun=true
Records werden nicht gelöscht:
Prüfe, ob policy: sync gesetzt ist. Bei upsert-only löscht external-dns keine Records. Außerdem: Records ohne passenden TXT-Ownership-Record werden nicht angefasst.
FAQ
Welche DNS-Provider werden unterstützt?
Über 30 Provider: Cloudflare, AWS Route53, Google Cloud DNS, Azure DNS, DigitalOcean, Hetzner DNS, Pi-hole und viele mehr. Die vollständige Liste findest du in der external-dns-Dokumentation auf GitHub.
Was passiert, wenn ich einen Ingress lösche?
Bei policy: sync löscht external-dns den zugehörigen DNS-Eintrag automatisch. Bei policy: upsert-only bleibt der Eintrag bestehen.
Kann external-dns auch CNAME-Records erstellen?
Ja. Bei Cloud-LoadBalancern, die einen Hostnamen statt einer IP zurückgeben (z.B. AWS ELB), erstellt external-dns automatisch CNAME-Records statt A-Records.
Wie verhindere ich, dass external-dns bestimmte Einträge ändert?
Nutze --exclude-domains oder setze die Annotation external-dns.alpha.kubernetes.io/exclude=true am Ingress. Oder beschränke die domainFilters auf eine Subdomain.
Ist external-dns sicher? Was wenn jemand einen falschen Ingress erstellt?
external-dns selbst hat keine Authentifizierung. Schütze dich mit RBAC: Beschränke, wer Ingress-Ressourcen erstellen darf, und nutze domainFilters, um nur bestimmte Domains zu erlauben.
Nächster Schritt: Kombiniere external-dns mit cert-manager für automatische TLS-Zertifikate. Oder richte Velero-Backups ein, damit deine DNS-Konfiguration bei einem Cluster-Verlust schnell wiederhergestellt werden kann.
Kubernetes-Beratung gesucht?
Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
API Gateway für Kubernetes: Nginx, Kong, Traefik
Kubernetes API Gateways im Vergleich: Nginx Ingress, Kong und Traefik mit Feature-Matrix, Installations-Aufwand und Gateway API HTTPRoute-Beispielen.
Developer Onboarding auf Kubernetes automatisieren
Developer Onboarding auf Kubernetes automatisieren mit Namespace-Provisioning, RBAC, ResourceQuotas und ArgoCD ApplicationSets für Team-Umgebungen.
CoreDNS Debugging: Kubernetes-DNS Probleme lösen
DNS-Probleme in Kubernetes systematisch debuggen: CoreDNS-Logs, ndots-Konfiguration, NXDOMAIN-Fehler und Corefile-Optimierung für schnellere Auflösung.
Documentation as Code für Kubernetes-Plattformen
Kubernetes-Plattform-Dokumentation als Code verwalten mit MkDocs, automatisch generierten Docs aus CRDs und Helm Charts sowie ADRs in Git.
Gateway API: Der neue Kubernetes Ingress Standard
Kubernetes Gateway API als moderner Ingress-Ersatz. GatewayClass, Gateway und HTTPRoute konfigurieren, Traffic Splitting und Header-basiertes Routing einrichten.