World map

 

BM: Baca dalam Bahasa Melayu

World K5: Lunch Rush

Pick a stall: nodeSelector and affinity

You will learn: how to send a tray only to stalls with the right label.

Checked with Kubernetes 1.37 on 31 Oct 2026

The problem

You are here: cluster kind-dev namespace default
The fast pod is created, but after 5 seconds it is still Pending, 0 of 1 ready. Terminal output: $ kubectl apply -f fast.yaml pod/fast created $ sleep 5 $ kubectl get pod fast NAME READY STATUS RESTARTS AGE fast 0/1 Pending 0 5s

The fast tray says Pending. It never starts. What is it waiting for?

Watch

fast.yaml carries a sign. A nodeSelector: A sign on the tray: "only stalls with this label". says: “only stalls with this label.”

spec:
  nodeSelector:
    disk: ssd

Which stall may take the fast tray?

Pick one answer.

Try it

Put every tray on a stall. Read the signs first.

Tap a tray, then tap a stall. Or drag the tray.

Waiting trays

  • stall-a
    disk=ssd
    CPU 0 of 2
    Memory 0Mi of 4Gi
    • stall-b
      disk=hdd
      CPU 0 of 2
      Memory 0Mi of 4Gi
      • Pending

        Trays that fit on no stall wait here.

        Check

        You are here: cluster kind-dev namespace default
        The FailedScheduling event: 0 of 3 nodes are available. 1 had an untolerated taint, 2 did not match the pod's node affinity or selector. Terminal output: $ kubectl apply -f fast.yaml pod/fast created $ sleep 5 $ kubectl get events --field-selector reason=FailedScheduling -o jsonpath={.items[0].message} 0/3 nodes are available: 1 node(s) had untolerated taint(s), 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling.

        Those are the scheduler’s real words. In plain words: one stall is locked. Two have the wrong label. No stall says disk=ssd.

        Try it

        Give stall dev-worker2 the sign. The waiting tray should move in.

        kubectl label nodes dev-worker2 disk=ssd
        You are here: cluster kind-dev namespace default
        Stalls: 3. Trays: 0 (0 ready). Waiting for a stall: 1.
        dev-control-planeOpenManager

        No trays here.

        dev-workerOpen

        No trays here.

        dev-worker2Open

        No trays here.

        Waiting for a stall
        • fastPending
        Time: +0s (sped up)

        Watch

        node affinity: A wish list for stalls: must-have rules and nice-to-have rules. is a wish list: must-haves (required) and nice-to-haves (preferred). The fast tray needs ssd. It would like the front zone. Sort them.

        Drag a card into a box. Or tap the card, then tap the box.

            In YAML, the two lists look like this:

            affinity:
              nodeAffinity:
                requiredDuringSchedulingIgnoredDuringExecution:
                  nodeSelectorTerms:
                    - matchExpressions:
                        - { key: disk, operator: In, values: [ssd] }
                preferredDuringSchedulingIgnoredDuringExecution:
                  - weight: 50
                    preference:
                      matchExpressions:
                        - { key: zone, operator: In, values: [front] }

            Predict

            The fast tray runs on dev-worker2. Now you remove the label: kubectl label nodes dev-worker2 disk-. What happens to the tray?

            Pick one answer.

            You did it!

            You can now send a tray to the right stall with labels.

            Go deeper (optional)

            kubectl get nodes --show-labels lists every stall’s labels. Built-in ones include kubernetes.io/hostname and, in clouds, topology.kubernetes.io/zone. Pod affinity puts trays near other trays. Anti-affinity keeps them apart.

            Real rep (optional): use a throwaway kind cluster. Label a worker, then apply a pod with a nodeSelector.