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.