Nexus GSLB installs on Kubernetes with kustomize manifests in deploy/kubernetes/. The manifests use a StatefulSet where each pod runs a co-located rqlited datastore (a native sidecar) and gets its own PVC. With replicas: 1 you get a standalone single node; with 3+ (odd) replicas the pods form one rqlite Raft cluster (ordinal-0 bootstraps; higher ordinals join it via the headless service) that replicates all config and data-plane objects across pods. NATS (optional) carries only ephemeral health/membership state, not config. See Datastore.
The manifests include full production hardening: NetworkPolicy, PodDisruptionBudget, seccompProfile, non-root uid, and automountServiceAccountToken: false.
Architecture
┌─────────────────────────────────────────────────┐│ Kubernetes cluster ││ ││ ┌──────────────┐ ┌──────────────┐ ││ │ gslbd-0 │ │ gslbd-1 │ ... ││ │ PVC: data-0 │ │ PVC: data-1 │ ││ └──────┬───────┘ └──────┬───────┘ ││ │ │ ││ └────────┬─────────┘ ││ │ NATS JetStream (optional) ││ ┌───────────────▼──────────────────┐ ││ │ LoadBalancer: gslbd-dns :5353 │ ││ └──────────────────────────────────┘ │└─────────────────────────────────────────────────┘
Manifest overview
File | Resource(s) |
|---|---|
|
|
|
|
|
|
|
|
|
|
| 4 services: headless, DNS LoadBalancer, API ClusterIP, metrics ClusterIP |
| Ingress/egress policy restricting pod traffic |
|
|
| Kustomize entry point |
Quick start0. Registry access
The images are published to public GitHub Container Registry — no authentication or pull secret is required:
ghcr.io/star-storm-development/nexus-gslb/gslbdghcr.io/star-storm-development/nexus-gslb/webui
Verify with an anonymous pull: docker pull ghcr.io/star-storm-development/nexus-gslb/gslbd:latest.
If you mirror the images to a private registry, create a pull secret and uncomment the
imagePullSecretsblock inserviceaccount.yaml.
1. Set credentials
kubectl create secret generic gslbd-credentials \ --namespace nexus-gslb \ --from-literal=GSLB_LICENSE_KEY=your-key \ --from-literal=GSLB_LICENSE_SECRET=your-secret
Free-tier deployments can skip this; the daemon enforces unlicensed RPS limits automatically.
2. Edit the configuration
Edit deploy/kubernetes/configmap.yaml to set your DNS domain, load-balancer endpoints, and any other options. The ConfigMap is mounted read-only at /etc/gslb/config.yaml inside each pod.
3. Deploy
# With kustomize (recommended)kubectl apply -k deploy/kubernetes/# Or apply manifests directly (skip kustomization.yaml)kubectl apply -f deploy/kubernetes/ --ignore-not-found
4. Verify
# Pod statuskubectl -n nexus-gslb get pods -w# Logskubectl -n nexus-gslb logs statefulset/gslbd -f# API healthkubectl -n nexus-gslb port-forward svc/gslbd-api 8080:8080curl http://localhost:8080/api/v1/health# DNS query through the LoadBalancerLB=$(kubectl -n nexus-gslb get svc gslbd-dns \ -o jsonpath='{.status.loadBalancer.ingress[0].ip}')dig @$LB -p 5353 A gslb.example.com
Image
The statefulset.yaml defaults to nexus-gslb/gslbd:latest. Update via kustomize without editing the StatefulSet directly:
# In deploy/kubernetes/kustomization.yaml:images: - name: nexus-gslb/gslbd newName: ghcr.io/star-storm-development/nexus-gslb/gslbd newTag: 0.3.0
Or with the CLI:
cd deploy/kuberneteskustomize edit set image nexus-gslb/gslbd=ghcr.io/star-storm-development/nexus-gslb/gslbd:0.3.0
Scaling
Config and data-plane objects replicate automatically: the per-pod rqlited sidecars form one Raft cluster (use an odd replica count; a 3-node Raft cluster tolerates one lost pod). NATS is optional and carries only ephemeral state — without it each pod still serves the same config but only observes health from its own probes.
# Scale to 3 replicas (each gets its own PVC)kubectl -n nexus-gslb scale statefulset/gslbd --replicas=3
Optionally enable ephemeral state sync in configmap.yaml:
state: nats: servers: ["nats://your-nats:4222"] healthPolicy: "prefer-local"
See docs/user/StateSyncSetup.md for full NATS configuration.
DNS on port 53
The default DNS port is 5353 (no privileged port required). Most cloud load balancers can map port 53 → 5353 transparently. To run natively on port 53:
In
configmap.yamlsetdns.port: 53In
statefulset.yamladd to the containersecurityContext:capabilities: add: ["NET_BIND_SERVICE"] drop: ["ALL"]Update
services.yamlgslbd-dnsport from5353to53
DNSSEC
Pass DNSSEC key PEM content via the Secret (recommended over file mounts):
kubectl create secret generic gslbd-credentials \ --namespace nexus-gslb \ --from-literal=GSLB_LICENSE_KEY=your-key \ --from-literal=GSLB_LICENSE_SECRET=your-secret \ --from-file=GSLB_KSK_PEM=./keys/ksk.pem \ --from-file=GSLB_ZSK_PEM=./keys/zsk.pem
Then in configmap.yaml:
dnssec: enabled: true zone: "gslb.example.com." ksk: envVar: "GSLB_KSK_PEM" zsk: envVar: "GSLB_ZSK_PEM" signatureValidityDays: 7
Uncomment the GSLB_KSK_PEM / GSLB_ZSK_PEM env var blocks in statefulset.yaml.
Export the DS record:
kubectl -n nexus-gslb exec statefulset/gslbd -- \ gslbctl dnssec ds --zone gslb.example.com. --ksk-env GSLB_KSK_PEM
Prometheus metrics
The gslbd-metrics Service exposes /metrics on port 9090 with standard prometheus.io/scrape annotations. For Prometheus Operator:
apiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata: name: gslbd namespace: nexus-gslbspec: selector: matchLabels: app.kubernetes.io/component: metrics endpoints: - port: metrics interval: 15s
Secrets management
For production, replace secret.yaml with your preferred secrets operator:
External Secrets Operator: create an
ExternalSecretprojecting from Vault/AWS SM/GCP SM intogslbd-credentialsSealed Secrets: seal with
kubesealand commit theSealedSecretVault Agent: inject secrets as environment variables via annotation
The Secret name (gslbd-credentials) and key names (GSLB_LICENSE_KEY, GSLB_LICENSE_SECRET) must match what the StatefulSet references.
Upgrade
# Update image tag in kustomization.yaml, then:kubectl apply -k deploy/kubernetes/# Watch the rolling updatekubectl -n nexus-gslb rollout status statefulset/gslbd
The StatefulSet uses RollingUpdate strategy. With maxUnavailable: 1 (PDB), a single-replica deployment will briefly be unavailable — scale to 2+ for zero-downtime upgrades.
Uninstall
kubectl delete -k deploy/kubernetes/# PVCs are not deleted by kustomize — remove manually if needed:kubectl -n nexus-gslb delete pvc -l app.kubernetes.io/name=gslbd