The most surprising thing about Route 53 external DNS for EKS is that it’s not just about making your services resolvable; it’s about making your Kubernetes cluster aware of the external world through DNS, which unlocks powerful automation patterns.
Let’s say you have an EKS cluster running a web application. You want to expose it to the internet. Normally, you’d create a Kubernetes Service of type LoadBalancer, which provisions an AWS Elastic Load Balancer (ELB) and gives you a DNS name for it. You’d then manually go into Route 53 and create an A record pointing your custom domain (e.g., myapp.example.com) to that ELB DNS name. This works, but it’s fragile. If the ELB is replaced (e.g., during an upgrade or failure), its DNS name changes, and you have to update Route 53 manually.
This is where automation comes in. We can use the external-dns project to automatically manage Route 53 records based on Kubernetes Service and Ingress resources.
Here’s how it works:
-
Install
external-dnsin your EKS cluster. You’ll typically deploy it as aDeploymentwithin your cluster.apiVersion: apps/v1 kind: Deployment metadata: name: external-dns namespace: kube-system spec: selector: matchLabels: app: external-dns template: metadata: labels: app: external-dns spec: containers: - name: external-dns image: registry.k8s.io/external-dns/external-dns:v0.13.1 # Use the latest stable version args: - --source=service # Watch Kubernetes Services - --source=ingress # Watch Kubernetes Ingresses - --domain-filter=example.com # Only manage records for this domain - --provider=aws # Use AWS as the DNS provider - --aws-zone-type=public # Specify the type of Route 53 hosted zone - --registry=txt # Use TXT records for ownership verification (recommended) - --txt-owner-id=my-eks-cluster-123 # A unique identifier for your cluster - --log-level=info - --interval=1m # How often to sync DNS records env: - name: AWS_ACCESS_KEY_ID valueFrom: secretKeyRef: name: aws-credentials # A Kubernetes Secret containing your AWS credentials key: aws_access_key_id - name: AWS_SECRET_ACCESS_KEY valueFrom: secretKeyRef: name: aws-credentials key: aws_secret_access_key - name: AWS_REGION value: "us-east-1" # Your AWS regionYou’ll also need to create the
aws-credentialssecret. This secret should containaws_access_key_idandaws_secret_access_keykeys with your AWS IAM user credentials. The IAM user needs permissions to list and modify DNS records in your Route 53 hosted zone. -
Create a Kubernetes
Serviceof typeLoadBalancer. Whenexternal-dnsis running and configured, it will watch for Services with specific annotations.apiVersion: v1 kind: Service metadata: name: my-webapp-service annotations: external-dns.alpha.kubernetes.io/hostname: myapp.example.com. # The desired DNS name spec: selector: app: my-webapp ports: - protocol: TCP port: 80 targetPort: 8080 type: LoadBalancerThe
external-dns.alpha.kubernetes.io/hostnameannotation is the key here. It tellsexternal-dnsto create or update a Route 53 record formyapp.example.comthat points to the ELB DNS name provisioned by thisService. -
Observe Route 53. After applying the
Service, you’ll see a newArecord appear in yourexample.comhosted zone in Route 53, pointing to the ELB’s DNS name (e.g.,a1b2c3d4e5f6.us-east-1.elb.amazonaws.com). If the ELB is replaced,external-dnswill detect the change in the ELB’s DNS name and automatically update the Route 53 record.
You can also use Ingress resources. If you’re using an Ingress controller (like AWS Load Balancer Controller), external-dns can manage DNS records for your Ingress hostnames.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-webapp-ingress
annotations:
external-dns.alpha.kubernetes.io/hostname: myapp.example.com.
# Other ingress controller annotations
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-webapp-service
port:
number: 80
This pattern is incredibly powerful for maintaining a stable DNS entry for your applications, even as the underlying Kubernetes resources are scaled, updated, or replaced. The txt-owner-id combined with the registry=txt provider option is crucial for preventing external-dns from accidentally deleting records it doesn’t own. It writes a TXT record with its owner ID next to the managed DNS record, and before modifying or deleting a record, it checks for this TXT record’s existence.
While external-dns handles the creation of A/CNAME records, it doesn’t automatically manage the creation of the Route 53 Hosted Zone itself. You still need to manually create the primary Route 53 Hosted Zone for your domain (e.g., example.com) before external-dns can manage records within it.