Can I use external-dns and openstack designate for automatic dns?

Yes, to reduce manual effort and automate the configuration of DNS zones, you may want to use external-dns. In summary, external-dns allows you to control DNS records dynamically with Kubernetes resources in a DNS provider-agnostic way. external-dns is not a DNS server by itself, but merely configures other DNS providers (for example, OpenStack Designate, Amazon Route53, Google Cloud DNS, and so on.)

Prerequisites

To successfully complete the following steps, you need the following:

Configure Your domain to use designate

Delegate your domains from your DNS provider to the following DNS name servers so that Designate can control the DNS resources of your domain.

dns1.ddns.innovo.cloud
dns2.ddns.innovo.cloud

Create a new DNS Zone

Before you use ExternalDNS, you need to add your DNS zones to your DNS provider, in this case, Designate DNS.

In our example we use the test domain name example.foo. It is important to create the zones before starting to control the DNS resources with Kubernetes.

Note: You must include the final . at the end of the zone/domain to be created.

$ openstack zone create --email webmaster@example.foo example.foo.

Next, make sure that the zone was created successfully and the status is active.

$ openstack zone list
$ openstack zone show example.foo.

Create application credentials for external-dns

Attention: It is imported to login with your service user into your openstack project, because Application Credentials are user specific.

Visit the WebGui and go to Identity -> Application Credentials, then click on the Button + CREATE APPLICATION CREDENTIAL or create credentials via cli:

$ openstack application credential create <name_of_app_credentials>

Install external-dns into your cluster

Note: Don’t forget to change the openstack application credentials and the command line arguments in the external-dns deployment --domain-filter=example.foo and the --txt-owner-id=<owner-id>. The domain-filter is the dns zone. With the txt-owner-id external-dns can identify the entries managed by itself. You should change the image to a new version if available (and shedule updates) if you want to use it in production.

  • Namespace:
apiVersion: v1
kind: Namespace
metadata:
  name: external-dns
  • RBAC:
---
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: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
  - apiGroups: ["extensions", "networking.k8s.io"]
    resources: ["ingresses"]
    verbs: ["get", "watch", "list"]
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["watch", "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
  • Secret:
apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: designate-openstack-credentials
  namespace: external-dns
stringData:
  OS_AUTH_URL: <auth-url>
  OS_REGION_NAME: <region>
  OS_AUTH_TYPE: v3applicationcredential
  OS_APPLICATION_CREDENTIAL_ID: <appcred_id>
  OS_APPLICATION_CREDENTIAL_SECRET: <appcred_secret>
  • Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: external-dns
  namespace: external-dns
spec:
  selector:
    matchLabels:
      app: external-dns
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      serviceAccountName: external-dns
      containers:
        - args:
            - --source=service
            - --source=ingress
            - --registry=txt
            - --provider=designate
            - --domain-filter=example.foo
            - --txt-owner-id=<owner-id>
            - --log-level=debug
          envFrom:
            - secretRef:
                name: designate-openstack-credentials
          image: registry.k8s.io/external-dns/external-dns:v0.14.2
          imagePullPolicy: IfNotPresent
          name: external-dns

Annotate the service or ingress

To add the dns entry to designate the service or ingress needs to be annotated with external-dns.alpha.kubernetes.io/hostname: my-app.example.foo. For example:

apiVersion: v1
kind: Namespace
metadata:
  name: my-app
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: my-app
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: my-app
  annotations:
    external-dns.alpha.kubernetes.io/hostname: my-app.example.foo
spec:
  selector:
    app: nginx
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

DNS Lookup

Make the dns record will be looked up correct:

$ openstack recordset list example.foo.
$ dig my-app.example.foo @dns1.ddns.innovo.cloud.
$ dig my-app.example.foo @dns2.ddns.innovo.cloud.
$ dig my-app.example.foo

Further information

For further information, please have a look at: