Skip to main content

Command Palette

Search for a command to run...

K8S-Schedule: Pod Affinity & Anti-Affinity

Updated
3 min read

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-pod is scheduled on the same Node as any Pod with the label app=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
12 views

More from this blog

Clarence's Blog

56 posts

I share insights on programming, web development, cloud computing, computer networks, and AI, alongside financial knowledge, reading notes, and reflections on business and entrepreneurship.