Skip to content

Commit bd2f8a4

Browse files
docs(tutorials): import existing DNS records into ExternalDNS (#5811)
* Added steps for importing existing DNS records with ExternalDNS * fixing lint errors * fixing lint errors * retry - fixing lint errors * retry - fixing lint errors * review --------- Co-authored-by: Michel Loiseleur <[email protected]>
1 parent 1debdbc commit bd2f8a4

File tree

2 files changed

+147
-14
lines changed

2 files changed

+147
-14
lines changed

docs/advanced/import-records.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Import Existing DNS Records
2+
3+
Sometimes DNS records are created manually (e.g., through Route53, CloudDNS, or AzureDNS), but you still want ExternalDNS to take ownership of them for ongoing management. This tutorial shows how to “import” such records into ExternalDNS by creating the appropriate TXT records.
4+
5+
---
6+
7+
## Prerequisites
8+
9+
* A working Kubernetes cluster
10+
* ExternalDNS installed and configured with your DNS provider
11+
* Manually created DNS records that you want to manage
12+
13+
---
14+
15+
## Example: Importing a Manually Created A Record
16+
17+
Let’s assume you already have the following A record created manually in Route53:
18+
19+
```text
20+
grafana.dev.example.com → A record → pointing to NLB
21+
```
22+
23+
This entry is referenced in an Istio Gateway resource but was not created by ExternalDNS.
24+
25+
This is how a gateway.yaml file looks like:
26+
27+
```yaml
28+
apiVersion: networking.istio.io/v1
29+
kind: Gateway
30+
metadata:
31+
name: gateway
32+
namespace: istio-system
33+
spec:
34+
selector:
35+
istio: gateway
36+
servers:
37+
- hosts:
38+
- grafana.dev.example.com
39+
port:
40+
name: http
41+
number: 80
42+
protocol: HTTP
43+
```
44+
45+
External-dns deployment file:
46+
47+
```yaml
48+
apiVersion: apps/v1
49+
kind: Deployment
50+
metadata:
51+
name: external-dns
52+
namespace: kube-system
53+
spec:
54+
minReadySeconds: 15
55+
replicas: 2
56+
revisionHistoryLimit: 10
57+
selector:
58+
matchLabels:
59+
app: external-dns
60+
strategy:
61+
rollingUpdate:
62+
maxSurge: 50%
63+
maxUnavailable: 25%
64+
type: RollingUpdate
65+
template:
66+
metadata:
67+
labels:
68+
app: external-dns
69+
spec:
70+
automountServiceAccountToken: true
71+
containers:
72+
- args:
73+
- --source=service
74+
- --source=ingress
75+
- --source=istio-gateway
76+
- --domain-filter=dev.example.com.
77+
- --provider=aws
78+
- --policy=sync
79+
- --aws-zone-type=private
80+
- --registry=txt
81+
- --events
82+
- --txt-owner-id=dev.example.com
83+
- --log-level=info
84+
env:
85+
- name: AWS_DEFAULT_REGION
86+
value: us-west-2
87+
image: registry.k8s.io/external-dns/external-dns:v0.19.0
88+
imagePullPolicy: IfNotPresent
89+
name: external-dns
90+
securityContext:
91+
fsGroup: 65534
92+
runAsNonRoot: false
93+
serviceAccount: external-dns
94+
```
95+
96+
---
97+
98+
## Step 1: Create Corresponding TXT Records
99+
100+
To let ExternalDNS take ownership of the existing A record, you must add TXT records that follow the ExternalDNS format. For example:
101+
102+
```text
103+
aaaa-grafana.dev.example.com → TXT → "heritage=external-dns,external-dns/owner=dev.example.com,external-dns/resource=gateway/istio/gateway"
104+
cname-grafana.dev.example.com → TXT → "heritage=external-dns,external-dns/owner=dev.example.com,external-dns/resource=gateway/istio/gateway"
105+
```
106+
107+
Note: The easiest way to determine the correct TXT value is to create a dummy record with ExternalDNS. This will generate the required TXT entries, which you can then copy and apply to your manually created records.
108+
109+
These TXT records tell ExternalDNS:
110+
111+
* Which resource owns the record (`external-dns/resource=...`) (in this case, it's istio)
112+
* Which owner identifier is managing it (`external-dns/owner=...`)
113+
114+
---
115+
116+
## Step 2: Verify ExternalDNS Behavior
117+
118+
After creating the TXT records, wait for the next reconciliation loop. You should now see ExternalDNS managing the record without errors.
119+
120+
* With `policy=sync`: if you remove the entry from the Kubernetes resource (e.g., Istio Gateway), ExternalDNS will also remove the corresponding DNS record from your provider.
121+
* With `policy=upsert-only`: ExternalDNS will not delete existing records, even if you remove them from Kubernetes resources.
122+
123+
---
124+
125+
## Notes
126+
127+
* TXT records are required because they serve as ownership markers, preventing conflicts between multiple ExternalDNS controllers.
128+
* This approach is especially useful during migrations, where DNS records pre-exist but you want to avoid downtime or duplication.
129+
130+
---
131+
132+
With this setup, ExternalDNS will manage both newly created and previously existing records in a consistent way.

mkdocs.yml

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,24 @@ nav:
1919
- Providers: docs/providers.md
2020
- Tutorials: docs/tutorials/*
2121
- Annotations:
22-
- About: docs/annotations/annotations.md
22+
- About: docs/annotations/annotations.md
2323
- Sources: docs/sources/*
2424
- Registries:
25-
- About: docs/registry/registry.md
26-
- TXT: docs/registry/txt.md
27-
- DynamoDB: docs/registry/dynamodb.md
25+
- About: docs/registry/registry.md
26+
- TXT: docs/registry/txt.md
27+
- DynamoDB: docs/registry/dynamodb.md
2828
- Advanced Topics:
29-
- Initial Design: docs/initial-design.md
30-
- Kubernetes Events: docs/advanced/events.md
31-
- Leader Election: docs/proposal/001-leader-election.md
32-
- Monitoring: docs/monitoring/*
33-
- MultiTarget: docs/proposal/multi-target.md
34-
- NAT64: docs/advanced/nat64.md
35-
- Rate Limits: docs/advanced/rate-limits.md
36-
- TTL: docs/advanced/ttl.md
37-
- FQDN Templating: docs/advanced/fqdn-templating.md
38-
- Decisions: docs/proposal/0*.md
29+
- FQDN Templating: docs/advanced/fqdn-templating.md
30+
- Import Records: docs/advanced/import-records.md
31+
- Initial Design: docs/initial-design.md
32+
- Kubernetes Events: docs/advanced/events.md
33+
- Leader Election: docs/proposal/001-leader-election.md
34+
- Monitoring: docs/monitoring/*
35+
- MultiTarget: docs/proposal/multi-target.md
36+
- NAT64: docs/advanced/nat64.md
37+
- Rate Limits: docs/advanced/rate-limits.md
38+
- TTL: docs/advanced/ttl.md
39+
- Decisions: docs/proposal/0*.md
3940
- Contributing:
4041
- Kubernetes Contributions: CONTRIBUTING.md
4142
- Release: docs/release.md

0 commit comments

Comments
 (0)