Kubernetes 调度器是如何工作的
Kubernetes

> 
> 了解 Kubernetes 调度器是如何发现新的吊舱并将其分配到节点。
> 
> 
> 


![](/data/attachment/album/202102/26/123446popgvrc0vppptvtk.jpg "Parts, modules, containers for software")


[Kubernetes](https://kubernetes.io/) 已经成为容器和容器化工作负载的标准编排引擎。它提供一个跨公有云和私有云环境的通用和开源的抽象层。


对于那些已经熟悉 Kuberbetes 及其组件的人，他们的讨论通常围绕着如何尽量发挥 Kuberbetes 的功能。但当你刚刚开始学习 Kubernetes 时，尝试在生产环境中使用前，明智的做法是从一些关于 Kubernetes 相关组件（包括 [Kubernetes 调度器](https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/)） 开始学习，如下抽象视图中所示：


![](/data/attachment/album/202102/26/123502gj4x8x7vg35y88vb.png)


Kubernetes 也分为控制平面和工作节点：


1. **控制平面：** 也称为主控，负责对集群做出全局决策，以及检测和响应集群事件。控制平面组件包括：


* etcd
* kube-apiserver
* kube-controller-manager
* 调度器


2. **工作节点：** 也称节点，这些节点是工作负载所在的位置。它始终和主控联系，以获取工作负载运行所需的信息，并与集群外部进行通讯和连接。工作节点组件包括：


* kubelet
* kube-proxy
* CRI


我希望这个背景信息可以帮助你理解 Kubernetes 组件是如何关联在一起的。


### Kubernetes 调度器是如何工作的


Kubernetes <ruby> <a href="https://kubernetes.io/docs/concepts/workloads/pods/">  吊舱 </a> <rt>  pod </rt></ruby> 由一个或多个容器组成组成，共享存储和网络资源。Kubernetes 调度器的任务是确保每个吊舱分配到一个节点上运行。


（LCTT 译注：容器技术领域大量使用了航海比喻，pod 一词，意为“豆荚”，在航海领域指“吊舱” —— 均指盛装多个物品的容器。常不翻译，考虑前后文，可译做“吊舱”。）


在更高层面下，Kubernetes 调度器的工作方式是这样的：


1. 每个需要被调度的吊舱都需要加入到队列
2. 新的吊舱被创建后，它们也会加入到队列
3. 调度器持续地从队列中取出吊舱并对其进行调度


[调度器源码](https://github.com/kubernetes/kubernetes/blob/e4551d50e57c089aab6f67333412d3ca64bc09ae/plugin/pkg/scheduler/scheduler.go)（`scheduler.go`）很大，约 9000 行，且相当复杂，但解决了重要问题：


#### 等待/监视吊舱创建的代码


监视吊舱创建的代码始于 `scheduler.go` 的 8970 行，它持续等待新的吊舱：



```
// Run begins watching and scheduling. It waits for cache to be synced, then starts a goroutine and returns immediately.

func (sched *Scheduler) Run() {
        if !sched.config.WaitForCacheSync() {
                return
        }

        go wait.Until(sched.scheduleOne, 0, sched.config.StopEverything)

```

#### 负责对吊舱进行排队的代码


负责对吊舱进行排队的功能是：



```
// queue for pods that need scheduling
        podQueue *cache.FIFO

```

负责对吊舱进行排队的代码始于 `scheduler.go` 的 7360 行。当事件处理程序触发，表明新的吊舱显示可用时，这段代码将新的吊舱加入队列中：



```
func (f *ConfigFactory) getNextPod() *v1.Pod {
        for {
                pod := cache.Pop(f.podQueue).(*v1.Pod)
                if f.ResponsibleForPod(pod) {
                        glog.V(4).Infof("About to try and schedule pod %v", pod.Name)
                        return pod
                }
        }
}

```

#### 处理错误代码


在吊舱调度中不可避免会遇到调度错误。以下代码是处理调度程序错误的方法。它监听 `podInformer` 然后抛出一个错误，提示此吊舱尚未调度并被终止：



```
// scheduled pod cache
        podInformer.Informer().AddEventHandler(
                cache.FilteringResourceEventHandler{
                        FilterFunc: func(obj interface{}) bool {
                                switch t := obj.(type) {
                                case *v1.Pod:
                                        return assignedNonTerminatedPod(t)
                                default:
                                        runtime.HandleError(fmt.Errorf("unable to handle object in %T: %T", c, obj))
                                        return false
                                }
                        },

```

换句话说，Kubernetes 调度器负责如下：


* 将新创建的吊舱调度至具有足够空间的节点上，以满足吊舱的资源需求。
* 监听 kube-apiserver 和控制器是否创建新的吊舱，然后调度它至集群内一个可用的节点。
* 监听未调度的吊舱，并使用 `/binding` 子资源 API 将吊舱绑定至节点。


例如，假设正在部署一个需要 1 GB 内存和双核 CPU 的应用。因此创建应用吊舱的节点上需有足够资源可用，然后调度器会持续运行监听是否有吊舱需要调度。


### 了解更多


要使 Kubernetes 集群工作，你需要使以上所有组件一起同步运行。调度器有一段复杂的的代码，但 Kubernetes 是一个很棒的软件，目前它仍是我们在讨论或采用云原生应用程序时的首选。


学习 Kubernetes 需要精力和时间，但是将其作为你的专业技能之一能为你的职业生涯带来优势和回报。有很多很好的学习资源可供使用，而且 [官方文档](https://kubernetes.io/docs/home/) 也很棒。如果你有兴趣了解更多，建议从以下内容开始：


* [Kubernetes the hard way](https://github.com/kelseyhightower/kubernetes-the-hard-way)
* [Kubernetes the hard way on bare metal](https://github.com/Praqma/LearnKubernetes/blob/master/kamran/Kubernetes-The-Hard-Way-on-BareMetal.md)
* [Kubernetes the hard way on AWS](https://github.com/Praqma/LearnKubernetes/blob/master/kamran/Kubernetes-The-Hard-Way-on-AWS.md)


你喜欢的 Kubernetes 学习方法是什么？请在评论中分享吧。




---


via: <https://opensource.com/article/20/11/kubernetes-scheduler>


作者：[Mike Calizo](https://opensource.com/users/mcalizo) 选题：[lujun9972](https://github.com/lujun9972) 译者：[MZqk](https://github.com/MZqk) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
[Kubernetes](https://kubernetes.io/) has emerged as the standard orchestration engine for containers and containerized workloads. It provides a common, open source abstraction layer that spans public and private cloud environments.

For those already familiar with Kubernetes and its components, the conversation is usually around maximizing Kubernetes' power. But when you're just learning Kubernetes, it's wise to begin with some general knowledge about Kubernetes and its components (including the [Kubernetes scheduler](https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/)), as shown in this high-level view, before trying to use it in production.

Kubernetes also uses control planes and nodes.

**Control plane:**Also known as master, these nodes are responsible for making global decisions about the clusters and detecting or responding to cluster events. The control plane components are:- etcd
- kube-apiserver
- kube-controller-manager
- scheduler

**Nodes:**Also called worker nodes, these sets of nodes are where a workload resides. They should always talk to the control plane to get the information necessary for the workload to run and to communicate and connect outside the cluster. Worker nodes' components are:- kubelet
- kube-proxy
- container runtime Interface.


I hope this background helps you understand how the Kubernetes components are stacked together.

## How Kubernetes scheduler works


A Kubernetes [pod](https://kubernetes.io/docs/concepts/workloads/pods/) is comprised of one or more containers with shared storage and network resources. The Kubernetes scheduler's task is to ensure that each pod is assigned to a node to run on.

At a high level, here is how the Kubernetes scheduler works:

- Every pod that needs to be scheduled is added to a queue
- When new pods are created, they are also added to the queue
- The scheduler continuously takes pods off that queue and schedules them

The [scheduler's code](https://github.com/kubernetes/kubernetes/blob/e4551d50e57c089aab6f67333412d3ca64bc09ae/plugin/pkg/scheduler/scheduler.go) (`scheduler.go`

) is large, around 9,000 lines, and fairly complex, but the important bits to tackle are:

-
**Code that waits/watches for pod creation**

The code that watches for pod creation begins on line 8970 of`scheduler.go`

; it waits indefinitely for new pods:`// Run begins watching and scheduling. It waits for cache to be synced, then starts a goroutine and returns immediately. func (sched *Scheduler) Run() { if !sched.config.WaitForCacheSync() { return } go wait.Until(sched.scheduleOne, 0, sched.config.StopEverything)`

-
**Code that is responsible for queuing the pod**

The function responsible for pod queuing is:`// queue for pods that need scheduling podQueue *cache.FIFO`

The code responsible for queuing the pod begins on line 7360 of

`scheduler.go`

. When the event handler is triggered to indicate that a new pod is available, this piece of code automatically puts the new pod in the queue:`func (f *ConfigFactory) getNextPod() *v1.Pod { for { pod := cache.Pop(f.podQueue).(*v1.Pod) if f.ResponsibleForPod(pod) { glog.V(4).Infof("About to try and schedule pod %v", pod.Name) return pod } } }`

-
**Code that handles errors**

You will inevitably encounter scheduling errors in pod scheduling. The following code is how the scheduler handles the errors. It listens to`podInformer`

and then spits out an error that the pod was not scheduled and terminates:`// scheduled pod cache podInformer.Informer().AddEventHandler( cache.FilteringResourceEventHandler{ FilterFunc: func(obj interface{}) bool { switch t := obj.(type) { case *v1.Pod: return assignedNonTerminatedPod(t) default: runtime.HandleError(fmt.Errorf("unable to handle object in %T: %T", c, obj)) return false } },`


In other words, the Kubernetes scheduler is responsible for:

- Scheduling the newly created pods on nodes with enough space to satisfy the pod's resource needs
- Listening to the kube-apiserver and the controller for the presence of newly created pods and then scheduling them to an available node on the cluster
- Watching for unscheduled pods and binding them to nodes by using the
`/binding`

pod sub-resource API.

For example, imagine an application is being deployed that requires 1GB of memory and two CPU cores. Therefore, the pods for the application are created on a node that has enough resources available. Then, the scheduler continues to run forever, watching to see if there are pods that need to be scheduled.

## Learn more

To have a working Kubernetes cluster, you need to get all the components above working together in sync. The scheduler is a complex piece of code, but Kubernetes is awesome software, and currently, it's the default choice when talking about adopting cloud-native applications.

Learning Kubernetes requires time and effort, but having it as one of your skills will give you an edge that should bring rewards in your career. There are a lot of good learning resources available, and the [documentation](https://kubernetes.io/docs/home/) is good. If you are interested in learning more, I recommend starting with:

What are your favorite ways to learn about Kubernetes? Please share in the comments.

## Comments are closed.