> ## Documentation Index
> Fetch the complete documentation index at: https://enterprise-docs.crewai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Crew Pod Scheduling

> Pin every crew pod the platform provisions to a specific node pool, taint, or affinity rule via `automation.podScheduling`.

## Overview

By default, crew pods (the `autom-*` web, worker, and Redis pods the platform spins up for every deployed automation) schedule on any node the cluster is willing to give them. `automation.podScheduling` lets you constrain that placement: pin them to a labeled node pool, tolerate a taint, or apply a full affinity rule.

The chart passes your value through to the platform as `CREW_POD_SCHEDULING` (a JSON env var). The provisioner reads it at deploy time and renders `nodeSelector`, `tolerations`, and `affinity` on each crew pod's spec — no per-crew configuration required.

## When to use it

* Isolate crew workloads on a dedicated node pool (cost tracking, blast-radius, compliance).
* Force crews onto nodes with specific hardware — GPU, high CPU, SSD.
* Send crews to spot / preemptible instances to lower cost.
* Keep crews off nodes the platform itself runs on.

Leave it at the default (`{}` / `[]` on every sub-key) if any node in the cluster is fine.

## What the chart expects

One block, under `automation.podScheduling`, with up to three sub-keys. Every sub-key maps 1:1 to the Kubernetes [pod spec fields](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) with the same name — no custom DSL, no renaming.

```yaml theme={null}
automation:
  podScheduling:
    nodeSelector: {}   # object — matches nodeSelector on a K8s pod
    tolerations: []    # array  — matches tolerations on a K8s pod
    affinity: {}       # object — matches affinity on a K8s pod
```

Rules:

* **Sub-keys are independent.** Set the ones you need; leave the others at their default empty value. An empty sub-key is skipped — it does not clear anything else.
* **The shape is exactly the K8s pod spec.** Copy-paste from a working pod manifest works. No wrapping, no translation.
* **The block applies to every crew pod** — web, worker, and Redis — for every deployment provisioned by this install. There is no per-crew or per-org override.

## Recipes

### Pin crews to a labeled node pool

```yaml theme={null}
automation:
  podScheduling:
    nodeSelector:
      customer.com/pool: agents
```

Every crew pod lands on nodes labeled `customer.com/pool=agents`. If no matching node exists, the pod stays `Pending`.

### Pin to a tainted, dedicated node pool

Label + taint the nodes, then match both:

```yaml theme={null}
automation:
  podScheduling:
    nodeSelector:
      customer.com/pool: agents
    tolerations:
      - key: customer.com/pool
        operator: Equal
        value: agents
        effect: NoSchedule
```

Without the toleration, the taint keeps the crew pod off the reserved nodes even though the selector matches.

### Require SSD-backed nodes via affinity

```yaml theme={null}
automation:
  podScheduling:
    affinity:
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
            - matchExpressions:
                - key: customer.com/disk
                  operator: In
                  values: [ssd]
```

`required...` is a hard constraint — pods stay `Pending` until a matching node exists. Use `preferredDuringSchedulingIgnoredDuringExecution` for a soft preference.

### Combine all three

```yaml theme={null}
automation:
  podScheduling:
    nodeSelector:
      automation-pool: enabled
    tolerations:
      - key: automation-pool
        operator: Equal
        value: enabled
        effect: NoSchedule
    affinity:
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
            - matchExpressions:
                - key: node.kubernetes.io/instance-type
                  operator: In
                  values: [c5.2xlarge, c5.4xlarge]
```

## Common pitfalls

<Warning>
  **Changes need a crew redeploy, not just `helm upgrade`.** Kubernetes only applies `nodeSelector`, `tolerations`, and `affinity` at pod creation. After `helm upgrade`, existing crew pods keep their old scheduling until you redeploy the crew from the platform UI (or delete their pods so the operator recreates them). New crews pick up the new rules immediately.
</Warning>

<Warning>
  **The block replaces the platform's default placement.** When any sub-key is non-empty, it overrides the platform's built-in workload-type / egress-group node placement for that constraint. This is deliberate — the intent is a full lift-and-shift of scheduling rules — but it means you own the whole picture. Include every selector / toleration your target nodes need.
</Warning>

<Warning>
  **Mind the YAML types.** `nodeSelector` and `affinity` are objects (`{}`); `tolerations` is a list (`[]`). Getting the type wrong will fail Helm's schema validation.
</Warning>

## Verifying the change

After `helm upgrade` and a crew redeploy, confirm the scheduling landed:

```bash theme={null}
kubectl -n <crew-namespace> get pod <autom-pod> -o jsonpath='{.spec.nodeSelector}{"\n"}{.spec.tolerations}{"\n"}{.spec.affinity}'
```

You should see the values you configured. If they are absent, the crew pod predates the upgrade — redeploy it.

## Reference

* Per-field defaults, types, and full ParamField reference: [Automation Configuration Reference](/reference/chart-values/automation).
* Kubernetes docs on scheduling: [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/), [Taints and Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/), [Affinity and anti-affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity).
