Install External DNS using TMC Catalog

Reading Time: 4 mins

Overview

ExternalDNS service publishes DNS records for applications to DNS servers. This post explains how to deploy ExternalDNS into a Tanzu Kubernetes (workload) and dns zone deployed on Azure.

Pre reqs

  • Bootstrap machine with the following installed: Tanzu CLI, kubectl installed as mentioned here
  • Tanzu Kubernetes Grid management cluster and workload cluster running on vSphere, Amazon EC2, or Azure, with the package repository installed. For this demo, I have deployed TKG on Azure.
  • Registered Domain Name

Note: For this demo, I have used a domain (captainvirtualization.in) registered with Godaddy and created dns zone in Azure as shown below:

Install AZ CLI

  • Follow the steps given here to install AZ CLI on your bootstrap machine.

Prepare setup in Azure

az login

az account set -s SUBSCRIPTION-ID-GUID
  • In Azure portal: Navigate to Home > Services > Azure Active Directory > App registrations > + New Registration
  • Provide a name and click Register

Note the Application ID, Tenant ID from the registered service principal

 

# Retrieve the ID of the resource group

#Syntax: az group show --name RESOURCE-GROUP --query id

#Example:  az group show --name images-rg --query id
"/subscriptions/827ba436b-aa9b-45d645395244/resourceGroups/images-rg"

# Assign the reader role to the service principal for the resource group scope

# Syntax: az role assignment create --role "Reader" --assignee APP-ID-GUID --scope RESOURCE-GROUP-RESOURCE-ID

# Example:  az role assignment create --role "Reader" --assignee 8d65aec8-96f7-45a3-a349-eac3d722de0c --scope /subscriptions/-f0b2-4e6b-aa9b-45d645395244/resourceGroups/images-rg
{
  "canDelegate": null,
  "id": "/subscriptions/-f0b2-4e6b-aa9b-45d645395244/resourceGroups/images-rg/providers/Microsoft.Authorization/roleAssignments/a435e88c-e1cb-4bc8-8810-03dfb37a3e88",
  "name": "a435e88c-e1cb-4bc8-8810-03dfb37a3e88",
  "principalId": "-c1fa-4a91-a58f-2641136f108d",
  "principalType": "ServicePrincipal",
  "resourceGroup": "images-rg",
  "roleDefinitionId": "/subscriptions/-f0b2-4e6b-aa9b-45d645395244/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7",
  "scope": "/subscriptions/-f0b2-4e6b-aa9b-444/resourceGroups/images-rg",
  "type": "Microsoft.Authorization/roleAssignments"
}


# Syntax:  az network dns zone show --name DNS-ZONE-NAME -g RESOURCE-GROUP-NAME --query id

# Syntax:  az role assignment create --role "Contributor" --assignee APP-ID-GUID --scope DNS-ZONE-RESOURCE-ID

# Example: az network dns zone show --name captainvirtualization.in -g images-rg --query id
"/subscriptions/0b2-4e6b-aa9b-45244/resourceGroups/images-rg/providers/Microsoft.Network/dnszones/captainvirtualization.in"
  • To connect the ExternalDNS service to the Azure DNS service, you create a configuration file named azure.json with content like shown below:
{
 "tenantId": "01234abc-de56-ff78-abc1-234567890def",
 "subscriptionId": "01234abc-de56-ff78-abc1-234567890def",
 "resourceGroup": "MyDnsResourceGroup",
 "aadClientId": "01234abc-de56-ff78-abc1-234567890def",
 "aadClientSecret": "uKiuXeiwui4jo9quae9o"
}

#### Don't include this #######
# To retrieve tenantId, you can run the az account show --query "tenantId" command.

# To retrieve subscriptionId, you can run the az account show --query "id" command.

# ResourceGroup is the name of the resource group that your DNS zone is within.
 
# aadClientId is the appId collected after creating the service principal. 

#aadClientSecret can created by navigating to Azure portal > Azure Active Directory > App registrations > Click on newly created service principal (capv-demo in this case) > certificated & Secrets > + New client secret 
# Get the admin credentials of the workload cluster into which you want to deploy External-DNS. In this case, capv-workload is workload cluster: 

$ tanzu cluster kubeconfig get capv-workload --admin

# Set the context of kubectl to the cluster

$ kubectl config use-context capv-workload-admin@capv-workload

# Create Namespace

$ kubectl create ns tanzu-system-service-discovery 
namespace/tanzu-system-service-discovery created

# Create secret
$ kubectl -n tanzu-system-service-discovery create secret generic azure-config-file --from-file=azure.json 
secret/azure-config-file created

Install the package

In TMC Console: Catalog > select the workload cluster (capv-workload in my case)  from drop down and click on external-dns

  • Click on Install Package which can be found on top right side of the page

  • Name the Installed package as : capv-workload-extdns and click NEXT

  • Package install resources: Leave to Default and click NEXT
  • Configure values: Provide below values after changing domain-filter and resource-group
# Deployment-related configuration.
namespace: tanzu-system-service-discovery
deployment:
 args:
   - --source=service
   - --source=ingress
   - --source=contour-httpproxy 
   - --domain-filter=captainvirtualization.in  ## To be Changed
   - --policy=upsert-only 
   - --registry=txt
   - --txt-prefix=externaldns- 
   - --provider=azure
   - --azure-resource-group=images-rg  ## To be Changed
 env: []
 securityContext: {}
 volumeMounts:
   - name: azure-config-file
     mountPath: /etc/kubernetes
     readOnly: true
 volumes:
   - name: azure-config-file
     secret:
       secretName: azure-config-file

  • Install Package

Validate

In TMC Console: Clusters > capv-workload > Add-ons > Installed > check if the package ( external-dns.tanzu.vmware.com ) is succeeded and healthy

Verify the pod status
# Validate the pods

kubectl get pods -n tanzu-system-service-discovery 
NAME                            READY   STATUS    RESTARTS   AGE
external-dns-646dbd7c96-kfvhb   1/1     Running   0          4m14s
  • Now, lets test the external-dns:
    • Create a yaml with below config to create a Service and Deployment
apiVersion: v1
kind: Service
metadata:
  name: nginx
  annotations:
    external-dns.alpha.kubernetes.io/hostname: nginx.captainvirtualization.in  ## Change me
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  type: LoadBalancer
  selector:
    app: nginx

---
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
              name: http
Service
# Get the external IP of service

kubectl get svc --kubeconfig ~/.kube/config-tkg
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)        AGE
kubernetes   ClusterIP      100.64.0.1      <none>         443/TCP        2d1h
nginx        LoadBalancer   100.69.57.234   20.207.97.64   80:31455/TCP   3m33s
logs
## Validate the logs and it should show a message "updating a record"

$ kubectl logs external-dns-646dbd7c96-kfvhb -n tanzu-system-service-discovery

time="2022-03-17T13:38:12Z" level=info msg="Updating A record named 'nginx' to '20.207.97.64' for Azure DNS zone 'captainvirtualization.in'."
time="2022-03-17T13:38:13Z" level=info msg="Updating TXT record named 'externaldns-nginx' to '\"heritage=external-dns,external-dns/owner=default,external-dns/resource=service/default/nginx\"' for Azure DNS zone 'captainvirtualization.in'."
  • DNS record should be automatically created as shown below:

  • Access the hostname in browser and it should load nginx page as shown below:

This confirms that external-dns is working as expected as the DNS records are created automatically in DNS.