After setting up a LoadBalancer and Ingress in my previous post I'm able to deploy a website successfully. But I have to enter the IP of the LoadBalancer to access the site. Not unlike you would do with a classical setup, there is DNS. Yes we can write DNS entries for all sites we want to host on the cluster. There are even pretty practical (web) user interfaces to do that.

But I want to get even further and rather not write DNS entries myself, but let Kubernetes configure it based on what Ingress resources I deploy.

Thanks to the folks at https://github.com/kubernetes-sigs/external-dns there are several integrations/providers available to let Kubernetes automatically configure DNS entries, based on Services/Ingress resources/annotations.

My initial thought was to do everything on my own, using the CoreDNS provider and configuring an ETCD and CoreDNS server to implement a DNS service. Still I would need a secondary DNS service to act as secondary DNS, since this is recommended when having a DNS service. I used https://www.buddyns.com/ so far and was very happy with the service!

But the status “alpha” of that provider has a reason. It is pretty unstable, but served DNS entries for Ingress resources I deployed…. sometimes. Having to use a ClusterIP in the config, since Kubernetes DNS resolution doesn't work on a CoreDNS container for a good reason, it isn't robust to redeploys of the ETCD service too. I might revisit that solution in the future, but for now it is too unstable to rely on.

One interesting solution is the Cloudflare DNS provider. Cloudflare provides an authoritative DNS service free of charge for personal blogs or websites like mine. And that provider is in “beta” state and first tests, showed it was much more reliable than the CoreDNS provider.

Create Cloudflare account and add first domain

First you need to create a Cloudflare account and add your first domain to the DNS editor: https://support.cloudflare.com/hc/en-us/articles/201720164-Step-2-Create-a-Cloudflare-account-and-add-a-website

Cloudflare will try to automatically retrieve your existing DNS configuration. You can safely ignore that, since we will create new entries with Kubernetes anyway. If any entries are “imported” or “proxied” you should remove all names, which you want to configure with Kubernetes.

Configure Cloudflare dns for your domain

You'll have to configure the Cloudflare DNS servers (shown in your dash on cloudflare.com under DNS) on your domains registrar in order to setup completely. Cloudflare will try to help you with that.

You can skip this step until you're sure you are setup.

Create Cloudflare API token

The service does need an access token to edit the DNS entries on your behalf. Please create a new API token on https://dash.cloudflare.com/profile/api-tokens. But only give it following permissions:

Permissions
Zone Zone Read
Zone DNS Edit

write down that token, since it will only be displayed once! We will need that very soon!

Deploy the External DNS controller

We can finally deploy the External DNS controller. I will enable automatic configuration of Ingress and Services with the right annotations. This differs from the official documentation sample.

Create a namespace for the DNS controller

kubectl create ns external-dns

Deploy the controller with RBAC enabled. You will need the API token for that (right at the bottom).

cat <<EOF | kubectl apply -f-
apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
  namespace: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: external-dns
  namespace: external-dns
rules:
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions"] 
  resources: ["ingresses"] 
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["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: external-dns
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
  namespace: 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: eu.gcr.io/k8s-artifacts-prod/external-dns/external-dns:v0.5.18
        args:
        - --source=ingress
        - --source=service
        - --provider=cloudflare
        env:
        - name: CF_API_TOKEN
          value: "<your-cloudflare-api-token-goes-here>"
EOF

Now whenever you deploy a Ingress resource with a host key or a Service with the external-dns.alpha.kubernetes.io/hostname=nginx.example.org annotation (replace nginx.example.org with a real value) it will create a DNS entry for it.

What's next?

You may ask yourself what's next? I want to enable the cluster to automatically issue Let's Encrypt certificates for each domain I deploy, so stay tuned!