Stage 3 · Build
DNS: The Phone Book of the Internet
Split-Horizon & CoreDNS
Internal vs external DNS, Kubernetes CoreDNS, and service discovery.
Split-Horizon DNS Concept
Split-horizon DNS (also called split DNS) serves different answers for the same domain depending on where the query originates. Internal clients get private IPs (10.x, 172.16.x). External clients get public IPs. This hides your internal infrastructure from the outside world.
| Client Location | Query to api.example.com | Answer |
|---|---|---|
| Internal (office/VPC) | 10.0.1.50 | Private IP, direct access |
| External (internet) | api.example.com | Public IP, behind load balancer |
This is critical for security. You do not want internal service IPs exposed in public DNS records. Split-horizon ensures internal traffic stays on the private network while external traffic goes through public endpoints.
Implementation Patterns
Internet User Internal User
| |
| api.example.com | api.example.com
v v
Public DNS Private DNS
(Route 53, CloudFlare) (Internal resolver)
| |
v v
Public LB (52.x.x.x) Private LB (10.0.1.50)
| |
v v
Application Servers Application ServersThe same domain name resolves to different IPs depending on which DNS server answers. The private resolver is only reachable from inside the network.
# Route 53 private hosted zone (associated with VPC)
aws route53 list-resource-record-sets \
--hosted-zone-id Z1234567890
# Route 53 public hosted zone
aws route53 list-resource-record-sets \
--hosted-zone-id Z0987654321
# Create private hosted zone
aws route53 create-hosted-zone \
--name example.com \
--caller-reference $(date +%s) \
--vpc VPCRegion=us-east-1,VPCId=vpc-abc123AWS Route 53 supports both public and private hosted zones. Private zones are associated with VPCs and only resolve from within those VPCs. You create separate records in each zone for the same domain.
CoreDNS in Kubernetes
CoreDNS is the default DNS server in Kubernetes. It provides service discovery — converting service names (my-service.my-namespace) to cluster IPs. Every pod in the cluster uses CoreDNS for DNS resolution.
# Check CoreDNS pods
kubectl -n kube-system get pods -l k8s-app=kube-dns
# Check CoreDNS ConfigMap
kubectl -n kube-system get configmap coredns -o yaml
# Test DNS resolution from a pod
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup kubernetes.default
# Check what CoreDNS is serving
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=20CoreDNS is configured via a ConfigMap. It can forward queries to external resolvers, serve internal records, and even load custom plugins. The default configuration handles Kubernetes service discovery and forwards everything else to the cluster's upstream DNS.
# Pod DNS (if enabled by cluster admin)
10-244-0-5.default.pod.cluster.local
# Service DNS
my-service.my-namespace.svc.cluster.local
# Headless service (returns all pod IPs)
my-headless.my-namespace.svc.cluster.local
# External service (ExternalName)
my-external.example.comEvery service gets a DNS entry automatically. StatefulSet pods get individual DNS names. This is the foundation of service discovery in Kubernetes — services find each other by DNS name, not IP address.
DNS-Based Service Discovery
DNS-based service discovery is the simplest pattern. Services register themselves in DNS, and clients resolve the name to find endpoints. Consul, etcd, and Kubernetes all use this pattern.
# Register a service
curl -X PUT http://localhost:8500/v1/agent/service/register \
-d '{
"ID": "api-1",
"Name": "api",
"Tags": ["v2"],
"Address": "10.0.1.50",
"Port": 8080
}'
# Discover services via DNS
dig @127.0.0.1 -p 8600 api.service.consul SRV
# Discover with health filter
dig @127.0.0.1 -p 8600 api.service.consul SRV +bboxConsul provides both DNS and HTTP interfaces for service discovery. The SRV query returns port numbers and weights. The +bbox flag filters for healthy services only.
Private DNS Zones
# AWS Private Hosted Zone
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "api.internal.example.com",
"Type": "A",
"TTL": 300,
"ResourceRecords": [{"Value": "10.0.1.50"}]
}
}]
}'
# GCP Private DNS zone
gdns managed-zones create my-private-zone \
--dns-name="internal.example.com." \
--visibility=private \
--networks=main-vpcCloud providers give you separate public and private DNS zones. Private zones are only accessible from within the specified VPC or network. This is the cloud-native way to implement split-horizon DNS.
Every service discovery system ultimately uses DNS. Even service meshes like Istio and Linkerd use DNS as the entry point for traffic routing. Understanding DNS-based discovery is understanding the foundation of modern microservices networking.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.