Kubernetes
kubectl
nodeSelector
tolerations
command-line

Kubectl run command with nodeSelector and tolerations

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

kubectl run is useful for creating a quick one-off Pod, but it does not expose dedicated flags for every field in the Pod spec. If you need nodeSelector and tolerations, the practical choices are either to use --overrides with inline JSON or to generate YAML and apply a proper manifest.

Understand What nodeSelector and Tolerations Do

nodeSelector restricts scheduling to nodes with matching labels. Tolerations do not select nodes by themselves. They only allow a Pod to be scheduled onto nodes with matching taints.

In practice, that means:

  • 'nodeSelector says where the Pod is allowed to go'
  • tolerations say which taints the Pod is willing to tolerate

You often need both when a special node pool is tainted and labeled.

Use kubectl run --overrides for a Quick Pod

For an ad hoc Pod, --overrides is the direct answer.

bash
1kubectl run debug-shell \
2  --image=busybox:1.36 \
3  --restart=Never \
4  --overrides='{
5    "apiVersion": "v1",
6    "spec": {
7      "nodeSelector": {
8        "workload": "batch"
9      },
10      "tolerations": [
11        {
12          "key": "dedicated",
13          "operator": "Equal",
14          "value": "batch",
15          "effect": "NoSchedule"
16        }
17      ]
18    }
19  }' \
20  -- sleep 3600

That creates a Pod named debug-shell scheduled only onto nodes labeled workload=batch, and only if it tolerates the dedicated=batch:NoSchedule taint.

Verify the Labels and Taints First

Before blaming kubectl run, confirm the target nodes actually match what you requested.

List labels:

bash
kubectl get nodes --show-labels

Describe the target node to inspect taints:

bash
kubectl describe node my-node-name

If the label is missing or the taint value does not match, the Pod will stay Pending no matter how correct the command syntax is.

Use --dry-run to Generate YAML

Inline JSON works, but it becomes hard to read quickly. A cleaner workflow is to generate a Pod manifest and edit it.

bash
1kubectl run debug-shell \
2  --image=busybox:1.36 \
3  --restart=Never \
4  --dry-run=client -o yaml \
5  -- sleep 3600

Then add the scheduling fields:

yaml
1apiVersion: v1
2kind: Pod
3metadata:
4  name: debug-shell
5spec:
6  nodeSelector:
7    workload: batch
8  tolerations:
9    - key: dedicated
10      operator: Equal
11      value: batch
12      effect: NoSchedule
13  containers:
14    - name: debug-shell
15      image: busybox:1.36
16      command: ["sleep", "3600"]
17  restartPolicy: Never

Apply it with:

bash
kubectl apply -f debug-shell.yaml

For anything beyond a quick one-off, this is easier to maintain than an inline JSON string.

Prefer a Manifest for Repeatable Work

kubectl run is convenient for experimentation, but repeatable operations should usually live in YAML checked into source control. That gives you a readable review path and avoids shell-escaping issues.

It also makes later upgrades easier if you want to switch from a Pod to a Job or Deployment with the same scheduling rules.

When nodeSelector Is Not Enough

nodeSelector only supports exact label matching. If you need richer scheduling rules, use node affinity instead.

Example:

yaml
1affinity:
2  nodeAffinity:
3    requiredDuringSchedulingIgnoredDuringExecution:
4      nodeSelectorTerms:
5        - matchExpressions:
6            - key: workload
7              operator: In
8              values:
9                - batch
10                - gpu

That is a better fit when you need multiple allowed values or more complex logic.

Debug a Pending Pod Systematically

If the Pod remains Pending, inspect it directly:

bash
kubectl describe pod debug-shell

Look at the scheduler events near the bottom. They usually tell you whether the issue is:

  • no nodes matched the selector
  • the Pod did not tolerate a taint
  • there were insufficient resources
  • another admission or policy rule blocked scheduling

Reading events is faster than guessing.

Common Pitfalls

Expecting tolerations to select nodes. They do not. They only allow placement on tainted nodes.

Using kubectl run without --restart=Never and then being surprised by generated controller behavior in older workflows.

Writing invalid JSON in --overrides. Shell quoting errors are common.

Forgetting to verify node labels and taints before creating the Pod.

Using nodeSelector when the scheduling rule really requires node affinity.

Summary

  • 'kubectl run does not have dedicated flags for nodeSelector and tolerations, so use --overrides or YAML.'
  • 'nodeSelector chooses matching labels, while tolerations allow tainted nodes.'
  • Verify node labels and taints before debugging the command.
  • For anything reusable, generate or write a manifest instead of relying on inline JSON.
  • Check scheduler events with kubectl describe pod when the Pod stays Pending.

Course illustration
Course illustration

All Rights Reserved.