15.1. Install External DNS#
Updating DNS is easy but it’s boring. Wouldn’t it be nice if when you create a new LoadBalancer
service or Ingress
with a name annotation a DNS record was created automatically? That’s the job of the External DNS project. External DNS is an official Kubernetes project.
Before You Begin
There are prerequisites that must be complete for you to do this lab:
You must have your own custom domain hosted using CloudDNS
You must not have a conflicting address record for your application (delete it before you begin)
Introduction#
External DNS runs as Pods in your cluster. One pod looks for new Ingress
and LoadBalancers
and sees if they have been annotated with a domain name. If so it reaches out of the cluster to update your DNS server. External DNS requires that you have a supported DNS server and the permission to modify records. In this lab we’ll:
Create a GCP service account with the permission to update DNS records.
Install External DNS
Check for new records
Create a Service Account#
Create a GCP service account (GSA) for ExternalDNS and save its email address.
$ project=$(gcloud config get-value core/project)
$ sa_name="Kubernetes external-dns"
$ gcloud iam service-accounts create sa-edns --display-name="$sa_name"
$ sa_email=$(gcloud iam service-accounts list --format='value(email)' \
--filter="displayName:$sa_name")
Bind the ExternalDNS GSA to the DNS admin role.
$ gcloud projects add-iam-policy-binding $project \
--member="serviceAccount:$sa_email" --role=roles/dns.admin
Link the ExternalDNS GSA to the Kubernetes service account (KSA) that external-dns will run under, i.e., the external-dns KSA in the external-dns namespaces.
$ gcloud iam service-accounts add-iam-policy-binding "$sa_email" \
--member="serviceAccount:${project}.svc.id.goog[default/external-dns]" \
--role=roles/iam.workloadIdentityUser
Deploy External DNS#
Just like any Helm chart External DNS needs configuration.
Warning
Update the file to contain your project and DNS name
Put the following into a file called values-edns.yaml
:
provider: "google"
policy: "sync"
serviceAccount:
create: true
name: external-dns
annotations:
iam.gke.io/gcp-service-account: sa-edns@MY-PROJECT-ID-HERE.iam.gserviceaccount.com
sources:
- service
- ingress
domainFilters:
- MYDOMAIN.HERE.
txtOwnerId: "kubernetes-app"
resources:
requests:
memory: "512Mi"
cpu: "250m"
ephemeral-storage: "10Mi"
limits:
memory: "512Mi"
cpu: "250m"
ephemeral-storage: "10Mi"
Deploy external DNS:
$ helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
$ helm repo update
$ helm install external-dns external-dns/external-dns --values values-edns.yaml
Now watch the pod get created:
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/external-dns-bbfcd6d55-cx5lc 1/1 Running 0 8m46s
pod/mysite 1/1 Running 0 52m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/external-dns ClusterIP 10.46.1.197 <none> 7979/TCP 8m46s
service/kubernetes ClusterIP 10.46.0.1 <none> 443/TCP 40d
service/mysite LoadBalancer 10.46.0.162 104.154.173.213 80:31633/TCP 3m21s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/external-dns 1/1 1 1 8m47s
NAME DESIRED CURRENT READY AGE
replicaset.apps/external-dns-bbfcd6d55 1 1 1 8m47s
Once running check the Pod logs. This will help you debug any problems:
$ kubectl logs -f pod/external-dns-bbfcd6d55-cx5lc
Annotate a Service#
Do this if you have not setup an Ingress controller. Set your service:
apiVersion: v1
kind: Service
metadata:
name: mysite
annotations:
external-dns.alpha.kubernetes.io/hostname: myhost.mydomain.com.
spec:
type: LoadBalancer
...
With the service annotation applied the host myhost.mydomain.com
will be automatically registered in your Cloud DNS zone.
Annotate an Ingress#
If you followed the Ingress lab you should already have an annotation specifying your hostname:
...
spec:
rules:
- host: "www.mydomain.com"
http:
...
This is sufficient to update the records.
Teardown#
If it works you should leave External DNS running so that it constantly updates your records. However, if you want to save money you can disable it until you make changes.
$ helm uninstall external-dns