This document describes the pod affinity, anti-affinity, and node affinity rules implemented in the GistPin Kubernetes cluster to ensure optimal performance, high availability, and proper workload distribution.
The scheduling rules are defined in two primary files:
infrastructure/k8s/affinity/backend-affinity.yaml: Affinity rules for backend-database co-location and GPU workload schedulinginfrastructure/k8s/affinity/anti-affinity-rules.yaml: Anti-affinity rules for replica distribution across nodes
To ensure low-latency communication between backend services and the PostgreSQL database, we implement strict affinity rules that prioritize co-location.
Backend pods must be scheduled in the same availability zone as the database:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- us-central1-aThis ensures network latency between backend and database remains minimal by forcing both workloads into the same cloud region and zone.
We prefer to schedule backend pods on the same node as the database when possible:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- postgres
topologyKey: kubernetes.io/hostname
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: gistpinThe high weight (100) makes this a strong preference, while still allowing the scheduler to place backend pods on other nodes if database node resources are exhausted.
For backend services that require GPU acceleration (e.g., machine learning inference, media processing), additional affinity rules ensure these workloads are scheduled in zones with GPU-capable nodes:
- weight: 50
podAffinityTerm:
labelSelector:
matchExpressions:
- key: workload-type
operator: In
values:
- gpu-workload
topologyKey: topology.kubernetes.io/zoneTo ensure high availability of all services, we implement pod anti-affinity rules that prevent multiple replicas from being scheduled on the same node.
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- backend
topologyKey: kubernetes.io/hostname
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: gistpinThis is a hard requirement that ensures no single node failure can take down multiple backend replicas. With 3 replicas configured, the scheduler must place each on a separate node.
These anti-affinity rules apply to:
- Backend API servers (3 replicas)
- Frontend web servers (3 replicas)
- Redis cache cluster (3 replicas)
- Any other stateful or stateless services requiring high availability
Workloads are labeled to facilitate proper scheduling:
| Label Key | Values | Purpose |
|---|---|---|
app |
backend, frontend, postgres, redis |
Core application identification |
workload-type |
cpu-workload, gpu-workload, memory-intensive |
Resource type classification |
environment |
dev, staging, production |
Deployment environment |
- Always test scheduling rules in staging first before promoting to production
- Monitor pod distribution using Kubernetes dashboard or metrics server to ensure rules are working as expected
- Review node capacity regularly to ensure there are enough nodes to satisfy anti-affinity constraints
- Update zone names if deploying to a different cloud region
- Adjust weights based on your specific latency and availability requirements
If pods remain in Pending state:
- Check if you have enough nodes to satisfy anti-affinity rules
- Verify node labels match the topology keys used in affinity rules
- Ensure namespace labels are correctly configured
- Check event logs using
kubectl describe pod <pod-name>for specific scheduling failures