Skip to content

Setting up ExternalDNS for Services on UltraDNS

This tutorial describes how to setup ExternalDNS for usage within a Kubernetes cluster using UltraDNS.

For this tutorial, please make sure that you are using a version > 0.7.2 of ExternalDNS.

Managing DNS with UltraDNS

If you would like to read-up on the UltraDNS service, you can find additional details here: Introduction to UltraDNS

Before proceeding, please create a new DNS Zone that you will create your records in for this tutorial process. For the examples in this tutorial, we will be using example.com as our Zone.

Setting Up UltraDNS Credentials

The following environment variables will be needed to run ExternalDNS with UltraDNS.

ULTRADNS_USERNAME,ULTRADNS_PASSWORD, &ULTRADNS_BASEURL
ULTRADNS_ACCOUNTNAME(optional variable).

Deploying ExternalDNS

Connect your kubectl client to the cluster you want to test ExternalDNS with.
Then, apply one of the following manifests file to deploy ExternalDNS.

  • Note: We are assuming the zone is already present within UltraDNS.
  • Note: While creating CNAMES as target endpoints, the --txt-prefix option is mandatory.

Manifest (for clusters without RBAC enabled)

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:
      containers:
      - name: external-dns
        image: registry.k8s.io/external-dns/external-dns:v0.14.2
        args:
        - --source=service 
        - --source=ingress # ingress is also possible
        - --domain-filter=example.com # (Recommended) We recommend to use this filter as it minimize the time to propagate changes, as there are less number of zones to look into..
        - --provider=ultradns
        - --txt-prefix=txt-
        env:
        - name: ULTRADNS_USERNAME
          value: ""
        - name: ULTRADNS_PASSWORD  # The password is required to be BASE64 encrypted.
          value: ""
        - name: ULTRADNS_BASEURL
          value: "https://api.ultradns.com/"
        - name: ULTRADNS_ACCOUNTNAME
          value: ""

Manifest (for clusters with RBAC enabled)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: 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"]
  resources: ["ingresses"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list","watch"]
---
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: 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: registry.k8s.io/external-dns/external-dns:v0.14.2
        args:
        - --source=service 
        - --source=ingress
        - --domain-filter=example.com #(Recommended) We recommend to use this filter as it minimize the time to propagate changes, as there are less number of zones to look into..
        - --provider=ultradns
        - --txt-prefix=txt-
        env:
        - name: ULTRADNS_USERNAME
          value: ""
        - name: ULTRADNS_PASSWORD # The password is required to be BASE64 encrypted.
          value: ""
        - name: ULTRADNS_BASEURL
          value: "https://api.ultradns.com/"
        - name: ULTRADNS_ACCOUNTNAME
          value: ""

Deploying an Nginx Service

Create a service file called ‘nginx.yaml’ with the following contents:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
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
  annotations:
    external-dns.alpha.kubernetes.io/hostname: my-app.example.com.
spec:
  selector:
    app: nginx
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

Please note the annotation on the service. Use the same hostname as the UltraDNS zone created above.

ExternalDNS uses this annotation to determine what services should be registered with DNS. Removing the annotation will cause ExternalDNS to remove the corresponding DNS records.

Creating the Deployment and Service:

$ kubectl create -f nginx.yaml
$ kubectl create -f external-dns.yaml

Depending on where you run your service from, it can take a few minutes for your cloud provider to create an external IP for the service.

Once the service has an external IP assigned, ExternalDNS will notice the new service IP address and will synchronize the UltraDNS records.

Verifying UltraDNS Records

Please verify on the UltraDNS UI that the records are created under the zone “example.com”.

For more information on UltraDNS UI, refer to (https://docs.ultradns.com/Content/MSP_User_Guide/Content/User%20Guides/MSP_User_Guide/Navigation/Moving%20Around%20the%20UI.htm#_Toc2780722).

Select the zone that was created above (or select the appropriate zone if a different zone was used.)

The external IP address will be displayed as a CNAME record for your zone.

Cleaning Up the Deployment and Service

Now that we have verified that ExternalDNS will automatically manage your UltraDNS records, you can delete example zones that you created in this tutorial:

$ kubectl delete service -f nginx.yaml
$ kubectl delete service -f externaldns.yaml

Examples to Manage your Records

Creating Multiple A Records Target

  • First, you want to create a service file called ‘apple-banana-echo.yaml’
    ---
    kind: Pod
    apiVersion: v1
    metadata:
      name: example-app
      labels:
        app: apple
    spec:
      containers:
        - name: example-app
          image: hashicorp/http-echo
          args:
            - "-text=apple"
    ---
    kind: Service
    apiVersion: v1
    metadata:
      name: example-service
    spec:
      selector:
        app: apple
      ports:
        - port: 5678 # Default port for image
    
  • Then, create service file called ‘expose-apple-banana-app.yaml’ to expose the services. For more information to deploy ingress controller, refer to (https://kubernetes.github.io/ingress-nginx/deploy/)
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: example-ingress
      annotations:
        ingress.kubernetes.io/rewrite-target: /
        ingress.kubernetes.io/scheme: internet-facing
        external-dns.alpha.kubernetes.io/hostname: apple.example.com.
        external-dns.alpha.kubernetes.io/target: 10.10.10.1,10.10.10.23
    spec:
      rules:
      - http:
          paths:
            - path: /apple
              pathType: Prefix
              backend:
                service:
                  name: example-service
                  port:
                    number: 5678
    
  • Then, create the deployment and service:
    $ kubectl create -f apple-banana-echo.yaml
    $ kubectl create -f expose-apple-banana-app.yaml
    $ kubectl create -f external-dns.yaml
    
  • Depending on where you run your service from, it can take a few minutes for your cloud provider to create an external IP for the service.
  • Please verify on the UltraDNS UI that the records have been created under the zone “example.com”.
  • Finally, you will need to clean up the deployment and service. Please verify on the UI afterwards that the records have been deleted from the zone “example.com”:
    $ kubectl delete -f apple-banana-echo.yaml
    $ kubectl delete -f expose-apple-banana-app.yaml
    $ kubectl delete -f external-dns.yaml
    

Creating CNAME Record

  • Please note, that prior to deploying the external-dns service, you will need to add the option –txt-prefix=txt- into external-dns.yaml. If this not provided, your records will not be created.
  • First, create a service file called ‘apple-banana-echo.yaml’
    • Config File Example – kubernetes cluster is on-premise not on cloud
      ---
      kind: Pod
      apiVersion: v1
      metadata:
        name: example-app
        labels:
          app: apple
      spec:
        containers:
          - name: example-app
            image: hashicorp/http-echo
            args:
              - "-text=apple"
      ---
      kind: Service
      apiVersion: v1
      metadata:
        name: example-service
      spec:
        selector:
          app: apple
        ports:
          - port: 5678 # Default port for image
      ---
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: example-ingress
        annotations:
          ingress.kubernetes.io/rewrite-target: /
          ingress.kubernetes.io/scheme: internet-facing
          external-dns.alpha.kubernetes.io/hostname: apple.example.com.
          external-dns.alpha.kubernetes.io/target: apple.cname.com.
      spec:
        rules:
        - http:
            paths:
              - path: /apple
                backend:
                  service:
                    name: example-service
                    port:
                      number: 5678
      
    • Config File Example – Kubernetes cluster service from different cloud vendors
      ---
      kind: Pod
      apiVersion: v1
      metadata:
        name: example-app
        labels:
          app: apple
      spec:
        containers:
          - name: example-app
            image: hashicorp/http-echo
            args:
              - "-text=apple"
      ---
      kind: Service
      apiVersion: v1
      metadata:
        name: example-service
        annotations:
          external-dns.alpha.kubernetes.io/hostname: my-app.example.com.
      spec:
        selector:
          app: apple
        type: LoadBalancer
        ports:
          - protocol: TCP
            port: 5678
            targetPort: 5678
      
  • Then, create the deployment and service:
    $ kubectl create -f apple-banana-echo.yaml
    $ kubectl create -f external-dns.yaml
    
  • Depending on where you run your service from, it can take a few minutes for your cloud provider to create an external IP for the service.
  • Please verify on the UltraDNS UI, that the records have been created under the zone “example.com”.
  • Finally, you will need to clean up the deployment and service. Please verify on the UI afterwards that the records have been deleted from the zone “example.com”:
    $ kubectl delete -f apple-banana-echo.yaml
    $ kubectl delete -f external-dns.yaml
    

Creating Multiple Types Of Records

  • Please note, that prior to deploying the external-dns service, you will need to add the option –txt-prefix=txt- into external-dns.yaml. Since you will also be created a CNAME record, If this not provided, your records will not be created.
  • First, create a service file called ‘apple-banana-echo.yaml’
    • Config File Example – kubernetes cluster is on-premise not on cloud
      ---
      kind: Pod
      apiVersion: v1
      metadata:
        name: example-app
        labels:
          app: apple
      spec:
        containers:
          - name: example-app
            image: hashicorp/http-echo
            args:
              - "-text=apple"
      ---
      kind: Service
      apiVersion: v1
      metadata:
        name: example-service
      spec:
        selector:
          app: apple
        ports:
          - port: 5678 # Default port for image
      ---
      kind: Pod
      apiVersion: v1
      metadata:
        name: example-app1
        labels:
          app: apple1
      spec:
        containers:
          - name: example-app1
            image: hashicorp/http-echo
            args:
              - "-text=apple"
      ---
      kind: Service
      apiVersion: v1
      metadata:
        name: example-service1
      spec:
        selector:
          app: apple1
        ports:
          - port: 5679 # Default port for image
      ---
      kind: Pod
      apiVersion: v1
      metadata:
        name: example-app2
        labels:
          app: apple2
      spec:
        containers:
          - name: example-app2
            image: hashicorp/http-echo
            args:
              - "-text=apple"
      ---
      kind: Service
      apiVersion: v1
      metadata:
        name: example-service2
      spec:
        selector:
          app: apple2
        ports:
          - port: 5680 # Default port for image
      ---
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: example-ingress
        annotations:
          ingress.kubernetes.io/rewrite-target: /
          ingress.kubernetes.io/scheme: internet-facing
          external-dns.alpha.kubernetes.io/hostname: apple.example.com.
          external-dns.alpha.kubernetes.io/target: apple.cname.com.
      spec:
        rules:
        - http:
            paths:
              - path: /apple
                backend:
                  service:
                    name: example-service
                    port:
                      number: 5678
      ---
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: example-ingress1
        annotations:
          ingress.kubernetes.io/rewrite-target: /
          ingress.kubernetes.io/scheme: internet-facing
          external-dns.alpha.kubernetes.io/hostname: apple-banana.example.com.
          external-dns.alpha.kubernetes.io/target: 10.10.10.3
      spec:
        rules:
        - http:
            paths:
              - path: /apple
                backend:
                  service:
                    name: example-service1
                    port:
                      number: 5679
      ---
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: example-ingress2
        annotations:
          ingress.kubernetes.io/rewrite-target: /
          ingress.kubernetes.io/scheme: internet-facing
          external-dns.alpha.kubernetes.io/hostname: banana.example.com.
          external-dns.alpha.kubernetes.io/target: 10.10.10.3,10.10.10.20
      spec:
        rules:
        - http:
            paths:
              - path: /apple
                backend:
                  service:
                    name: example-service2
                    port:
                      number: 5680
      
    • Config File Example – Kubernetes cluster service from different cloud vendors
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nginx
      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
        annotations:
          external-dns.alpha.kubernetes.io/hostname: my-app.example.com.
      spec:
        selector:
          app: nginx
        type: LoadBalancer
        ports:
          - protocol: TCP
            port: 80
            targetPort: 80
      ---
      kind: Pod
      apiVersion: v1
      metadata:
        name: example-app
        labels:
          app: apple
      spec:
        containers:
          - name: example-app
            image: hashicorp/http-echo
            args:
              - "-text=apple"
      ---
      kind: Service
      apiVersion: v1
      metadata:
        name: example-service
      spec:
        selector:
          app: apple
        ports:
          - port: 5678 # Default port for image
      ---
      kind: Pod
      apiVersion: v1
      metadata:
        name: example-app1
        labels:
          app: apple1
      spec:
        containers:
          - name: example-app1
            image: hashicorp/http-echo
            args:
              - "-text=apple"
      ---
      apiVersion: extensions/v1beta1
      kind: Service
      apiVersion: v1
      metadata:
        name: example-service1
      spec:
        selector:
          app: apple1
        ports:
          - port: 5679 # Default port for image
      ---
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: example-ingress
        annotations:
          ingress.kubernetes.io/rewrite-target: /
          ingress.kubernetes.io/scheme: internet-facing
          external-dns.alpha.kubernetes.io/hostname: apple.example.com.
          external-dns.alpha.kubernetes.io/target: 10.10.10.3,10.10.10.25
      spec:
        rules:
        - http:
            paths:
              - path: /apple
                backend:
                  service:
                    name: example-service
                    port:
                      number: 5678
      ---
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: example-ingress1
        annotations:
          ingress.kubernetes.io/rewrite-target: /
          ingress.kubernetes.io/scheme: internet-facing
          external-dns.alpha.kubernetes.io/hostname: apple-banana.example.com.
          external-dns.alpha.kubernetes.io/target: 10.10.10.3
      spec:
        rules:
        - http:
            paths:
              - path: /apple
                backend:
                  service:
                    name: example-service1
                    port:
                      number: 5679
      
  • Then, create the deployment and service:
    $ kubectl create -f apple-banana-echo.yaml
    $ kubectl create -f external-dns.yaml
    
  • Depending on where you run your service from, it can take a few minutes for your cloud provider to create an external IP for the service.
  • Please verify on the UltraDNS UI, that the records have been created under the zone “example.com”.
  • Finally, you will need to clean up the deployment and service. Please verify on the UI afterwards that the records have been deleted from the zone “example.com”:
    console $ kubectl delete -f apple-banana-echo.yaml $ kubectl delete -f external-dns.yaml