Multi-Region Setup Example
Geographic distribution for global DNS resilience and performance.
Overview
This example demonstrates:
- Primary instances in multiple regions
- Secondary instances for redundancy
- Zone replication across regions
- Anycast for geographic load balancing
- Cross-region monitoring
Architecture
┌────────────────────────────────────────────────────────────────────┐
│ Global DNS Infrastructure │
└────────────────────────────────────────────────────────────────────┘
Region 1: us-east-1 Region 2: us-west-2 Region 3: eu-west-1
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ Primary Instances │ │ Secondary Instances │ │ Secondary Instances │
│ │ │ │ │ │
│ ┌────┐ ┌────┐ │◄─────┤ ┌────┐ ┌────┐ │◄────┤ ┌────┐ ┌────┐ │
│ │Pod1│ │Pod2│ │ AXFR │ │Pod1│ │Pod2│ │AXFR │ │Pod1│ │Pod2│ │
│ └────┘ └────┘ │ │ └────┘ └────┘ │ │ └────┘ └────┘ │
│ │ │ │ │ │
│ DNSSEC: Enabled │ │ DNSSEC: Verify │ │ DNSSEC: Verify │
│ Replicas: 2 │ │ Replicas: 2 │ │ Replicas: 2 │
└─────────────────────┘ └─────────────────────┘ └─────────────────────┘
│ │ │
└────────────────────────────┴────────────────────────────┘
│
Anycast IP: 192.0.2.1
(Routes to nearest region)
Region 1: us-east-1 (Primary)
Save as region-us-east-1.yaml:
---
# Namespace
apiVersion: v1
kind: Namespace
metadata:
name: dns-system
labels:
region: us-east-1
role: primary
---
# Primary Bind9Instance
apiVersion: bindy.firestoned.io/v1alpha1
kind: Bind9Instance
metadata:
name: primary-us-east-1
namespace: dns-system
labels:
app: bindy
dns-role: primary
region: us-east-1
environment: production
spec:
replicas: 2
version: "9.18"
config:
recursion: false
allowQuery:
- "0.0.0.0/0"
allowTransfer:
- "10.1.0.0/16" # us-west-2 CIDR
- "10.2.0.0/16" # eu-west-1 CIDR
dnssec:
enabled: true
validation: false
listenOn:
- "any"
listenOnV6:
- "any"
---
# PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: primary-dns-pdb
namespace: dns-system
spec:
minAvailable: 1
selector:
matchLabels:
dns-role: primary
region: us-east-1
---
# Primary DNSZone
apiVersion: bindy.firestoned.io/v1alpha1
kind: DNSZone
metadata:
name: example-com-primary
namespace: dns-system
spec:
zoneName: "example.com"
zoneType: "primary"
instanceSelector:
matchLabels:
dns-role: primary
region: us-east-1
soaRecord:
primaryNs: "ns1.us-east-1.example.com."
adminEmail: "dns-admin@example.com"
serial: 2024010101
refresh: 900
retry: 300
expire: 604800
negativeTtl: 300
ttl: 300
---
# Nameserver Records
apiVersion: bindy.firestoned.io/v1alpha1
kind: ARecord
metadata:
name: ns1-us-east-1
namespace: dns-system
spec:
zone: "example-com-primary"
name: "ns1.us-east-1"
ipv4Address: "192.0.2.1"
ttl: 86400
---
apiVersion: bindy.firestoned.io/v1alpha1
kind: ARecord
metadata:
name: ns2-us-west-2
namespace: dns-system
spec:
zone: "example-com-primary"
name: "ns2.us-west-2"
ipv4Address: "192.0.2.2"
ttl: 86400
---
apiVersion: bindy.firestoned.io/v1alpha1
kind: ARecord
metadata:
name: ns3-eu-west-1
namespace: dns-system
spec:
zone: "example-com-primary"
name: "ns3.eu-west-1"
ipv4Address: "192.0.2.3"
ttl: 86400
---
# Regional Web Servers
apiVersion: bindy.firestoned.io/v1alpha1
kind: ARecord
metadata:
name: www-us-east-1
namespace: dns-system
spec:
zone: "example-com-primary"
name: "www.us-east-1"
ipv4Address: "192.0.2.10"
ttl: 60
---
apiVersion: bindy.firestoned.io/v1alpha1
kind: ARecord
metadata:
name: www-us-west-2
namespace: dns-system
spec:
zone: "example-com-primary"
name: "www.us-west-2"
ipv4Address: "192.0.2.20"
ttl: 60
---
apiVersion: bindy.firestoned.io/v1alpha1
kind: ARecord
metadata:
name: www-eu-west-1
namespace: dns-system
spec:
zone: "example-com-primary"
name: "www.eu-west-1"
ipv4Address: "192.0.2.30"
ttl: 60
---
# GeoDNS using SRV records for service discovery
apiVersion: bindy.firestoned.io/v1alpha1
kind: SRVRecord
metadata:
name: srv-web-us-east
namespace: dns-system
spec:
zone: "example-com-primary"
name: "_http._tcp.us-east-1"
priority: 10
weight: 100
port: 80
target: "www.us-east-1.example.com."
ttl: 300
Region 2: us-west-2 (Secondary)
Save as region-us-west-2.yaml:
---
# Namespace
apiVersion: v1
kind: Namespace
metadata:
name: dns-system
labels:
region: us-west-2
role: secondary
---
# Secondary Bind9Instance
apiVersion: bindy.firestoned.io/v1alpha1
kind: Bind9Instance
metadata:
name: secondary-us-west-2
namespace: dns-system
labels:
app: bindy
dns-role: secondary
region: us-west-2
environment: production
spec:
replicas: 2
version: "9.18"
config:
recursion: false
allowQuery:
- "0.0.0.0/0"
dnssec:
enabled: false
validation: true
listenOn:
- "any"
listenOnV6:
- "any"
---
# PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: secondary-dns-pdb
namespace: dns-system
spec:
minAvailable: 1
selector:
matchLabels:
dns-role: secondary
region: us-west-2
---
# Secondary DNSZone
apiVersion: bindy.firestoned.io/v1alpha1
kind: DNSZone
metadata:
name: example-com-secondary
namespace: dns-system
spec:
zoneName: "example.com"
zoneType: "secondary"
instanceSelector:
matchLabels:
dns-role: secondary
region: us-west-2
secondaryConfig:
primaryServers:
- "192.0.2.1" # Primary in us-east-1
- "192.0.2.2"
ttl: 300
Region 3: eu-west-1 (Secondary)
Save as region-eu-west-1.yaml:
---
# Namespace
apiVersion: v1
kind: Namespace
metadata:
name: dns-system
labels:
region: eu-west-1
role: secondary
---
# Secondary Bind9Instance
apiVersion: bindy.firestoned.io/v1alpha1
kind: Bind9Instance
metadata:
name: secondary-eu-west-1
namespace: dns-system
labels:
app: bindy
dns-role: secondary
region: eu-west-1
environment: production
spec:
replicas: 2
version: "9.18"
config:
recursion: false
allowQuery:
- "0.0.0.0/0"
dnssec:
enabled: false
validation: true
listenOn:
- "any"
listenOnV6:
- "any"
---
# PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: secondary-dns-pdb
namespace: dns-system
spec:
minAvailable: 1
selector:
matchLabels:
dns-role: secondary
region: eu-west-1
---
# Secondary DNSZone
apiVersion: bindy.firestoned.io/v1alpha1
kind: DNSZone
metadata:
name: example-com-secondary
namespace: dns-system
spec:
zoneName: "example.com"
zoneType: "secondary"
instanceSelector:
matchLabels:
dns-role: secondary
region: eu-west-1
secondaryConfig:
primaryServers:
- "192.0.2.1" # Primary in us-east-1
- "192.0.2.2"
ttl: 300
Deployment
1. Deploy to Each Region
# us-east-1
kubectl apply -f region-us-east-1.yaml --context us-east-1
# us-west-2
kubectl apply -f region-us-west-2.yaml --context us-west-2
# eu-west-1
kubectl apply -f region-eu-west-1.yaml --context eu-west-1
2. Verify Replication
# Check zone transfer from primary
kubectl exec -n dns-system -it <primary-pod> -- \
dig @localhost example.com AXFR
# Verify secondary received zone
kubectl exec -n dns-system -it <secondary-pod> -- \
dig @localhost example.com SOA
3. Configure Anycast (Infrastructure Level)
This requires network infrastructure support:
# Example using MetalLB for on-premises
apiVersion: v1
kind: Service
metadata:
name: dns-anycast
namespace: dns-system
annotations:
metallb.universe.tf/address-pool: anycast-pool
spec:
type: LoadBalancer
loadBalancerIP: 192.0.2.1 # Same IP in all regions
selector:
app: bindy
ports:
- protocol: UDP
port: 53
targetPort: 53
Cross-Region Monitoring
Prometheus Federation
# Global Prometheus Configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
data:
prometheus.yml: |
global:
scrape_interval: 30s
scrape_configs:
# us-east-1
- job_name: 'dns-us-east-1'
static_configs:
- targets: ['prometheus.us-east-1.example.com:9090']
metric_relabel_configs:
- source_labels: [__name__]
regex: 'dns_.*'
action: keep
# us-west-2
- job_name: 'dns-us-west-2'
static_configs:
- targets: ['prometheus.us-west-2.example.com:9090']
metric_relabel_configs:
- source_labels: [__name__]
regex: 'dns_.*'
action: keep
# eu-west-1
- job_name: 'dns-eu-west-1'
static_configs:
- targets: ['prometheus.eu-west-1.example.com:9090']
metric_relabel_configs:
- source_labels: [__name__]
regex: 'dns_.*'
action: keep
Health Checks
#!/bin/bash
# health-check-multi-region.sh
REGIONS=("us-east-1" "us-west-2" "eu-west-1")
QUERY="www.example.com"
for region in "${REGIONS[@]}"; do
echo "Checking $region..."
# Get DNS service IP
DNS_IP=$(kubectl get svc -n dns-system --context $region \
-o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}')
# Test query
if dig @$DNS_IP $QUERY +short > /dev/null; then
echo "✓ $region: OK"
else
echo "✗ $region: FAILED"
fi
done
Disaster Recovery
Regional Failover
# Promote secondary in us-west-2 to primary
kubectl patch bind9instance secondary-us-west-2 \
-n dns-system --context us-west-2 \
--type merge \
--patch '{"metadata":{"labels":{"dns-role":"primary"}}}'
# Update zone to primary
kubectl patch dnszone example-com-secondary \
-n dns-system --context us-west-2 \
--type merge \
--patch '{"spec":{"zoneType":"primary"}}'
Backup Strategy
#!/bin/bash
# backup-all-regions.sh
REGIONS=("us-east-1" "us-west-2" "eu-west-1")
BACKUP_DIR="./multi-region-backups/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
for region in "${REGIONS[@]}"; do
echo "Backing up $region..."
kubectl get dnszones,arecords,aaaarecords,cnamerecords,mxrecords,txtrecords \
-n dns-system --context $region -o yaml \
> "$BACKUP_DIR/$region.yaml"
done
echo "Backup completed: $BACKUP_DIR"
Performance Testing
Global Latency Test
#!/bin/bash
# test-global-latency.sh
REGIONS=(
"us-east-1:192.0.2.1"
"us-west-2:192.0.2.2"
"eu-west-1:192.0.2.3"
)
for region_ip in "${REGIONS[@]}"; do
region="${region_ip%%:*}"
ip="${region_ip##*:}"
echo "Testing $region ($ip)..."
# Measure query time
time dig @$ip www.example.com +short
done
Load Distribution
# Using dnsperf across regions
for region in us-east-1 us-west-2 eu-west-1; do
dnsperf -s $DNS_IP -d queries.txt -c 50 -l 30 -Q 1000 | \
tee results-$region.txt
done
Cost Optimization
Regional Scaling
# HPA for each region based on local load
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: dns-hpa-us-east-1
namespace: dns-system
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: primary-us-east-1
minReplicas: 2
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Compliance and Data Residency
Regional Data Isolation
# EU-specific zone for GDPR compliance
apiVersion: bindy.firestoned.io/v1alpha1
kind: DNSZone
metadata:
name: eu-example-com
namespace: dns-system
labels:
compliance: gdpr
spec:
zoneName: "eu.example.com"
zoneType: "primary"
instanceSelector:
matchLabels:
region: eu-west-1
soaRecord:
primaryNs: "ns1.eu-west-1.example.com."
adminEmail: "dpo@example.com"
serial: 2024010101
refresh: 900
retry: 300
expire: 604800
negativeTtl: 300