Pod Scheduling
On this page
You can pin the Apache Flink® JobManager and TaskManager pods that run your deployments to specific Kubernetes nodes in your BYOC cluster. Scheduling is entered as YAML in the console, using the standard Kubernetes nodeSelector, affinity, and tolerations fields.
Use it to run Flink on dedicated node groups in a shared or multi-tenant cluster, and to keep Flink off nodes reserved for other teams. The fields follow the standard Kubernetes schema and semantics, as described in Assigning Pods to Nodes and Taints and Tolerations.
What You Can Schedule
You set scheduling in two places: as a namespace default, and per deployment.
Per-deployment values take precedence over the namespace default. Because deployment defaults are applied when a deployment is created, existing deployments don't pick up a new default. Set their scheduling per deployment instead.
Session clusters accept the same pods, jobManagerPodTemplate, and taskManagerPodTemplate settings through the session cluster API. The console has no separate scheduling editor for session clusters. A session cluster created in the console copies the scheduling from the namespace's deployment defaults at creation time. To change scheduling on an existing session cluster, use the session cluster API.
In BYOC, each workspace maps to one namespace, so for tenant isolation use one workspace per tenant, each with its own namespace default.
Schedule Flink JobManager and TaskManager Pods
The Flink pod scheduling editor, for both the namespace default and a single deployment, takes three optional blocks. pods applies to both roles, and each pod template applies to one role:
1pods: # JobManager and TaskManager
2 nodeSelector: {}
3 tolerations: []
4 affinity: {}
5jobManagerPodTemplate: # JobManager only
6 spec:
7 nodeSelector: {}
8 tolerations: []
9 affinity: {}
10taskManagerPodTemplate: # TaskManager only
11 spec:
12 nodeSelector: {}
13 tolerations: []
14 affinity: {}When a field is set both in pods and in a role's template, the values combine as follows:
To give the JobManager and TaskManagers different affinity rules, leave pods.affinity empty and set affinity only in the two pod templates. Otherwise both roles get the affinity from pods.
BYOC ignores securityContext and serviceAccountName in the pod templates.
To set scheduling for a deployment through the API, update the deployment's kubernetes field with PUT /api/v2/workspaces/{workspace}/namespaces/{namespace}/deployments/{deploymentId}. The request replaces the whole deployment, so retrieve the deployment first, modify the field, and send the full object back. Namespace defaults are configured in the console. See the API reference for the request schema.
When Changes Take Effect
Scheduling changes wait for the next pod creation.
Kubernetes never moves a running pod because its scheduling rules changed.
Examples
The examples use illustrative label and taint names. Replace them with the labels and taints on your node groups. Some node labels, such as capacity type, depend on your cloud provider and node provisioner.
A toleration only allows a pod onto a tainted node; it doesn't send the pod there. A dedicated node group needs a taint on the nodes, plus a toleration and a node selector or affinity on the pods.
Dedicated Flink Node Group per Tenant
Give each tenant's node group a label, such as tenant=analytics, and a taint, such as dedicated=analytics:NoSchedule. Then set this as the namespace default in that tenant's workspace:
1pods:
2 nodeSelector:
3 tenant: analytics
4 tolerations:
5 - key: dedicated
6 operator: Equal
7 value: analytics
8 effect: NoScheduleThe taint keeps other pods off the node group, and the node selector keeps this tenant's Flink pods on it. New deployments pick up the default automatically. Set the same block on existing deployments individually.
JobManager and TaskManagers on Different Nodes
For a large stateful job, split the roles with the pod templates and leave pods.affinity unset:
1pods:
2 nodeSelector:
3 tenant: analytics
4 tolerations:
5 - key: dedicated
6 operator: Equal
7 value: analytics
8 effect: NoSchedule
9jobManagerPodTemplate:
10 spec:
11 nodeSelector:
12 capacity: on-demand
13taskManagerPodTemplate:
14 spec:
15 affinity:
16 nodeAffinity:
17 requiredDuringSchedulingIgnoredDuringExecution:
18 nodeSelectorTerms:
19 - matchExpressions:
20 - key: node.kubernetes.io/instance-type
21 operator: In
22 values: [r6i.2xlarge, r7i.2xlarge]Because nodeSelector merges by key, the JobManager gets both tenant: analytics and capacity: on-demand. The TaskManagers keep the tenant selector and toleration and add the instance type rule.
Verify and Troubleshoot
After a restart, check where the pods landed and which scheduling rules they received:
1# Which node each pod runs on
2kubectl get pods -n <flink-namespace> -o wide
3
4# The scheduling rules the pod received
5kubectl get pod <pod> -n <namespace> \
6 -o jsonpath='{.spec.nodeSelector}{"\n"}{.spec.affinity}{"\n"}{.spec.tolerations}{"\n"}'
7
8# Labels and taints on the nodes
9kubectl get nodes --show-labels
10kubectl describe node <node> | grep -A3 TaintsIf the pod spec doesn't show your rules, check that:
- The deployment was restarted after the change.
- The deployment was created after the namespace default changed. Existing deployments don't pick up a new default.
pods.affinityisn't overriding the affinity in a role's pod template.
If the spec shows your rules but the pod runs on the wrong node, check the node labels.
A pod stuck in Pending usually means that no node satisfies every hard rule. A typo in a label value leaves the pod Pending rather than falling back to another node. The Events section of kubectl describe pod <pod> shows the reason:
If the cluster autoscaler doesn't add nodes for a Pending Flink pod, check that the node group's launch template or node pool declares the same labels and taints. An autoscaler that scales up from zero nodes only knows the labels and taints that the template declares.
Recommended Rollout
Roll out scheduling in a non-production workspace first, so that a misconfiguration only affects a test job:
- Label and taint the target node groups in your cloud provider, and declare the same labels and taints in the launch templates or node pools.
- Set the namespace default for Flink pods, create a test deployment, and check its placement with
kubectl get pods -o wide. - Set scheduling on existing deployments individually, and restart each one from a savepoint.
- Repeat in production. Restart deployments during maintenance windows.
Prefer a node selector plus a taint and toleration for the base rule, and use affinity for exceptions. Keep anti-affinity rules preferred unless a hard guarantee is worth the risk of pods not starting.