Kubernetes之Scheduler详解

news2024/10/6 20:33:01

本文尝试从Kubernetes Scheduler的功能介绍、交互逻辑、伪代码实现、最佳实践、自定义Scheduler举例及其历史演进6个方面进行详细阐述。希望对您有所帮助!

一、Kubernetes Scheduler 功能

Kubernetes Scheduler 是 Kubernetes 集群的核心组件之一,负责将新创建的 Pod 分配到合适的节点上。它根据一系列规则和策略,确保集群资源的最佳利用和应用的高效运行。以下是 Kubernetes Scheduler 的功能详解。

1. Scheduler 工作流程

Kubernetes Scheduler 的工作流程主要包括以下几个步骤:

  1. 监听未分配的 Pod:Scheduler 监听 API Server,当有新的 Pod 被创建且未绑定到任何节点时,Scheduler 会将其加入调度队列中。
  2. 预选节点(Filtering):Scheduler 通过一系列过滤规则筛选出符合条件的节点。例如,节点是否有足够的资源(CPU、内存等)、节点是否满足 Pod 的亲和性/反亲和性规则等。
  3. 优选节点(Scoring):对通过过滤的节点进行打分,依据不同的优选规则对节点进行评分(如节点资源的剩余情况、Pod 分布等),最终选择得分最高的节点。
  4. 绑定 Pod 到节点:Scheduler 将 Pod 绑定到选定的节点,API Server 会更新 Pod 的状态。

2. Scheduler 的主要功能

节点过滤(Predicates)

节点过滤是调度过程中的第一步,主要包括以下几种过滤规则:

  • PodFitsResources:检查节点是否有足够的资源(CPU、内存等)供 Pod 使用。
  • PodFitsHostPorts:检查节点上是否有指定的主机端口可用。
  • PodFitsHost:检查 Pod 是否要求运行在特定的节点上。
  • NoDiskConflict:检查节点上是否有 Pod 使用了同一持久卷。
  • MatchNodeSelector:检查节点标签是否满足 Pod 的节点选择器要求。
  • CheckNodeUnschedulable:检查节点是否可调度。
  • PodToleratesNodeTaints:检查 Pod 是否容忍节点的污点。
节点优选(Priorities)

在通过过滤规则后,Scheduler 会对符合条件的节点进行打分,依据不同的优选规则对节点进行评分:

  • LeastRequestedPriority:优先选择资源请求最少的节点。
  • BalancedResourceAllocation:优先选择资源分配最平衡的节点。
  • NodePreferAvoidPodsPriority:优先选择没有被其他 Pod 标记为“避开”的节点。
  • NodeAffinityPriority:依据节点亲和性规则对节点进行打分。
  • TaintTolerationPriority:依据污点容忍规则对节点进行打分。
Pod 亲和性和反亲和性(Pod Affinity and Anti-Affinity)

Pod 亲和性和反亲和性允许用户定义更复杂的调度规则,以确保 Pod 能够调度到特定的节点或避免调度到某些节点。例如,可以定义 Pod 必须与某些标签的 Pod 在同一节点上,或者必须与某些标签的 Pod 不在同一节点上。

节点亲和性(Node Affinity)

节点亲和性允许用户定义 Pod 只能调度到某些特定的节点。它是节点选择器的更灵活和表达力更强的形式,可以基于节点的标签进行配置。

Taints 和 Tolerations

Taints 和 Tolerations 用于避免 Pod 被调度到不适合的节点。节点可以有污点(Taints),只有容忍这些污点(Tolerations)的 Pod 才能被调度到这些节点上。

3. 自定义 Scheduler

Kubernetes 允许用户编写和部署自定义的调度器,替代默认的调度器或与之共存。以下是编写自定义调度器的基本步骤:

  1. 创建调度器插件:基于 Kubernetes 提供的调度框架,创建新的调度插件。调度插件可以是过滤插件、打分插件、预绑定插件等。
  2. 配置调度器:在 kube-scheduler 配置文件中添加或修改调度插件。
  3. 部署自定义调度器:将自定义调度器部署到 Kubernetes 集群中,并在 Pod 定义中指定使用自定义调度器。

4. 调试和监控

Kubernetes Scheduler 提供了多种调试和监控工具,以便用户了解调度过程并解决调度问题。例如:

  • 调度事件日志:Scheduler 会记录调度过程中的事件日志,可以通过查看这些日志来了解调度过程。
  • 调度指标:Scheduler 提供了一些 Prometheus 指标,可以用来监控调度性能和调度决策。

通过上述功能和工具,Kubernetes Scheduler 能够实现灵活、高效的调度策略,满足不同应用的需求。

二、Kubernetes Scheduler与其他组件交互示意图

下图表示 Kubernetes Scheduler 与其他组件交互过程 。图示包括 API Server、Scheduler、Controller Manager、etcd、Kubelet 和节点。

示意图

User API Server Scheduler Controller Manager etcd Kubelet Node Create Pod Store Pod Spec Acknowledge Pod Creation Notify of Pending Pod Get Pod Spec Get Node Information Node Information Filter Nodes Score Nodes Bind Pod to Node Update Pod Binding Acknowledge Binding Notify of Pod Update Get Pod Spec Update Pod Status Notify of Pod Assignment Get Pod Spec Create and Start Pod Pod Running Update Pod Status Store Pod Status Pod Running User API Server Scheduler Controller Manager etcd Kubelet Node

交互流程解释

  1. 用户创建 Pod

    • 用户向 API Server 提交 Pod 创建请求。
    • API Server 将 Pod 的配置信息存储在 etcd 中,并确认创建成功。
  2. 调度 Pod

    • API Server 通知 Scheduler 有新的待调度 Pod。
    • Scheduler 从 API Server 获取 Pod 的配置信息,并从 etcd 获取集群中节点的信息。
    • Scheduler 过滤和打分节点,选择最合适的节点。
    • Scheduler 将 Pod 绑定到选定的节点,并通知 API Server。
  3. 更新 Pod 绑定信息

    • API Server 将 Pod 的绑定信息更新到 etcd。
    • Scheduler 确认绑定成功。
  4. 控制器管理 Pod

    • API Server 通知 Controller Manager Pod 的更新信息。
    • Controller Manager 从 etcd 获取 Pod 配置信息,并更新 Pod 的状态。
  5. Kubelet 启动 Pod

    • API Server 通知 Kubelet Pod 已分配到其管理的节点上。
    • Kubelet 从 etcd 获取 Pod 的配置信息。
    • Kubelet 在节点上创建并启动 Pod。
    • 节点返回 Pod 的运行状态给 Kubelet。
    • Kubelet 更新 Pod 的状态到 API Server。
  6. 存储 Pod 状态并通知用户

    • API Server 将 Pod 的运行状态存储到 etcd。
    • API Server 通知用户 Pod 处于运行状态。

通过这个交互示意图和解释,可以清晰地了解 Kubernetes Scheduler 与其他组件的交互流程和机制。

三、Kubernetes Scheduler伪代码实现

下面是一个使用 Go 语言编写的 Kubernetes Scheduler 功能的伪代码示例。此示例包括基本的调度流程,包括从 API Server 获取未调度的 Pod,筛选节点,评分节点,并将 Pod 绑定到选定的节点。

Kubernetes Scheduler 伪代码

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    "path/filepath"
    "k8s.io/kubernetes/pkg/scheduler"
    "k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources"
    "k8s.io/kubernetes/pkg/scheduler/framework/plugins/registry"
    "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
)

func main() {
    // 加载Kubernetes配置
    var kubeconfig string
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = filepath.Join(home, ".kube", "config")
    }

    config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
    if err != nil {
        log.Fatalf("Error building kubeconfig: %s", err.Error())
    }

    // 创建Kubernetes客户端
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        log.Fatalf("Error creating Kubernetes client: %s", err.Error())
    }

    // 注册调度插件
    registry := registry.NewRegistry()
    pluginFactory := noderesources.NewFit
    registry.Register("NodeResourcesFit", pluginFactory)

    // 创建调度框架
    schedulerFramework, err := runtime.NewFramework(registry, nil, nil)
    if err != nil {
        log.Fatalf("Error creating scheduler framework: %s", err.Error())
    }

    // 创建自定义调度器
    sched := scheduler.New(
        clientset,
        schedulerFramework,
        nil,
        context.TODO(),
        "custom-scheduler",
    )

    // 主调度循环
    for {
        pod := getPendingPod(clientset)
        if pod != nil {
            nodes := getNodes(clientset)
            filteredNodes := filterNodes(pod, nodes)
            if len(filteredNodes) > 0 {
                bestNode := scoreNodes(pod, filteredNodes)
                bindPodToNode(clientset, pod, bestNode)
            }
        }
        time.Sleep(1 * time.Second)
    }
}

// 获取未调度的Pod
func getPendingPod(clientset *kubernetes.Clientset) *v1.Pod {
    pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatalf("Error listing pods: %s", err.Error())
    }
    for _, pod := range pods.Items {
        if pod.Spec.NodeName == "" {
            return &pod
        }
    }
    return nil
}

// 获取所有节点
func getNodes(clientset *kubernetes.Clientset) []v1.Node {
    nodes, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatalf("Error listing nodes: %s", err.Error())
    }
    return nodes.Items
}

// 节点过滤
func filterNodes(pod *v1.Pod, nodes []v1.Node) []v1.Node {
    var filteredNodes []v1.Node
    for _, node := range nodes {
        if nodeHasSufficientResources(pod, &node) {
            filteredNodes = append(filteredNodes, node)
        }
    }
    return filteredNodes
}

// 检查节点是否有足够资源
func nodeHasSufficientResources(pod *v1.Pod, node *v1.Node) bool {
    // 实现资源检查逻辑,如CPU和内存是否足够
    return true
}

// 节点评分
func scoreNodes(pod *v1.Pod, nodes []v1.Node) *v1.Node {
    var bestNode *v1.Node
    var highestScore int
    for _, node := range nodes {
        score := calculateNodeScore(pod, &node)
        if score > highestScore {
            highestScore = score
            bestNode = &node
        }
    }
    return bestNode
}

// 计算节点分数
func calculateNodeScore(pod *v1.Pod, node *v1.Node) int {
    // 实现评分逻辑,如节点的资源利用率、亲和性等
    return 0
}

// 绑定Pod到节点
func bindPodToNode(clientset *kubernetes.Clientset, pod *v1.Pod, node *v1.Node) {
    binding := &v1.Binding{
        ObjectMeta: metav1.ObjectMeta{Name: pod.Name, Namespace: pod.Namespace},
        Target: v1.ObjectReference{
            Kind: "Node",
            Name: node.Name,
        },
    }
    err := clientset.CoreV1().Pods(pod.Namespace).Bind(context.TODO(), binding, metav1.CreateOptions{})
    if err != nil {
        log.Fatalf("Error binding pod: %s", err.Error())
    } else {
        fmt.Printf("Successfully bound pod %s to node %s\n", pod.Name, node.Name)
    }
}

伪代码解释

  1. 主函数

    • 加载 Kubernetes 配置并创建 Kubernetes 客户端。
    • 注册调度插件并创建调度框架。
    • 创建自定义调度器,并进入主调度循环。
  2. 主调度循环

    • 获取未调度的 Pod。
    • 获取所有节点。
    • 过滤节点,找出符合条件的节点。
    • 对符合条件的节点进行评分,选择得分最高的节点。
    • 将 Pod 绑定到选定的节点。
  3. 辅助函数

    • getPendingPod:获取未调度的 Pod。
    • getNodes:获取所有节点。
    • filterNodes:根据资源要求过滤节点。
    • nodeHasSufficientResources:检查节点是否有足够资源。
    • scoreNodes:对符合条件的节点进行评分。
    • calculateNodeScore:计算节点的分数。
    • bindPodToNode:将 Pod 绑定到选定的节点。

这个伪代码示例展示了一个基本的自定义调度器的工作流程和关键函数。实际实现中,你可以根据具体需求扩展和修改这些函数。

下面是表示上述自定义 Kubernetes Scheduler 伪代码的调用图。这张图展示了调度器的主要流程,包括获取未调度的 Pod、获取节点、过滤节点、评分节点以及将 Pod 绑定到选定节点的过程。

Nodes
etcd
Kubernetes API
No
Yes
No
Yes
Communicates
Fetch Pods
Fetch Nodes
Bind Pod
Stores
Node1
Node2
Node3
Filter Nodes
Score Nodes
Pod & Node Information
API Server
Start Scheduler
Get Pending Pod
Get Nodes
Bind Pod to Node
Pod Found?
Filtered Nodes Found?
Select Best Node
Log Success

图解说明

  1. Start Scheduler

    • 调度器启动并进入主循环。
  2. Get Pending Pod

    • 从 API Server 获取未调度的 Pod。
  3. Pod Found?

    • 判断是否找到未调度的 Pod,如果没有找到则返回主循环继续检查。
  4. Get Nodes

    • 从 API Server 获取所有节点的信息。
  5. Filter Nodes

    • 根据资源要求和调度规则过滤节点。
  6. Filtered Nodes Found?

    • 判断是否有符合条件的节点,如果没有找到则返回主循环。
  7. Score Nodes

    • 对符合条件的节点进行评分。
  8. Select Best Node

    • 选择得分最高的节点。
  9. Bind Pod to Node

    • 将 Pod 绑定到选定的节点,并更新 API Server。
  10. Log Success

    • 记录绑定成功的日志。
  11. Communicates with Kubernetes API

    • 调度器通过 API Server 与 Kubernetes 交互,获取 Pod 和节点信息,更新绑定状态。
  12. etcd

    • API Server 将 Pod 和节点信息存储到 etcd 中。
  13. Nodes

    • 显示集群中的节点,调度器对这些节点进行过滤和评分。

该图直观地展示了自定义 Kubernetes Scheduler 的主要工作流程和与其他组件的交互。

四、自定义 Kubernetes Scheduler最佳实践

自定义 Kubernetes Scheduler 是一个高级主题,需要仔细考虑和实现,确保它能够有效地管理和调度 Pod 到集群中的节点。以下是一些关于自定义 Kubernetes Scheduler 的最佳实践:

1. 确定需求和场景

在开始之前,确保明确你的需求和场景。了解你想要实现的特定调度逻辑和策略,例如特定的资源分配、亲和性/反亲和性需求、定制化的节点选择算法等。理解这些需求将有助于指导你设计和实现自定义 Scheduler。

2. 使用 Kubernetes 提供的调度框架和插件

Kubernetes 提供了灵活的调度框架和各种插件,例如节点资源调度、亲和性/反亲和性、污点和容忍等。在自定义 Scheduler 时,可以基于现有的调度框架进行扩展和定制化,使用已有的调度插件或编写新的插件以满足特定需求。

3. 编写调度器代码

编写自定义 Scheduler 的代码时,考虑以下几点:

  • 初始化 Kubernetes 客户端:确保能够与 Kubernetes API Server 进行通信。
  • 注册调度插件:根据需要注册适合的调度插件,如节点资源调度插件、亲和性/反亲和性插件等。
  • 实现调度逻辑:在主循环中实现从 API Server 获取未调度的 Pod、获取节点列表、过滤和评分节点、绑定 Pod 到节点等核心调度逻辑。
  • 错误处理和日志记录:添加适当的错误处理机制,并记录调度过程中的关键事件和决策。

4. 测试和验证

在部署自定义 Scheduler 之前,进行充分的测试和验证是必不可少的步骤。确保你的 Scheduler 能够正确地处理各种场景和边界条件,例如不同类型的 Pod、不同的节点状态、并发调度等。

5. 部署和监控

部署自定义 Scheduler 到 Kubernetes 集群后,确保能够有效地监控其性能和行为。使用 Kubernetes 提供的监控工具(如 Prometheus)或自定义指标来收集调度器的运行数据,并及时调整和优化调度策略。

6. 考虑安全性和可扩展性

在设计和实现自定义 Scheduler 时,要考虑安全性和可扩展性。确保 Scheduler 的操作是安全的,并且可以在集群的规模和负载增加时保持稳定和高效。

示例实现

以下是一个简单的示例实现,展示了如何使用 Go 和 Kubernetes 客户端库来创建自定义 Scheduler:

  • 初始化 Kubernetes 客户端和调度器框架。
  • 注册节点资源调度插件。
  • 实现调度逻辑,包括节点过滤、评分和绑定 Pod 到节点。
  • 在主循环中运行调度器,并持续监视未调度的 Pod。
// 请参考前面给出的Go语言伪代码实现。

通过遵循这些最佳实践,你可以成功地设计、开发和部署自定义 Kubernetes Scheduler,以满足特定的业务需求和调度策略。

五、自定义Kubernetes Scheduler示例

自定义 Kubernetes Scheduler 允许你定义调度逻辑以满足特定需求。下面是如何创建、配置和部署自定义 Scheduler 的详细步骤。

步骤 1:编写自定义调度器

你可以使用 Go 语言编写自定义调度器。以下是一个基本的自定义调度器示例:

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    "path/filepath"
    "k8s.io/kubernetes/pkg/scheduler"
    "k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources"
    "k8s.io/kubernetes/pkg/scheduler/framework/plugins/registry"
    "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
)

func main() {
    var kubeconfig string
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = filepath.Join(home, ".kube", "config")
    }

    config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
    if err != nil {
        log.Fatalf("Error building kubeconfig: %s", err.Error())
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        log.Fatalf("Error creating Kubernetes client: %s", err.Error())
    }

    registry := registry.NewRegistry()
    pluginFactory := noderesources.NewFit
    registry.Register("NodeResourcesFit", pluginFactory)

    schedulerFramework, err := runtime.NewFramework(registry, nil, nil)
    if err != nil {
        log.Fatalf("Error creating scheduler framework: %s", err.Error())
    }

    sched := scheduler.New(
        clientset,
        schedulerFramework,
        nil,
        context.TODO(),
        "custom-scheduler",
    )

    for {
        err := sched.Run(context.TODO())
        if err != nil {
            log.Printf("Error running scheduler: %s", err.Error())
        }
        time.Sleep(1 * time.Second)
    }
}

步骤 2:构建 Docker 镜像

为你的自定义调度器创建一个 Docker 镜像。首先,创建一个 Dockerfile:

FROM golang:1.17 as builder

WORKDIR /go/src/custom-scheduler
COPY . .

RUN go get -d -v ./...
RUN go build -o custom-scheduler .

FROM alpine:latest
RUN apk --no-cache add ca-certificates

WORKDIR /root/
COPY --from=builder /go/src/custom-scheduler/custom-scheduler .

CMD ["./custom-scheduler"]

然后构建镜像:

docker build -t custom-scheduler:latest .

步骤 3:创建 Kubernetes Deployment

创建一个 Deployment 来运行自定义调度器:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: custom-scheduler
  labels:
    app: custom-scheduler
spec:
  replicas: 1
  selector:
    matchLabels:
      app: custom-scheduler
  template:
    metadata:
      labels:
        app: custom-scheduler
    spec:
      containers:
      - name: custom-scheduler
        image: custom-scheduler:latest
        imagePullPolicy: IfNotPresent
        command: ["./custom-scheduler"]
      serviceAccountName: system:scheduler

步骤 4:配置调度器名称

为你的 Pod 指定使用自定义调度器。在 Pod 定义中设置 schedulerName

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  schedulerName: custom-scheduler
  containers:
  - name: example-container
    image: nginx

步骤 5:部署和验证

  1. 部署自定义调度器:

    kubectl apply -f custom-scheduler-deployment.yaml
    
  2. 创建一个使用自定义调度器的 Pod:

    kubectl apply -f example-pod.yaml
    
  3. 检查 Pod 是否使用自定义调度器成功调度:

    kubectl get pod example-pod -o jsonpath='{.spec.schedulerName}'
    

总结

通过以上步骤,你可以编写、构建、部署和使用自定义 Kubernetes Scheduler。这使你能够实现更灵活和特定需求的调度逻辑。

六、Kubernetes Scheduler历史演进

Kubernetes Scheduler 是 Kubernetes 集群管理系统的核心组件之一,它负责将未分配节点的 Pod 分配到合适的节点上。自 Kubernetes 项目启动以来,Kubernetes Scheduler 也经历了显著的演进。以下是 Kubernetes Scheduler 的历史演进:

1. Kubernetes 早期版本(2014-2015)

1.1. 初始设计
  • Kubernetes 于 2014 年开源,最初的调度器设计非常简单,主要基于静态调度策略,如 CPU 和内存资源。
  • 调度算法主要基于 “First Fit” 策略,即选择第一个满足资源要求的节点。
1.2. 调度器插件机制
  • 初始版本中,调度逻辑内嵌在调度器代码中,缺乏灵活性和扩展性。

2. Kubernetes 1.0(2015)

2.1. 初步稳定
  • Kubernetes 1.0 版本标志着 Kubernetes 的首次正式发布。
  • 调度器引入了更复杂的调度策略,如节点亲和性和反亲和性。

3. Kubernetes 1.2-1.5(2016-2017)

3.1. Pod 优先级和抢占
  • 引入 Pod 优先级和抢占机制,以便更好地处理资源紧张的场景。
  • 调度器能够根据优先级调整 Pod 的调度顺序。
3.2. 多调度器支持
  • Kubernetes 支持用户自定义调度器,使得在同一个集群中可以运行多个调度器实例。

4. Kubernetes 1.6-1.9(2017-2018)

4.1. 调度器扩展点
  • 引入调度器扩展点机制,使得用户可以插入自定义的调度策略和插件,增强调度器的可扩展性。
4.2. 事件驱动的调度
  • 调度器逐步从定期扫描变为事件驱动,更高效地响应 Pod 和节点状态的变化。

5. Kubernetes 1.10-1.13(2018-2019)

5.1. 调度框架(Scheduling Framework)
  • Kubernetes 1.11 引入了调度框架(Scheduling Framework),允许用户通过插件扩展调度器的行为。
  • 这一框架提供了多个扩展点,如预过滤、过滤、优选、绑定等。
5.2. 调度器性能优化
  • 持续的性能优化,提升调度器在大规模集群中的表现。

6. Kubernetes 1.14-1.19(2019-2020)

6.1. 调度框架逐步稳定
  • 调度框架功能逐步完善,用户可以更加灵活地自定义调度逻辑。
  • 增加了更多内置插件,提升了调度器的默认能力。
6.2. 调度器配置文件(Scheduler Configuration)
  • 引入调度器配置文件,允许用户通过配置文件定制调度器行为,而无需修改代码。

7. Kubernetes 1.20-1.23(2020-2021)

7.1. 调度框架的广泛采用
  • 调度框架被广泛采用,并逐渐成为定制调度逻辑的标准方式。
  • 更多的社区插件和企业插件被开发出来,满足不同场景的需求。
7.2. 性能和稳定性提升
  • 持续的性能和稳定性改进,使调度器能够在更大规模和更复杂的环境中运行。

8. Kubernetes 1.24+(2022-至今)

8.1. 提升调度器的智能化
  • 引入更多智能化的调度策略和算法,如机器学习驱动的调度。
  • 增加对异构资源(如 GPU、FPGA)的更好支持。
8.2. 多集群调度
  • 支持多集群环境中的调度需求,使得调度器能够跨多个 Kubernetes 集群进行资源调度。
8.3. 提升调度器的可观测性
  • 增加更多调度器的可观测性特性,使得管理员能够更好地了解调度决策和调度过程。

总结

Kubernetes Scheduler 的演进反映了 Kubernetes 社区对调度需求的不断理解和优化。随着 Kubernetes 的发展,调度器变得更加智能、灵活和高效,以应对现代应用程序的复杂需求和大规模集群的挑战。未来,调度器将继续演进,以支持更多新兴的计算资源和调度策略。

完。
希望对您有用!关注锅总,及时获得更多花里胡哨的运维实用操作!

一个秘密

在这里插入图片描述
锅总个人博客

https://gentlewok.blog.csdn.net/

锅总微信公众号
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1871067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用jupyter打开本地ipynb文件的方法

常用方法: 先启动jupyter,然后在打开的页面点击upload,选择想要打开的文件上传然后打开,但是这样其实是先复制了一份到jupyter中,然后打开运行。而我不想复制。 方法二 先打开项目文件所在文件夹,文件夹…

M芯片 Parallels Desktop 19虚拟机安装Windows11教程

Parallels Desktop 19 for Mac 乃是一款适配于 Mac 的虚拟化软件。它能让您在 Mac 计算机上同时运行多个操作系统。您可借此创建虚拟机,并于其中装设不同的操作系统,如 Windows、Linux 或 macOS。使用 Parallels Desktop 19 mac 版时,您可在 …

情感分析方法与实践

第1关:情感分析的基本方法 情感分析简介 情感分析,又称意见挖掘、倾向性分析等。简单而言,是对带有情感色彩的主观性文本进行分析、处理、归纳和推理的过程。在日常生活中,情感分析的应用非常普遍,下面列举几种常见的…

数据库和程序 按照层级进行排序

文章目录 先上效果图(四种方式实现)前期工作创建表添加表数据 第一种方式: 具体执行SQL更深层次的sql案例 第二种方式: 使用java程序动态的生成SQL进行执行单元测试注意事项 第三种方式: 使用java程序进行排序[单字段排序]第四种方式: 使用lambda方式进行排序[多字段排序]最后的…

一个最简单的MySQL事务模拟测试

这里只是简单写了一个转账的小事务,模拟一下事务的过程 代码: 初始数据: 当你关闭自动提交 并且开启一个事务执行了下面的更新语句 但是没有提交时: 此时虽然你运行查询语句会发现他的值发生了变化 ,但是当你运行回滚…

数据结构速成--树和二叉树

由于是速成专题,因此内容不会十分全面,只会涵盖考试重点,各学校课程要求不同 ,大家可以按照考纲复习,不全面的内容,可以看一下小编主页数据结构初阶的内容,找到对应专题详细学习一下。 气死了…

C++ ─── vector模拟实现的扩容拷贝问题

扩容拷贝问题 源代码使用memcpy拷贝&#xff0c;在使用vector<int>存储内置类型时没有问题&#xff0c; 但是如果存储的是含有指针的类型&#xff0c;如string&#xff0c;就会发生浅拷贝问题 //3、容量相关void reserve(size_t n){if (n > capacity()){size_t old_si…

【PWN · ret2libc | protobuf】[2024CISCN · 华中赛区]protoverflow

套了一层protobuf壳&#xff0c;然后就是简单的ret2libc 参考速递&#xff1a;深入二进制安全&#xff1a;全面解析Protobuf-CSDN博客 前言 第一次遇到protobuf&#xff0c;如果没有了解过&#xff0c;是显然做不出来的。此次复现&#xff0c;也算是点亮了一个技能点 一、什么…

Linux系统编程(七)进程间通信IPC

进程间通讯的7种方式_进程间通信的几种方法-CSDN博客 管道 pipe&#xff08;命名管道和匿名管道&#xff09;&#xff1b;信号 signal&#xff1b;共享内存&#xff1b;消息队列&#xff1b;信号量 semaphore&#xff1b;套接字 socket&#xff1b; 1. 管道 内核提供&#x…

Halcon 如何根据特征过滤区域和XLD

一 如何跟进特征过滤区域和XLD dev_open_window(0,0,512,512,black,WindowHandle)read_image(Image,fabrik)threshold(Image,Region,128,255)connection(Region,ConnectedRegions)*根据面积范围[8000,9000] dev_display(Image)select_shape(ConnectedRegions,SelectedRegions,…

Python和tkinter实现的字母记忆配对游戏

Python和tkinter实现的字母记忆配对游戏 因为这个小游戏用到了tkinter&#xff0c;先简要介绍一下它。tkinter是Python的标准GUI(图形用户界面)库&#xff0c;它提供了一种简单而强大的方式来创建图形界面应用程序。它提供了创建基本图形界面所需的所有工具&#xff0c;同时保…

【Pillow】module ‘PIL.Image‘ has no attribute ‘ANTIALIAS‘问题解决

问题描述 我在使用 SummaryWriter 记录图片数据日志时&#xff0c;遇到了报错&#xff0c;如下图所示&#xff1a; 问题的原因在于&#xff0c;使用的pillow版本已经舍弃了ANTIALIAS&#xff0c;在新版本中已经改为了LANCZOS 问题解决 两种解决方式&#xff1a; 修改源码更…

C++之STL(十一)

1、迭代器适配器 2、插入迭代器 #include <iostream> #include <vector> #include <algorithm> #include <list> using namespace std;void showVec(const vector<int>& v) {for (vector<int>::const_iterator it v.begin(); it ! v.…

如何使用大模型进行文本分类任务?

暑期实习基本结束了&#xff0c;校招即将开启。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友解惑答疑&…

视频上面怎样编辑文字?4种视频编辑文字方法分享

视频已成为我们日常生活中不可或缺的一部分。无论是社交分享、商业宣传还是个人记录&#xff0c;视频都以其直观、生动的特点吸引着观众的眼球。然而&#xff0c;一个优质的视频&#xff0c;除了画面和音效&#xff0c;文字编辑也是提升观看体验的关键。那么&#xff0c;如何在…

2024百度之星第二场-小度的01串

补题链接&#xff1a; 码蹄集 一道经典线段树板子题。 区间修改01置换&#xff0c;区间查询子串权值。 唯一区别&#xff0c;权值要求的是相邻字符都不同所需修改的最小字符个数。 我们在线段树节点上分别维护当前连续区间&#xff1a; 奇数位是0的个数&#xff08;j0&…

03逻辑门电路

分立门电路&#xff1a; 集成门电路&#xff1a; TTL门电路 MOS门电路&#xff1a;NMOS门电路、PMOS门电路、CMOS门电路 BICMOS门电路&#xff1a;CMOS的高输入阻抗和TTL的高放大倍数的结合 向更低功耗、更高速度发展 MOS管的Rdson在可变电阻区的阻值也一般会小于1000欧姆 …

【自动化测试】Selenium自动化测试框架 | 相关介绍 | Selenium + Java环境搭建 | 常用API的使用

文章目录 自动化测试一、selenium1.相关介绍1.Selenium IDE2.Webdriverwebdriver的工作原理&#xff1a; 3.selenium Grid 2.Selenium Java环境搭建3.常用API的使用1.定位元素2.操作测试对象3.添加等待4.打印信息5.浏览器的操作6.键盘事件7.鼠标事件8.定位一组元素9.多层框架定…

prompt:我是晚餐盲盒,只要你问出“今晚吃什么”我就将为你生成美妙的食物推荐。

使用方法&#xff1a;在ChatGP粘贴下面提示词模型&#xff0c;点击输出。然后再问“晚餐有什么好吃的&#xff1f;”&#xff0c;AI输出丰种食物供你选择。抽到什么吃什么&#xff0c;极大的解决选择困难的问题。 客户需要生成1000条俏皮灵动&#xff0c;趣味盎然&#xff0c;比…

VS2019安装插件image watch

image watch的作用&#xff1a; &#xff08;1&#xff09;放大、缩小图像&#xff1b; &#xff08;2&#xff09;将图像保存到指定的目录&#xff1b; &#xff08;3&#xff09;显示图像大小、通道数&#xff1b; &#xff08;4&#xff09;拖拽图像&#xff1b; &…