|
| 1 | +# Kubernetes ExternalDNS to create Record Sets in Azure DNS from AKS |
| 2 | + |
| 3 | +## Step-01: Introduction |
| 4 | +- Create External DNS Manifest |
| 5 | +- Provide Access to DNZ Zones using **Azure Managed Service Identity** for External DNS pod to create **Record Sets** in Azure DNS Zones |
| 6 | +- Review Application & Ingress Manifests |
| 7 | +- Deploy and Test |
| 8 | +[](https://www.udemy.com/course/aws-eks-kubernetes-masterclass-devops-microservices/?referralCode=257C9AD5B5AF8D12D1E1) |
| 9 | + |
| 10 | +## Step-02: Create External DNS Manifests |
| 11 | +- External-DNS needs permissions to Azure DNS to modify (Add, Update, Delete DNS Record Sets) |
| 12 | +- We can provide permissions to External-DNS pod in two ways in Azure |
| 13 | + - Using Azure Service Principal |
| 14 | + - Using Azure Managed Service Identity (MSI) |
| 15 | +- We are going to use `MSI` for providing necessary permissions here which is latest and greatest in Azure as on today. |
| 16 | + |
| 17 | + |
| 18 | +### Gather Information Required for azure.json file |
| 19 | +```t |
| 20 | +# To get Azure Tenant ID |
| 21 | +az account show --query "tenantId" |
| 22 | + |
| 23 | +# To get Azure Subscription ID |
| 24 | +az account show --query "id" |
| 25 | +``` |
| 26 | + |
| 27 | +### Create azure.json file |
| 28 | +```json |
| 29 | +{ |
| 30 | + "tenantId": "c81f465b-99f9-42d3-a169-8082d61c677a", |
| 31 | + "subscriptionId": "82808767-144c-4c66-a320-b30791668b0a", |
| 32 | + "resourceGroup": "dns-zones", |
| 33 | + "useManagedIdentityExtension": true, |
| 34 | + "userAssignedIdentityID": "404b0cc1-ba04-4933-bcea-7d002d184436" |
| 35 | +} |
| 36 | +``` |
| 37 | + |
| 38 | +### Review external-dns.yml manifest |
| 39 | +```yaml |
| 40 | +apiVersion: v1 |
| 41 | +kind: ServiceAccount |
| 42 | +metadata: |
| 43 | + name: external-dns |
| 44 | +--- |
| 45 | +apiVersion: rbac.authorization.k8s.io/v1 |
| 46 | +kind: ClusterRole |
| 47 | +metadata: |
| 48 | + name: external-dns |
| 49 | +rules: |
| 50 | +- apiGroups: [""] |
| 51 | + resources: ["services","endpoints","pods", "nodes"] |
| 52 | + verbs: ["get","watch","list"] |
| 53 | +- apiGroups: ["extensions","networking.k8s.io"] |
| 54 | + resources: ["ingresses"] |
| 55 | + verbs: ["get","watch","list"] |
| 56 | +- apiGroups: [""] |
| 57 | + resources: ["nodes"] |
| 58 | + verbs: ["list"] |
| 59 | +--- |
| 60 | +apiVersion: rbac.authorization.k8s.io/v1 |
| 61 | +kind: ClusterRoleBinding |
| 62 | +metadata: |
| 63 | + name: external-dns-viewer |
| 64 | +roleRef: |
| 65 | + apiGroup: rbac.authorization.k8s.io |
| 66 | + kind: ClusterRole |
| 67 | + name: external-dns |
| 68 | +subjects: |
| 69 | +- kind: ServiceAccount |
| 70 | + name: external-dns |
| 71 | + namespace: default |
| 72 | +--- |
| 73 | +apiVersion: apps/v1 |
| 74 | +kind: Deployment |
| 75 | +metadata: |
| 76 | + name: external-dns |
| 77 | +spec: |
| 78 | + strategy: |
| 79 | + type: Recreate |
| 80 | + selector: |
| 81 | + matchLabels: |
| 82 | + app: external-dns |
| 83 | + template: |
| 84 | + metadata: |
| 85 | + labels: |
| 86 | + app: external-dns |
| 87 | + spec: |
| 88 | + serviceAccountName: external-dns |
| 89 | + containers: |
| 90 | + - name: external-dns |
| 91 | + image: k8s.gcr.io/external-dns/external-dns:v0.11.0 |
| 92 | + args: |
| 93 | + - --source=service |
| 94 | + - --source=ingress |
| 95 | + #- --domain-filter=example.com # (optional) limit to only example.com domains; change to match the zone created above. |
| 96 | + - --provider=azure |
| 97 | + #- --azure-resource-group=externaldns # (optional) use the DNS zones from the specific resource group |
| 98 | + volumeMounts: |
| 99 | + - name: azure-config-file |
| 100 | + mountPath: /etc/kubernetes |
| 101 | + readOnly: true |
| 102 | + volumes: |
| 103 | + - name: azure-config-file |
| 104 | + secret: |
| 105 | + secretName: azure-config-file |
| 106 | +``` |
| 107 | +
|
| 108 | +## Step-03: Create MSI - Managed Service Identity for External DNS to access Azure DNS Zones |
| 109 | +
|
| 110 | +### Create Manged Service Identity (MSI) |
| 111 | +- Go to All Services -> Managed Identities -> Add |
| 112 | +- Resource Name: aksdemo1-externaldns-access-to-dnszones |
| 113 | +- Subscription: Pay-as-you-go |
| 114 | +- Resource group: aks-rg1 |
| 115 | +- Location: Central US |
| 116 | +- Click on **Create** |
| 117 | +
|
| 118 | +### Add Azure Role Assignment in MSI |
| 119 | +- Opem MSI -> aksdemo1-externaldns-access-to-dnszones |
| 120 | +- Click on **Azure Role Assignments** -> **Add role assignment** |
| 121 | +- Scope: Resource group |
| 122 | +- Subscription: Pay-as-you-go |
| 123 | +- Resource group: dns-zones |
| 124 | +- Role: Contributor |
| 125 | +
|
| 126 | +### Make a note of Client Id and update in azure.json |
| 127 | +- Go to **Overview** -> Make a note of **Client ID" |
| 128 | +- Update in **azure.json** value for **userAssignedIdentityID** |
| 129 | +``` |
| 130 | + "userAssignedIdentityID": "de836e14-b1ba-467b-aec2-93f31c027ab7" |
| 131 | +``` |
| 132 | +
|
| 133 | +## Step-04: Associate MSI in AKS Cluster VMSS |
| 134 | +- Go to All Services -> Virtual Machine Scale Sets (VMSS) -> Open aksdemo1 related VMSS (aks-agentpool-27193923-vmss) |
| 135 | +- Go to Settings -> Identity -> User assigned -> Add -> aksdemo1-externaldns-access-to-dnszones |
| 136 | +
|
| 137 | +
|
| 138 | +
|
| 139 | +## Step-05: Create Kubernetes Secret and Deploy ExternalDNS |
| 140 | +```t |
| 141 | +# Create Secret |
| 142 | +cd kube-manifests/01-ExteranlDNS |
| 143 | +kubectl create secret generic azure-config-file --from-file=azure.json |
| 144 | + |
| 145 | +# List Secrets |
| 146 | +kubectl get secrets |
| 147 | + |
| 148 | +# Deploy ExternalDNS |
| 149 | +cd kube-manifests/01-ExteranlDNS |
| 150 | +kubectl apply -f external-dns.yml |
| 151 | + |
| 152 | +# Verify ExternalDNS Logs |
| 153 | +kubectl logs -f $(kubectl get po | egrep -o 'external-dns[A-Za-z0-9-]+') |
| 154 | +``` |
| 155 | + |
| 156 | +```log |
| 157 | +# Error Type: 400 |
| 158 | +time="2020-08-24T11:25:04Z" level=error msg="azure.BearerAuthorizer#WithAuthorization: Failed to refresh the Token for request to https://management.azure.com/subscriptions/82808767-144c-4c66-a320-b30791668b0a/resourceGroups/dns-zones/providers/Microsoft.Network/dnsZones?api-version=2018-05-01: StatusCode=400 -- Original Error: adal: Refresh request failed. Status Code = '400'. Response body: {\"error\":\"invalid_request\",\"error_description\":\"Identity not found\"}" |
| 159 | +
|
| 160 | +# Error Type: 403 |
| 161 | +Notes: Error 403 will come when our Managed Service Identity dont have access to respective destination resource |
| 162 | +
|
| 163 | +# When all good, we should get log as below |
| 164 | +time="2020-08-24T11:27:59Z" level=info msg="Resolving to user assigned identity, client id is 404b0cc1-ba04-4933-bcea-7d002d184436." |
| 165 | +``` |
| 166 | + |
| 167 | + |
| 168 | +## Step-06: Deploy Application and Test |
| 169 | +- When dns record set got created in DNS Zone, the log in external-dns should look as below. |
| 170 | + |
| 171 | +### Deploy Application |
| 172 | +```t |
| 173 | +# Deploy Application |
| 174 | +kubectl apply -f kube-manifests/02-NginxApp1 |
| 175 | + |
| 176 | +# Verify Pods and Services |
| 177 | +kubectl get po,svc |
| 178 | + |
| 179 | +# Verify Ingress |
| 180 | +kubectl get ingress |
| 181 | +``` |
| 182 | + |
| 183 | +### Verify logs in External DNS Pod |
| 184 | +- Wait for 3 to 5 minutes for Record Set update in DNZ Zones |
| 185 | +```t |
| 186 | +# Verify ExternalDNS Logs |
| 187 | +kubectl logs -f $(kubectl get po | egrep -o 'external-dns[A-Za-z0-9-]+') |
| 188 | +``` |
| 189 | +- External DNS Pod Logs |
| 190 | +```log |
| 191 | +time="2020-08-24T11:30:54Z" level=info msg="Updating A record named 'eapp1' to '20.37.141.33' for Azure DNS zone 'kubeoncloud.com'." |
| 192 | +time="2020-08-24T11:30:55Z" level=info msg="Updating TXT record named 'eapp1' to '\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/default/nginxapp1-ingress-service\"' for Azure DNS zone 'kubeoncloud.com'." |
| 193 | +``` |
| 194 | + |
| 195 | +### Verify Record Set in DNZ Zones -> kubeoncloud.com |
| 196 | +- Go to All Services -> DNS Zones -> kubeoncloud.com |
| 197 | +- Verify if we have `eapp1.kubeoncloud.com` created |
| 198 | +```t |
| 199 | +# Template Command |
| 200 | +az network dns record-set a list -g <Resource-Group-dnz-zones> -z <yourdomain.com> |
| 201 | + |
| 202 | +# Replace DNS Zones Resource Group and yourdomain |
| 203 | +az network dns record-set a list -g dns-zones -z kubeoncloud.com |
| 204 | +``` |
| 205 | +- Perform `nslookup` test |
| 206 | +```t |
| 207 | +# nslookup Test |
| 208 | +Kalyans-MacBook-Pro:01-ExternalDNS kdaida$ nslookup eapp1.kubeoncloud.com |
| 209 | +Server: 192.168.0.1 |
| 210 | +Address: 192.168.0.1#53 |
| 211 | + |
| 212 | +Non-authoritative answer: |
| 213 | +Name: eapp1.kubeoncloud.com |
| 214 | +Address: 20.37.141.33 |
| 215 | + |
| 216 | +Kalyans-MacBook-Pro:01-ExternalDNS kdaida$ |
| 217 | +``` |
| 218 | + |
| 219 | +### Access Application and Test |
| 220 | +```t |
| 221 | +# Access Application |
| 222 | +http://eapp1.kubeoncloud.com |
| 223 | +http://eapp1.kubeoncloud.com/app1/index.html |
| 224 | + |
| 225 | +# Note: Replace kubeoncloud.com with your domain name |
| 226 | +``` |
| 227 | + |
| 228 | +## Step-07: Clean-Up |
| 229 | +```t |
| 230 | +# Delete Application |
| 231 | +kubectl delete -f kube-manifests/02-NginxApp1 |
| 232 | + |
| 233 | +# Verify External DNS pod to ensure record set got deleted |
| 234 | +kubectl logs -f $(kubectl get po | egrep -o 'external-dns[A-Za-z0-9-]+') |
| 235 | + |
| 236 | +# Verify Record set got automatically deleted in DNS Zones |
| 237 | +# Template Command |
| 238 | +az network dns record-set a list -g <Resource-Group-dnz-zones> -z <yourdomain.com> |
| 239 | + |
| 240 | +# Replace DNS Zones Resource Group and yourdomain |
| 241 | +az network dns record-set a list -g dns-zones -z kubeoncloud.com |
| 242 | +``` |
| 243 | + |
| 244 | +```log |
| 245 | +time="2020-08-24T12:08:52Z" level=info msg="Deleting A record named 'eapp1' for Azure DNS zone 'kubeoncloud.com'." |
| 246 | +time="2020-08-24T12:08:53Z" level=info msg="Deleting TXT record named 'eapp1' for Azure DNS zone 'kubeoncloud.com'." |
| 247 | +``` |
| 248 | + |
| 249 | +## References |
| 250 | +- https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/azure.md |
| 251 | +- Open Issue and Break fix: https://github.com/kubernetes-sigs/external-dns/issues/1548 |
| 252 | +- https://github.com/kubernetes/ingress-nginx/tree/master/charts/ingress-nginx#configuration |
| 253 | +- https://github.com/kubernetes/ingress-nginx/blob/master/charts/ingress-nginx/values.yaml |
| 254 | +- https://kubernetes.github.io/ingress-nginx/ |
| 255 | + |
| 256 | +## External DNS References |
| 257 | +- https://github.com/kubernetes-sigs/external-dns |
| 258 | +- https://github.com/kubernetes-sigs/external-dns/blob/master/docs/faq.md |
0 commit comments