load 150 req/s

PodPlacement rulePlaced on
kind: HorizontalPodAutoscaler
spec: { scaleTargetRef: { kind: Deployment, name: web }, minReplicas: 2, maxReplicas: 10,
        metrics: [{ type: Resource, resource: { name: cpu, target: { type: Utilization, averageUtilization: 50 } } }] }
---
# db pod:      nodeSelector: { disktype: ssd }
# trainer pod: tolerations: [{ key: gpu, value: "true", effect: NoSchedule }]
#              affinity: { nodeAffinity: { requiredDuringSchedulingIgnoredDuringExecution: ... gpu=true } }
# node-3:      kubectl taint nodes node-3 gpu=true:NoSchedule
Gauge needle: web's average CPU; the bright mark is the HPA's 50% targetStriped barrier: node-3's taint, which only pods with a matching toleration passDashed outline: the node the Cluster Autoscaler adds when pods are PendingThe Horizontal Pod Autoscaler watches a metric, here average CPU, and sets a Deployment's replicas to bring it to the target: desired = ceil(current × actual ÷ target). It scales up quickly and down only after a stabilization window. More pods need room: when pods stay Pending because no node they are allowed on has space, the Cluster Autoscaler adds a node, and it removes nodes that sit empty. Where pods may go is up to you: a nodeSelector or node affinity pulls a pod to labelled nodes, and a taint pushes every pod away from a node except those with a matching toleration.
Next: ServiceAccounts & RBAC →