K8S-Schedule: Pod Affinity & Anti-Affinity
Intro
In Kubernetes scheduling, Pod Affinity and Anti-Affinity provide powerful mechanisms to influence where Pods are placed based on the presence (or absence) of other Pods. These rules allow workloads to be strategically co-located or distributed across Nodes, optimizing performance, fault tolerance, and resource utilization.
Pod Affinity: Placing Pods Together
- Pod Affinity enables Pods to be scheduled closer to other Pods that match specific labels. This is useful for applications that require low latency communication, such as microservices that frequently interact with each other.
Pod Anti-Affinity: Keeping Pods Apart
- Pod Anti-Affinity ensures that certain Pods are not scheduled on the same Node as other specified Pods. This is commonly used for high availability, ensuring that replicas of the same application are spread across different Nodes or availability zones to improve fault tolerance.
Both affinity and anti-affinity rules support soft (preferred) and hard (required) constraints, allowing administrators to fine-tune scheduling strategies. In the following sections, we will explore how to implement these policies in real-world Kubernetes workloads.
Demo
Pod Affinity Demo
Deploy the First Pod (Reference Pod)
We first deploy a backend service that will act as the reference for Pod Affinity.
apiVersion: v1
kind: Pod
metadata:
name: backend-pod
labels:
app: myapp-backend
spec:
containers:
- name: backend-container
image: nginx-k8s:latest
imagePullPolicy: Never
Deploy a Pod with Affinity Rules (hard affinity)
Now, we deploy a frontend Pod that must be scheduled on the same Node as the backend Pod using Pod Affinity.
apiVersion: v1
kind: Pod
metadata:
name: frontend-pod
labels:
app: frontend-app
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # Hard affinity
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp-backend # Affinity to backend pod
topologyKey: "kubernetes.io/hostname"
containers:
- name: frontend-container
image: nginx-k8s:latest
imagePullPolicy: Never
In this example:
Pod Affinity rule ensures that the
frontend-podis scheduled on the same Node as any Pod with the labelapp=myapp-backend.topologyKey: "kubernetes.io/hostname"ensures the Pods are placed on the same Node.
Verify
They are indeed on the same node!
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
backend-pod 1/1 Running 0 53s 10.244.1.6 kind-worker2 <none> <none>
frontend-pod 1/1 Running 0 10s 10.244.1.7 kind-worker2 <none> <none>
Soft Affinity Example
apiVersion: v1
kind: Pod
metadata:
name: frontend-pod
labels:
app: frontend-app
spec:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution: # Soft affinity
- weight: 1 # The node with the highest weight will be chosen
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp-backend
topologyKey: "kubernetes.io/hostname"
containers:
- name: frontend-container
image: nginx-k8s:latest
imagePullPolicy: Never
Pod Anti-affinity Demo
We are still going to use the reference pod we created in last part.
Deploy a Pod with Anti-affinity Rules (hard anti-affinity)
apiVersion: v1
kind: Pod
metadata:
name: frontend-pod
labels:
app: frontend-app
spec:
affinity:
podAntiAffinity: # Hard Anti-Affinity
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp-backend # Ensure this Pod is NOT scheduled on the same Node as backend Pods
topologyKey: "kubernetes.io/hostname"
containers:
- name: frontend-container
image: nginx-k8s:latest
imagePullPolicy: Never
Verify
They are not on the same node this time!
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
backend-pod 1/1 Running 0 21s 10.244.1.8 kind-worker2 <none> <none>
frontend-pod 1/1 Running 0 6s 10.244.2.5 kind-worker <none> <none>
Soft Anti-affinity Example
apiVersion: v1
kind: Pod
metadata:
name: frontend-pod
labels:
app: frontend-app
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1 # Defined how strongly k8s wants to seperate these pods, the higher, the stronger
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp-backend # Prefer to avoid scheduling on Nodes with backend pods
topologyKey: "kubernetes.io/hostname"
containers:
- name: frontend-container
image: nginx-k8s:latest
imagePullPolicy: Never

