April 13, 2021 - Patrick Kerwood
With External DNS for Kubernetes you can automate the creation of DNS records based on an ingress resource. This is a great feature to have, especially in a dynamic development environment. You could have pipelines deploy feature branches which create ingress hostnames based on the branch name and let External DNS create DNS entries for them.
Actually External DNS does not only create DNS entries, it will also remove them again once the ingress resource is deleted. It would be appropriate to say that External DNS synchronizes ingresses resource hostnames with DNS records. ExternalDNS will keep track of which records it has control over, and will never modify any records which it doesn't have control over. It uses TXT records to label owned records.
External DNS supports a long list of DNS providers, you can find the complete list at the official Github page. (opens new window)
Under the docs/tutorials (opens new window) folder you can find how-to's on different providers. In this example I will be using Digital Ocean is my DNS provider.
Create a namespace.
kubectl create namespace external-dns
External DNS needs a service account to operate. Below manifest will create the service account, a cluster role and a role binding. This step is the same regardless of which ever provider you choose.
apiVersion: v1 kind: ServiceAccount metadata: name: external-dns namespace: external-dns --- apiVersion: rbac.authorization.k8s.io/v1 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: ["list"] --- apiVersion: rbac.authorization.k8s.io/v1 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: external-dns
Create the secrets necessary for your provider.
kubectl create secret generic digital-ocean-token --from-literal=token=<digital-ocean-token> -n external-dns
The next step is where we configure and deploy External DNS. Below is a deployment resource, which you can configure to fit your needs.
--sourceis what External DNS is "monitoring" for hostnames, can be
--provideris your supported DNS provider.
--registry=txtis needed for External DNS to gain ownership of the created records.
--txt-owner-idis a unique ID set for the cluster. If you have multiple clusters, each cluster should have their own ID.
--txt-prefixwill prefix the txt record. Some DNS providers like Digital Ocean will not allow
TXTrecords with identical names.
--domain-filteris optional and will limit External DNS to that domain name.
Add your provider specific environment variables from the secrets created.
apiVersion: apps/v1 kind: Deployment metadata: name: external-dns namespace: external-dns spec: replicas: 1 selector: matchLabels: app: external-dns strategy: type: Recreate template: metadata: labels: app: external-dns spec: serviceAccountName: external-dns containers: - name: external-dns image: k8s.gcr.io/external-dns/external-dns:v0.7.6 args: - --source=ingress - --provider=digitalocean - --registry=txt - --txt-owner-id=6b32e37c - --txt-prefix=xdns- - --domain-filter=example.org env: - name: DO_TOKEN valueFrom: secretKeyRef: name: digital-ocean-token key: token
Annotate your ingress resource with
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: httpbin annotations: kubernetes.io/ingress.class: nginx external-dns.alpha.kubernetes.io/hostname: hello-world.example.org spec: rules: - host: hello-world.example.org http: paths: - path: / pathType: Prefix backend: service: name: httpbin port: number: 80
External DNS will create the following records.