Are you running your workloads in GKE / EKS / AKS? Do you use the ingress and load balancer service type for public-facing domains? Are your sub-domains increasing and changing regularly? If yes, then external DNS is for you.
Problem
Let us suppose you have a web application running in your Kubernetes Cluster. You might have a public-facing load balancer so that your application is accessible to the entire world.
Imagine you have a domain name called example.com and you want to map that to your public-facing load balancer provisioned by Kubernetes. For this, you can either use a gcloud command or maybe do it manually.
Now, what if you have hundreds of projects and thousands of DNS records to be created? What if the LoadBalancer Endpoint changes? How do you keep a track of hundreds of thousands of DNS records?
Solution
Here come external-dns to the picture. ExternalDNS allows you to control DNS records dynamically via Kubernetes resources in a DNS provider-agnostic way. ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers.
DNS Provider support
ExternalDNS allows you to keep selected zones (via --domain-filter
) synchronized with Ingresses and Services of type=LoadBalancer
and nodes in various cloud providers:
- Google Cloud DNS
- AWS Route53
- Azure DNS
- BlueCat
- Cloudflare
- RcodeZero
- DigitalOcean
- DNSimple, etc
What is the entire story all about? (TLDR)
- Create a GKE cluster.
- Deploy ExternalDNS to our GKE Cluster.
- Deploy a sample Web-Application.
- Automate the creation of DNS records in Google Cloud DNS using External DNS.
Prerequisites
- GCP account with running GKE cluster
- A Domain hosted in Google Cloud DNS
Host domain in Cloud DNS
Follow the below steps to configure Cloud DNS:
- Open GCP console
- Now, search for cloud DNS and open it.
- If you have already hosted a zone in the GCP that you can use then not required to follow this.
- Create a DNS zone.
- After that put your Name Server information to your domain provider Nameserver settings.
Deploy External DNS to the Kubernetes Cluster
Below is the manifest file to deploy the external-dns to the GKE cluster:
apiVersion: v1
kind: ServiceAccount
metadata:
name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: external-dns
rules:
- apiGroups: [""]
resources: ["services","endpoints","pods"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: external-dns-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: external-dns
subjects:
- kind: ServiceAccount
name: external-dns
namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: external-dns
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: external-dns
template:
metadata:
labels:
app: external-dns
spec:
serviceAccountName: external-dns
containers:
- name: external-dns
image: k8s.gcr.io/external-dns/external-dns:v0.7.3
args:
- --source=service
- --source=ingress
- --domain-filter=my.himanshuchaudhary.tech
- --provider=google
- --policy=upsert-only
- --registry=txt
- --txt-owner-id=gcloud-external-dns
Firstly, check the --domain-filter
arg which is filtering the domain that you want to use with external-dns. Secondly, check the --policy
arg which is set to upsert-only which means it can only create a dns entry but is not able to delete it automatically.
If you want to delete it as well, then change it to sync.
To deploy external-dns run the below command:
$ kubectl apply -f external-dns.yml
$ kubectl get pods
$ kubectl logs external-dns-6554c7ddf4-z5cfr
Deploy sample Application
After setting up the external dns now deploy a sample application with load balancer service and check the dns entry in the cloud dns which is done automatically with the help of external dns.
sample-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mywebapp
labels:
service: nginx
spec:
replicas: 2
selector:
matchLabels:
service: nginx
template:
metadata:
name: mywebapp-pod
labels:
service: nginx
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: service
operator: In
values:
- nginx
topologyKey: "kubernetes.io/hostname"
weight: 100
containers:
- name: mywebapp
image: docker.io/himanshuchaudhary/mywebapp:v1
ports:
- containerPort: 80
Above is the sample deployment, and the service type of load balancer is used for internet facing the application.
service.yml
apiVersion: v1
kind: Service
metadata:
name: mywebapp
labels:
service: nginx
annotations:
external-dns.alpha.kubernetes.io/hostname: test.my.himanshuchaudhary.tech
spec:
selector:
service: nginx
type: LoadBalancer
ports:
- port: 80
targetPort: 80
In service.yml I had used an annotation of external-dns, which tells the controller, which sub-domain entry it needs to add in cloud dns.
Verifying the Implementation
In the above image, you can see DNS entry is created automatically by external-dns and routing traffic to the load balancer IP. We can more verify by checking the logs of the controller.
Conclusion
In the blog, we learned how can we automate the DNS entry with the help of external-dns. If you have any doubts you can comment below or can reach out to me at himanshu.chaudhary@knoldus.com.
