DNS-Aware Load Balancer Scaling
This guide shows a simple pattern to scale Kubernetes services while keeping DNS records in sync through ExternalDNS.
The idea is:
- ExternalDNS manages public DNS records from Kubernetes resources.
- GoKubeDownscaler controls when your gateway/service workloads are up or down.
Prerequisites
First you need to have ExternalDNS installed in your cluster and configured for your cloud provider.
- AWS Route 53/EKS
- Azure DNS/AKS
- Google Cloud DNS/GKE
Install ExternalDNS on AWS/EKS:
- ExternalDNS with Service Controller: this guide
shows how to set up ExternalDNS with AWS Route 53 and the default AWS Service Controller for EKS.
This guide works only for
Services. - ExternalDNS AWS LB Controller:
this guide shows how to set up ExternalDNS with AWS Route 53 and the AWS Load Balancer Controller for EKS.
This guide works for
Services,Ingress, and (soon)Gatewayresources.
Install ExternalDNS for Azure/AKS.
- ExternalDNS with Azure Service Controller: this guide will
show you how to set up ExternalDNS with Azure DNS and the default Azure Service Controller for AKS.
This guide works for
Service,Ingressand (soon)Gatewayresources.
Install ExternalDNS for Google Cloud DNS managed zones.
- ExternalDNS with Google Service Controller: this guide will
show you how to set up ExternalDNS with Google Cloud DNS for GKE.
This guide works for
Service,Ingressand (soon)Gatewayresources. - ExternalDNS with Nginx Ingress Controller: this guide will
show you how to set up ExternalDNS with Nginx Ingress Controller for GKE.
This guide works for
Service,Ingressand (soon)Gatewayresources.
This guide also works with other DNS providers supported by ExternalDNS, such as Cloudflare, DigitalOcean, and others. You can even build a custom webhook yourself if you are using a custom solution. Check the ExternalDNS documentation for provider-specific setup instructions.
General references:
- ExternalDNS docs: kubernetes-sigs.github.io/external-dns
- Annotations reference: ExternalDNS annotations
Set ExternalDNS Annotations
ExternalDNS commonly watches a Service of type LoadBalancer and creates/updates DNS records from annotations.
To set up DNS-aware scaling, you need to annotate your public service with the desired hostname and TTL.
You can do this either by editing the service manifest or by using kubectl annotate.
- kubectl
- Edit manifest
Add ExternalDNS annotations with kubectl:
kubectl annotate svc public-gateway -n edge \
external-dns.alpha.kubernetes.io/hostname=api.example.com \
external-dns.alpha.kubernetes.io/ttl=60
Edit the service manifest and add the annotations:
apiVersion: v1
kind: Service
metadata:
name: public-gateway
namespace: edge
annotations:
external-dns.alpha.kubernetes.io/hostname: api.example.com
external-dns.alpha.kubernetes.io/ttl: "60"
spec:
type: LoadBalancer
selector:
app: public-gateway
ports:
- name: https
port: 443
targetPort: 8443
Alternatively, if your setup allows it, you can annotate Ingress or Gateway resources instead of Service.
The following
example shows how to annotate an Ingress:
- kubectl
- Edit manifest
Add ExternalDNS annotations with kubectl:
kubectl annotate ingress echoserver -n edge \
external-dns.alpha.kubernetes.io/hostname=api.example.com \
external-dns.alpha.kubernetes.io/ttl=60
Edit the ingress manifest and add the annotations:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echoserver
namespace: edge
annotations:
external-dns.alpha.kubernetes.io/hostname: api.example.com
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: public-gateway
port:
number: 80
Apply Downtime
Finally, you can apply downtime clusterwide, to the service's namespace or the service itself using GoKubeDownscaler.
Make sure to include services (or ingresses, gateways) in your targeted resources by using the --include-resources
flag on the Downscaler deployment.
- Environment Variable
- Cli Argument
- Namespace
- Workload
If you want to add a cluster-wide downtime with environment variables you can add them inside the values.yaml file.
There you have to add it to the configMap.extraConfig field:
# ...
configMap:
name: go-kube-downscaler
extraConfig: |
DEFAULT_DOWNTIME: "Mon-Fri 18:00-08:00 UTC, Sat-Sun 00:00-24:00 UTC"
# ...
If you want to use a cli argument for the cluster-wide downtime you can add them inside the values.yaml file.
There you have to add it to the arguments field:
# ...
arguments:
- --default-downtime="Mon-Fri 18:00-08:00 UTC, Sat-Sun 00:00-24:00 UTC"
# ...
Adding the downtime with kubectl is a single command:
kubectl annotate ns my-namespace downscaler/downtime="Mon-Fri 18:00-08:00 UTC, Sat-Sun 00:00-24:00 UTC"
Adding the downtime with kubectl is a single command:
kubectl annotate deployment my-deployment downscaler/downtime="Mon-Fri 18:00-08:00 UTC, Sat-Sun 00:00-24:00 UTC"
You will now observe that:
- When the downtime is active, the service will be scaled down to
ClusterIPand ExternalDNS will remove the DNS record from your public DNS provider - When the downtime ends, the service will scale back up to
LoadBalancer(orIngress/Gateway) and ExternalDNS will recreate the DNS record.
- Keep TTL low (for example
60) for faster DNS convergence during scale events. - Explore ExternalDNS to fine tune your DNS management, including provider-specific configurations and advanced features.
- Explore ExternalDNS annotations.
- Validate behavior in a non-production namespace before applying cluster-wide schedules.