























kube-scheduler is responsible for scheduling and assigning Pods to nodes within the cluster. It listens to kube-apiserver, queries for Pods that haven’t been assigned to Nodes, and then assigns nodes to these Pods based on scheduling policies (updating the Pod’s NodeName field).
The scheduler needs to fully consider many factors:
kube-scheduler scheduling is divided into two phases, predicate and priority:
CPU
Memory
In k8s, request is used for scheduling. Pod can be scheduled if node remaining resources meet request value. limit has no effect in k8s system, just passed to cri.
In cri, when using cgroup to limit resources, how do they correspond?
Taking cpu resource as example:
Container ephemeral storage includes logs and writable layer data, which can be requested by defining limits.ephemeral-storage and requests.ephemeral-storage in Pod Spec. After Pod scheduling is completed, compute node’s limitation on ephemeral storage is not based on CGroup, but kubelet periodically gets container logs and container writable layer disk usage. If it exceeds limit, Pod will be evicted.
When kube-scheduler schedules Pod with multiple init containers, it only calculates the init container with most cpu.request, not the sum of all init containers. Since multiple init containers execute sequentially and exit immediately after completion, the resources required by init container with most resource requests can meet all init container requirements. When kube-scheduler calculates resources occupied by this node, init container resources are still included in calculation. Because init containers may be executed again under specific circumstances, such as when Sandbox is rebuilt due to image changes.
Pods can be scheduled to desired Nodes through nodeSelector, nodeAffinity, podAffinity, and Taints and tolerations. You can also schedule Pod to specific node by setting nodeName parameter.
For example, using nodeSelector, first add labels to Node
kubectl label nodes <your-node-name> disktype=ssd
Then, specify that this Pod only wants to run on Nodes with disktype=ssd label.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
nodeSelector:
disktype: ssd
First label the Node:
kubectl label nodes node-01 disktype=ssd
Then specify nodeSelector as disktype: ssd in daemonset:
spec:
nodeSelector:
disktype: ssd
NodeAffinity currently supports two types: requiredDuringSchedulingIgnoredDuringExecution and preferredDuringSchedulingIgnoredDuringExecution.
They represent must-satisfy conditions and preferred conditions respectively. For example, the following example represents preferring to schedule to nodes containing label disktype=ssd.
If no nodes satisfy this condition, it can still be scheduled.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
For example, the following example represents only scheduling to nodes containing label disktype=ssd.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
podAffinity selects Node based on Pod labels, only scheduling to Nodes where qualifying Pods are located, supporting podAffinity and podAntiAffinity.
This feature is quite complex, using the following example:
If a “Node runs pods containing at least one pod with a=b label”, then it can be scheduled to that Node, while also unable to schedule to “Nodes containing at least one running Pod with app=anti-nginx label”.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-anti
spec:
replicas: 2
selector:
matchLabels:
app: anti-nginx
template:
metadata:
labels:
app: anti-nginx
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: a
operator: In
values:
- b
topologyKey: kubernetes.io/hostname
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- anti-nginx
topologyKey: kubernetes.io/hostname
containers:
- name: with-pod-affinity
image: nginx
Taints and Tolerations are used to ensure Pods are not scheduled to inappropriate Nodes, where Taint is applied to Node and Toleration is applied to Pod.
Currently supported Taint types:
However, when Pod’s Tolerations match all Taints of Node, it can be scheduled to that Node; when Pod is already running, it won’t be deleted (evicted) either. Additionally for NoExecute, if Pod adds a tolerationSeconds, it will only delete Pod after that time.
Kubernetes clusters are generally universal clusters that can be shared by all users, with users not needing to care about compute node details. But often some customers with their own compute resources require:
Implementation solution:
Does this solution have loopholes? How to close them?
Experience from production systems
Starting from v1.8, kube-scheduler supports defining Pod priority, ensuring high-priority Pods are scheduled first. Enabling method:
Before specifying Pod priority, you need to first define a PriorityClass (non-namespace resource), such as:
apiVersion: v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for XYZ service pods only."
Then set priorityClass for pod:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
priorityClassName: high-priority
If the default scheduler doesn’t meet requirements, you can also deploy custom schedulers. Moreover, multiple scheduler instances can run simultaneously in the entire cluster, using podSpec.schedulerName to choose which scheduler to use (default uses built-in scheduler).
Small clusters:
Amplification effect:
Application bomb:
The scheduler can be said to be one of the components with best stability during operations, basically requiring no major maintenance effort.
According to init container resource requirements section, after pod startup, init container resources are still not reclaimed.
Scenario: init container needs large resources during initialization, which decreases after initialization is complete. How to optimize this situation?
CPU resources can be compressed, at worst initialization is slower, but memory resources cannot - less memory directly causes OOM.
Native k8s doesn’t optimize this situation. Community has a vertical scaling feature that can dynamically adjust pod resource requirements, but support is not as good as horizontal scaling.
cpuset, bind Pod with specific CPU cores, kubelet supports static cpu config
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。