Multi-Cluster Basics
This section covers the hands-on mechanics of working across more than one Kubernetes cluster: managing contexts, drawing region and environment boundaries, and delivering the same workload to several clusters safely.
Prerequisites
- Kubernetes 1.36.2 clusters (containerd via CRI on nodes) and
kubectlmatching within one minor. - Helm 3 for packaging add-ons and workloads.
- Compose v2 and Docker Engine 29.6.1 for local build/dev only (nodes run containerd).
- Two or more kubeconfig entries - a common convention is one per cluster, merged into
~/.kube/config.
# Merge several kubeconfigs into one and confirm the contexts
export KUBECONFIG=~/.kube/prod-us:~/.kube/prod-eu:~/.kube/staging
kubectl config view --flatten > ~/.kube/config
kubectl config get-contextsBasic Examples
1. List and switch contexts
Each cluster is a context in your kubeconfig; switching contexts is how you point kubectl at a different cluster.
kubectl config get-contexts
kubectl config use-context prod-eu
kubectl get nodes- A context bundles a cluster endpoint, a user credential, and a default namespace.
use-contextsets the default target for every later command.- Always confirm
kubectl config current-contextbefore applying to production. - Contexts are local convenience only - they carry no authority the cluster itself does not grant.
2. Run a command against one cluster without switching
Use --context for a one-off so you never accidentally leave kubectl pointed at the wrong cluster.
kubectl --context prod-us get deploy -n web
kubectl --context prod-eu get deploy -n web--contextoverrides the current context for a single command.- This pattern is safer in scripts than a global
use-context. - Pair it with
-n <namespace>to be fully explicit about target and scope.
3. Name clusters by region and environment
Consistent naming is the cheapest fleet tool you have.
# context name pattern: <env>-<region>
prod-us-east
prod-eu-west
staging-us-east- Encode environment first so
kubectl config get-contextsgroups them naturally. - Region tells you the failure domain and data-residency zone.
- Avoid team or app names in cluster names - workloads move, regions do not.
4. Label nodes and clusters for topology
Standard topology labels let the scheduler and your tooling reason about location.
kubectl get nodes -L topology.kubernetes.io/region,topology.kubernetes.io/zonetopology.kubernetes.io/regionand.../zoneare well-known labels set by cloud providers.- Workloads use them for
topologySpreadConstraintsand zonal spreading. - A cluster usually lives in one region across multiple zones.
5. Separate environments with clusters, teams with namespaces
Use a cluster boundary for upgrade risk, and namespaces for team isolation inside it.
apiVersion: v1
kind: Namespace
metadata:
name: team-payments
labels:
pod-security.kubernetes.io/enforce: restricted- Namespaces share the cluster's API server and node kernels.
- The
restrictedPod Security Standard is the safe default for workload namespaces. - Reserve separate clusters for prod-vs-nonprod and for hard tenancy.
6. Constrain a namespace with quota and limits
Quotas stop one team from starving a shared cluster.
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-payments-quota
namespace: team-payments
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Girequestsreserve capacity;limitscap burst.- A quota forces every pod in the namespace to declare requests and limits.
- Pair with a
LimitRangeto supply defaults so pods without requests still schedule.
7. Deploy the same chart to two clusters
Helm plus a per-cluster values file is the simplest multi-cluster delivery.
helm upgrade --install web ./charts/web \
--kube-context prod-us --values values/prod-us.yaml
helm upgrade --install web ./charts/web \
--kube-context prod-eu --values values/prod-eu.yaml- One chart, many values files, keeps clusters in lockstep on structure.
--kube-contexttargets the release without changing your current context.- This is the manual precursor to GitOps-driven fleet delivery.
Intermediate Examples
8. Spread replicas across zones
Topology spread keeps a workload available when one zone fails.
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: webmaxSkew: 1keeps replica counts nearly even across zones.DoNotSchedulerefuses to place a pod that would violate the spread.- Use
ScheduleAnywayif availability matters more than perfect balance.
9. Pin config per cluster with a ConfigMap overlay
Keep base config shared and let each cluster override only what differs.
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
namespace: web
data:
REGION: "eu-west"
DB_HOST: "db.eu-west.internal"- Only cluster-specific values (region, endpoints) belong in the overlay.
- Kustomize or Helm values render base plus overlay per cluster.
- Drift between overlays is the top cause of "works in one region only" bugs.
10. Verify a rollout on every cluster
Never assume a multi-cluster apply succeeded everywhere.
for ctx in prod-us prod-eu; do
echo "== $ctx =="
kubectl --context "$ctx" rollout status deploy/web -n web --timeout=120s
done- Loop over contexts to check each cluster independently.
rollout statusblocks until the deployment is healthy or times out.- A failure in one cluster should stop your promotion, not be ignored.
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).