AKS’s default DNS resolution behavior is to forward all DNS queries to the Azure DNS service.
Let’s see how to break that.
Imagine you have a Kubernetes cluster running in Azure Kubernetes Service (AKS). By default, when a pod needs to resolve a hostname (like my-internal-service.mycompany.local), AKS forwards that request to Azure DNS. This is fine for public domains, but what if you have internal DNS zones you need to resolve, or you want to use your own DNS servers for specific domains? That’s where custom DNS configuration comes in.
Here’s a common scenario: you have an on-premises Active Directory environment with its own DNS servers that manage your internal domain names. You want your AKS pods to be able to resolve hostnames within that internal domain.
To achieve this, you’ll configure AKS to use your custom DNS servers. This involves setting up a DNS service within your AKS cluster that intercepts DNS requests and forwards them to your specified custom DNS servers based on defined rules.
Let’s walk through the configuration.
First, you need a DNS server that AKS can reach. This could be an Azure Private DNS Zone, a VM running a DNS server in your VNet, or even an on-premises DNS server accessible via VPN or ExpressRoute. For this example, let’s assume you have an on-premises DNS server at 10.1.1.53 that handles mycompany.local.
The core of custom DNS in AKS is the dnsService resource. You’ll deploy this as a Kubernetes deployment and service.
Here’s a minimal deployment for a DNS proxy (like coredns or dnsmasq). We’ll use coredns for this example, as it’s the default in AKS and highly configurable.
apiVersion: apps/v1
kind: Deployment
metadata:
name: custom-dns-proxy
namespace: kube-system
spec:
replicas: 2
selector:
matchLabels:
app: custom-dns-proxy
template:
metadata:
labels:
app: custom-dns-proxy
spec:
containers:
- name: coredns
image: coredns/coredns:1.8.0 # Use a specific version
args:
- "-conf"
- "/etc/coredns/Corefile"
volumeMounts:
- name: config-volume
mountPath: /etc/coredns
volumes:
- name: config-volume
configMap:
name: custom-dns-config
items:
- key: Corefile
path: Corefile
---
apiVersion: v1
kind: Service
metadata:
name: custom-dns-service
namespace: kube-system
labels:
k8s-app: kube-dns # This label is important for AKS to pick it up
spec:
selector:
app: custom-dns-proxy
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
Next, you need to create the Corefile ConfigMap that tells coredns how to behave. This is where you specify your custom DNS servers.
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-dns-config
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . 10.1.1.53 { # Forward all other queries to your custom DNS server
force_tcp
}
cache 30
loop
reload
loadbalance
}
In this Corefile:
.:53: This is the main configuration block, specifying thatcorednslistens on port 53 for all domains (.).kubernetes cluster.local in-addr.arpa ip6.arpa: This block tellscorednsto handle DNS queries for Kubernetes internal services (cluster.local).forward . 10.1.1.53: This is the crucial part. It instructscorednsto forward all DNS queries that aren’t handled by thekubernetesplugin (i.e., not internal Kubernetes services) to the IP address10.1.1.53.force_tcpis often useful for reliable forwarding.cache 30: Caches DNS responses for 30 seconds.reload: Allowscorednsto reload its configuration without restarting.
After applying these YAMLs, you need to tell AKS to use this new DNS service. The default DNS service in AKS is kube-dns (which is typically coredns itself). By creating a service named kube-dns in the kube-system namespace with the k8s-app: kube-dns label, you’re essentially replacing the default DNS service with your custom one.
You can verify by deploying a test pod and checking its DNS resolution:
kubectl run test-dns --image=busybox:latest --restart=Never --rm -it -- sh
nslookup my-internal-service.mycompany.local
If 10.1.1.53 is reachable from your AKS cluster and correctly resolves my-internal-service.mycompany.local, your pod should receive the correct IP address.
The coredns pods you deployed will now act as the primary DNS resolver for your cluster. They’ll handle internal Kubernetes lookups and forward everything else to your specified custom DNS server.
One subtle point is the force_tcp directive in the forward plugin. While DNS is traditionally UDP-based, TCP is often preferred for forwarding to external servers, especially when dealing with larger DNS responses or when network intermediaries might drop UDP packets. It ensures more reliable resolution for those external lookups.
The next thing you’ll likely want to configure is DNS-based access control for specific domains, or even have multiple custom DNS servers for different domain suffixes.