Global Server Load Balancing (GSLB) distributes traffic across multiple data centers, cloud regions, or Kubernetes clusters based on geographic proximity, server health, and capacity. While cloud providers offer managed GSLB services (Route 53, Cloudflare Load Balancing), self-hosted alternatives give you full control over routing logic, eliminate per-query charges, and keep DNS infrastructure within your operational boundary. In this guide, we compare three approaches to self-hosted DNS GSLB: K8GB, PowerDNS with GeoIP backend, and CoreDNS with GeoIP plugin.

What Is DNS-Based Global Load Balancing?

DNS GSLB works by returning different IP addresses for the same domain name based on:

  • Geographic location — users in Europe get European data center IPs
  • Server health — unhealthy data centers are removed from DNS responses
  • Load balancing — traffic is distributed across available endpoints
  • Latency optimization — users are routed to the closest responding endpoint

This approach operates at the DNS level (before the TCP connection is established), making it transparent to applications and compatible with any protocol. Unlike HTTP-based load balancers, DNS GSLB works for TCP, UDP, and any IP-based protocol.

K8GB

K8GB is a Kubernetes-native global load balancer that operates as an externalDNS controller. It watches endpoints across multiple Kubernetes clusters and generates DNS records that route traffic to the closest healthy cluster. With over 1,160 GitHub stars, it’s the most Kubernetes-focused GSLB solution.

Architecture

K8GB runs as a deployment in each Kubernetes cluster. It watches local Service endpoints and shares health information with other K8GB instances via a shared DNS zone (typically using Infoblox, Route 53, or a self-hosted DNS server). When a DNS query arrives, the authoritative server responds with the IP of the healthiest, closest cluster.

Key Features

  • Kubernetes-native — watches Services, Endpoints, and Ingress resources directly
  • Active-active and active-passive — supports both multi-site topologies
  • Health checking — HTTP/TCP health probes across clusters
  • Failover automation — automatic traffic redirection on cluster failure
  • GeoDNS support — location-aware DNS responses via upstream DNS provider
  • Multi-cluster coordination — uses DNS zone sharing for cross-cluster state

Deployment

1
2
helm repo add k8gb https://absaoss.github.io/k8gb/
helm install k8gb k8gb/k8gb   --namespace k8gb   --create-namespace   --set k8gb.edgeDnsServersFromEnv.enabled=true   --set k8gb.clusterGeoTag=eu-west-1

Example K8GB CRD:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: k8gb.absa.oss/v1alpha1
kind: Gslb
metadata:
  name: my-application
  namespace: production
spec:
  ingress:
    ingressClassName: nginx
    rules:
      - host: app.example.com
        http:
          paths:
            - pathType: Prefix
              path: /
              backend:
                service:
                  name: my-service
                  port:
                    number: 80
  strategy:
    type: failover
    primaryGeoTag: eu-west-1

Docker Compose (Local Testing)

For local testing with multiple “clusters”:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
version: "3.8"
services:
  k8gb-cluster-a:
    image: ghcr.io/absaoss/k8gb:latest
    environment:
      - K8GB_NAMESPACE=cluster-a
      - K8GB_CLUSTER_GEOTAG=us-east-1
      - K8GB_EDGE_DNS_SERVERS=10.0.0.10
    ports:
      - "8080:8080"
    volumes:
      - ./cluster-a-config:/etc/k8gb

  k8gb-cluster-b:
    image: ghcr.io/absaoss/k8gb:latest
    environment:
      - K8GB_NAMESPACE=cluster-b
      - K8GB_CLUSTER_GEOTAG=eu-west-1
      - K8GB_EDGE_DNS_SERVERS=10.0.0.10
    ports:
      - "8081:8080"
    volumes:
      - ./cluster-b-config:/etc/k8gb

  dns-authoritative:
    image: powerdns/pdns-auth-49:latest
    ports:
      - "53:53/udp"
      - "53:53/tcp"
      - "8082:8081"
    environment:
      - PDNS_gmysql_host=dns-db
      - PDNS_gmysql_user=pdns
      - PDNS_gmysql_password=pdns
    depends_on:
      - dns-db

  dns-db:
    image: mariadb:11
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: pdns
      MYSQL_USER: pdns
      MYSQL_PASSWORD: pdns
    volumes:
      - dns-data:/var/lib/mysql

volumes:
  dns-data:

PowerDNS with GeoIP Backend

PowerDNS is a mature, high-performance authoritative DNS server with extensive backend options. Its GeoIP backend returns different DNS responses based on the source IP of the query, enabling DNS-based global load balancing without additional software.

Architecture

PowerDNS runs as an authoritative DNS server with a GeoIP backend (via the geoip backend module). It uses a MaxMind GeoIP database (or compatible) to map query source IPs to geographic regions. Backend data is stored in a database (MySQL, PostgreSQL, SQLite) or YAML files, with different IP pools per region.

Key Features

  • Battle-tested DNS server — used by ISPs and enterprises worldwide
  • GeoIP backend — native GeoIP module with MaxMind database support
  • Multiple backends — switch between pipe, remote, BIND, and SQL backends
  • DNSSEC support — native DNSSEC signing and validation
  • API-driven configuration — RESTful API for dynamic record management
  • High performance — handles millions of queries per second
  • Load balancing strategies — weighted, random, and all-records modes

Deployment

Install PowerDNS with the GeoIP backend:

1
2
3
4
5
# Debian/Ubuntu
apt install pdns-server pdns-backend-geoip

# Or with Docker
docker run -d --name pdns-geoip   -p 53:53/udp -p 53:53/tcp -p 8081:8081   -v ./pdns.conf:/etc/pdns/pdns.conf   -v ./geoip.conf:/etc/pdns/geoip.conf   -v ./geoip-db:/usr/share/GeoIP   powerdns/pdns-auth-49

Configuration example:

1
2
3
4
5
6
7
8
9
# pdns.conf
launch=geoip
geoip-database-files=/usr/share/GeoIP/GeoLite2-City.mmdb
geoip-zones-file=/etc/pdns/geoip.conf
api=yes
api-key=your-secret-key
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# geoip.conf
example.com A:
  # Default fallback
  - 203.0.113.1

  # North America
  - &us
    geoip-match:
      - country: US
      - country: CA
    addresses:
      - 203.0.113.10

  # Europe
  - &eu
    geoip-match:
      - country: DE
      - country: FR
      - country: GB
    addresses:
      - 203.0.113.20

  # Asia-Pacific
  - &apac
    geoip-match:
      - country: JP
      - country: AU
      - country: SG
    addresses:
      - 203.0.113.30

Docker Compose

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
version: "3.8"
services:
  pdns:
    image: powerdns/pdns-auth-49:latest
    ports:
      - "53:53/udp"
      - "53:53/tcp"
      - "8081:8081"
    volumes:
      - ./pdns.conf:/etc/pdns/pdns.conf:ro
      - ./geoip.conf:/etc/pdns/geoip.conf:ro
      - ./geoip-db:/usr/share/GeoIP:ro
    environment:
      - PDNS_launch=geoip
      - PDNS_geoip_database_files=/usr/share/GeoIP/GeoLite2-City.mmdb
    restart: unless-stopped

CoreDNS with GeoIP Plugin

CoreDNS is a flexible, plugin-based DNS server that is the default DNS provider in Kubernetes. Its GeoIP plugin (via the geoip plugin or the rewrite + template plugin combination) enables geographic routing without running a separate DNS server.

Architecture

CoreDNS runs as a single binary with a plugin chain. The GeoIP functionality can be achieved through the geoip plugin (community-maintained) or by combining rewrite and template plugins with a MaxMind database lookup. CoreDNS is typically deployed as a DaemonSet or Deployment in Kubernetes.

Key Features

  • Kubernetes default DNS — already running in most K8s clusters
  • Plugin ecosystem — extensible with 30+ official plugins
  • GeoIP routing — geographic DNS responses via community plugin
  • Low resource usage — single binary, minimal memory footprint
  • Service discovery — native Kubernetes service discovery integration
  • Caching — built-in DNS caching for reduced upstream queries

Deployment

CoreDNS with GeoIP requires a custom build with the geoip plugin:

1
2
3
4
5
6
# Build CoreDNS with geoip plugin
git clone https://github.com/coredns/coredns.git
cd coredns
echo "geoip:github.com/infobloxopen/coredns-geoip" >> plugin.cfg
go generate
go build

Corefile configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
.:53 {
    geoip {
        database /usr/share/GeoIP/GeoLite2-City.mmdb
        zones example.com
        record example.com {
            match US,CA { 203.0.113.10 }
            match DE,FR,GB,NL { 203.0.113.20 }
            match JP,AU,SG { 203.0.113.30 }
            default { 203.0.113.1 }
        }
    }
    errors
    log
    health
    ready
}

Kubernetes deployment:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns-geoip
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        geoip {
            database /geoip/GeoLite2-City.mmdb
        }
        errors
        log
        health
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa
    }
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns-geoip
  namespace: kube-system
spec:
  replicas: 2
  selector:
    matchLabels:
      app: coredns-geoip
  template:
    spec:
      containers:
        - name: coredns
          image: coredns/coredns:1.12.0
          args: ["-conf", "/etc/coredns/Corefile"]
          ports:
            - containerPort: 53
              protocol: UDP
            - containerPort: 53
              protocol: TCP
          volumeMounts:
            - name: config
              mountPath: /etc/coredns
            - name: geoip-db
              mountPath: /geoip
      volumes:
        - name: config
          configMap:
            name: coredns-geoip
        - name: geoip-db
          emptyDir: {}

Feature Comparison

FeatureK8GBPowerDNS GeoIPCoreDNS GeoIP
GitHub Stars1,160+N/A (core project: 4,350+)Community plugin
LicenseApache 2.0MIT (core), Apache 2.0 (backend)Apache 2.0
Kubernetes NativeYesNoYes (runs in K8s)
Health CheckingHTTP/TCP probesNo (external monitor needed)No (external monitor needed)
Automatic FailoverYesManual or via scriptManual or via script
GeoIP DatabaseVia upstream DNSMaxMind GeoLite2MaxMind GeoLite2
DNSSECVia upstreamNativeVia plugin
Multi-ClusterYesSingle serverSingle cluster
ConfigurationKubernetes CRDsConfig files + APICorefile
API ManagementKubernetes APIREST APINone (config files)
Best ForMulti-K8s GSLBTraditional DNS GSLBK8s-internal GeoDNS

Choosing the Right DNS GSLB Solution

  • Choose K8GB if you run multiple Kubernetes clusters and want a native Kubernetes solution that handles health checking, failover, and cross-cluster coordination automatically. It’s purpose-built for Kubernetes GSLB.

  • Choose PowerDNS GeoIP if you need a production-grade authoritative DNS server with geographic routing for non-Kubernetes workloads, DNSSEC requirements, or integration with existing DNS infrastructure. It’s the most versatile option.

  • Choose CoreDNS GeoIP if you already run CoreDNS in Kubernetes and want to add geographic routing without deploying a separate DNS server. It’s the simplest path for K8s-native teams, though it lacks built-in health checking.

For related reading, see our authoritative DNS server comparison for broader DNS server options, and PowerDNS GeoDNS routing guide for geographic DNS techniques.

Why Self-Host Your DNS Global Load Balancer?

Self-hosting DNS GSLB eliminates per-query charges that cloud providers impose on managed services. At high query volumes, Route 53 and Cloudflare Load Balancing costs can add up significantly. A self-hosted solution handles millions of queries with minimal infrastructure cost.

Self-hosted GSLB also keeps your DNS infrastructure within your operational control. You define the routing logic, control health check parameters, and can implement custom policies that managed services don’t support — such as time-based routing, capacity-aware distribution, or integration with internal monitoring systems.

For organizations operating across multiple data centers or cloud regions, DNS GSLB provides the foundation for disaster recovery. When a primary site fails, DNS responses automatically redirect traffic to the secondary site. The failover is transparent to end users (aside from DNS TTL delays) and requires no application changes.

Additionally, self-hosted DNS GSLB integrates with your existing monitoring and alerting stack. You can trigger failover based on custom health metrics, integrate with PagerDuty for alerting, and maintain full audit logs of DNS responses and failover events.

For teams managing multi-cluster infrastructure, understanding Kubernetes CNI options and DNS anycast configurations provides essential networking context for building resilient global DNS architectures.

FAQ

How does DNS-based load balancing differ from HTTP load balancing?

DNS-based load balancing operates at the DNS resolution level — when a client resolves a domain name, it receives an IP address of one of the available endpoints. HTTP load balancing operates at the application level, intercepting HTTP requests and routing them to backend servers. DNS GSLB is protocol-agnostic (works with TCP, UDP, SMTP, etc.) but has less granular control. HTTP load balancers can inspect request content but only work for HTTP/S traffic.

What is the TTL problem with DNS failover?

DNS records have a Time-To-Live (TTL) value that tells resolvers how long to cache the response. During a failover, clients may continue using the cached (now incorrect) IP until the TTL expires. To minimize downtime, GSLB systems use short TTLs (30-60 seconds), but this increases DNS query volume. K8GB mitigates this by using very low TTLs for health-sensitive records.

Do I need a MaxMind GeoIP database for all three solutions?

Yes, all three solutions rely on a GeoIP database to map IP addresses to geographic locations. The MaxMind GeoLite2 database is the most common choice and is freely available. Commercial databases offer higher accuracy but require paid subscriptions. PowerDNS and CoreDNS require you to provide the database file; K8GB delegates to the upstream DNS provider.

Can DNS GSLB replace a traditional load balancer?

DNS GSLB and traditional load balancers serve different purposes. DNS GSLB distributes traffic across geographically distributed endpoints at the DNS level. A traditional load balancer (like HAProxy or Nginx) distributes traffic across backend servers within a single data center. They are complementary — DNS GSLB routes users to the right data center, and the local load balancer distributes traffic within that data center.

How do I test DNS GSLB without deploying globally?

You can simulate geographic routing locally by modifying the GeoIP database or using DNS override files. PowerDNS allows manual zone overrides for testing. CoreDNS supports the hosts plugin for local overrides. K8GB can be tested with multiple Docker Compose clusters on the same host, using different geo tags to simulate multiple regions.

Is DNS GSLB compatible with IPv6?

Yes. All three solutions support IPv6 DNS records (AAAA). You can configure separate IPv6 address pools per geographic region, just as you do with IPv4 (A records). PowerDNS and CoreDNS handle IPv6 natively. K8GB supports IPv6 endpoints through its standard service discovery mechanism.