With nodeSelector you can directly tie a Pod to a node, but it doesn't provide any means for spreading the Pods of a Deployment across the nodes.
To spread Pods across the nodes, you can use Pod anti-affinity.
For example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
selector:
matchLabels:
app: my-app
replicas: 3
template:
metadata:
labels:
app: my-app
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- my-app
topologyKey: "kubernetes.io/hostname"
containers:
- name: my-app
image: my-app:1.0.0
This schedules the Pods so that no two Pods of the Deployment are located on the same node, if possible.
For example, if you have 5 nodes and 3 replicas in the Deployment, then each Pod should be scheduled to a different node. If you have 5 nodes and 6 replicas, then the first 5 Pods should be scheduled to a different node each and the 6th Pod is scheduled to a node which already already has Pod (because there's no other possibility).
See more examples in the Kubernetes documentation.