Skip to content

Custom Scheduler 测验(第 1 部分)

本测验用于测试你对在 Kubernetes 中实现和使用 Custom Scheduler 的理解。

测验问题

1. 在 Kubernetes 中,scheduler 的主要作用是什么?

A. Pod 的创建和删除 B. 将 Pod 分配给合适的 Node C. Node 资源监控 D. Container image 下载

显示答案

答案: B. 将 Pod 分配给合适的 Node

解析: 在 Kubernetes 中,scheduler 的主要作用是将 Pod 分配给合适的 Node。scheduler 会监听新创建的 Pod,并为尚未分配到 Node 的 Pod 找到最适合运行它们的 Node。

Scheduler 的主要功能:

  1. Pod-Node 分配: 根据 Pod 需求和 Node 可用资源选择最优 Node。
  2. Filtering: 排除无法运行该 Pod 的 Node(例如资源不足、taints 等)。
  3. Scoring: 对合适的 Node 进行评分,以选择最优 Node。
  4. Binding: 将 Pod 绑定到所选 Node,以最终确定调度决策。

调度流程:

  1. Filtering Stage (Predicates): 排除无法运行该 Pod 的 Node。

    • PodFitsResources: 检查 Node 是否有足够资源满足 Pod 的 resource requests
    • PodFitsHostPorts: 检查请求的 host ports 是否可用
    • PodMatchNodeSelector: 检查 Pod 的 node selector 是否匹配 Node labels
    • NoVolumeZoneConflict: 检查 volume zone 约束
    • CheckNodeMemoryPressure: 检查 Node memory pressure 状态
    • CheckNodeDiskPressure: 检查 Node disk pressure 状态
  2. Scoring Stage (Priorities): 对合适的 Node 进行评分。

    • LeastRequestedPriority: 给已请求资源较少的 Node 更高分数
    • BalancedResourceAllocation: 给资源使用更均衡的 Node 更高分数
    • NodeAffinityPriority: 基于 node affinity 规则评分
    • TaintTolerationPriority: 基于 taint toleration 评分
    • InterPodAffinityPriority: 基于 inter-pod affinity/anti-affinity 评分
  3. Binding: 将 Pod 绑定到得分最高的 Node。

默认 Scheduler 配置示例:

yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
  plugins:
    score:
      disabled:
      - name: NodeResourcesLeastAllocated
      enabled:
      - name: NodeResourcesBalancedAllocation
        weight: 1

其他选项的问题:

  • A. Pod 的创建和删除: 这主要是 controller manager 和 API server 的职责。
  • C. Node 资源监控: 这主要是 kubelet 和 metrics server 的职责。
  • D. Container image 下载: 这是 kubelet 和 container runtime 的职责。

2. 以下哪一项不是实现 Custom Scheduler 的方法?

A. 扩展现有的 kube-scheduler B. 实现一个全新的 scheduler C. 开发 scheduling framework plugin D. 修改 kubelet

显示答案

答案: D. 修改 kubelet

解析: 修改 kubelet 不是实现 Custom Scheduler 的方法。kubelet 是运行在每个 Node 上并管理 Pod 执行的代理,但它不做调度决策。调度由 kube-scheduler 或 custom schedulers 执行。

实现 Custom Scheduler 的方法:

  1. 扩展现有的 kube-scheduler:

    • 使用 KubeSchedulerConfiguration 自定义默认 scheduler 的行为。
    • 调整 plugin 权重、启用/禁用等。
    yaml
    apiVersion: kubescheduler.config.k8s.io/v1
    kind: KubeSchedulerConfiguration
    profiles:
    - schedulerName: custom-scheduler
      plugins:
        score:
          disabled:
          - name: NodeResourcesLeastAllocated
          enabled:
          - name: NodeResourcesBalancedAllocation
            weight: 2
  2. 实现一个全新的 scheduler:

    • 开发一个与 Kubernetes API 通信的独立 scheduler。
    • 直接实现 Pod 监听、Node 选择和绑定逻辑。
    go
    // Simple Go scheduler example
    func main() {
        config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
        if err != nil {
            log.Fatal(err)
        }
    
        clientset, err := kubernetes.NewForConfig(config)
        if err != nil {
            log.Fatal(err)
        }
    
        // Watch unscheduled pods
        watchPods(clientset)
    }
    
    func watchPods(clientset *kubernetes.Clientset) {
        watch, err := clientset.CoreV1().Pods("").Watch(context.TODO(), metav1.ListOptions{
            FieldSelector: "spec.schedulerName=custom-scheduler,spec.nodeName=",
        })
        if err != nil {
            log.Fatal(err)
        }
    
        for event := range watch.ResultChan() {
            if event.Type != watch.Added {
                continue
            }
    
            pod := event.Object.(*v1.Pod)
            // Implement node selection logic
            node := selectNode(clientset, pod)
            if node != "" {
                bindPod(clientset, pod, node)
            }
        }
    }
  3. 开发 scheduling framework plugin:

    • 使用 Kubernetes scheduling framework 为特定调度阶段开发 plugins。
    • 实现 filter、score、bind 等 extension points。
    go
    // Scoring plugin example
    type MyScorePlugin struct{}
    
    func (pl *MyScorePlugin) Name() string {
        return "MyScorePlugin"
    }
    
    func (pl *MyScorePlugin) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
        // Implement custom scoring logic
        return score, nil
    }
    
    func (pl *MyScorePlugin) ScoreExtensions() framework.ScoreExtensions {
        return pl
    }
    
    func (pl *MyScorePlugin) NormalizeScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status {
        // Implement score normalization logic
        return nil
    }

kubelet 的作用: kubelet 是运行在每个 Node 上的代理,执行以下职责:

  • 根据 Pod specs 运行和管理 containers
  • 监控并报告 Node 状态
  • 执行 container health checks
  • 管理 volume mounts

kubelet 执行 scheduler 做出的决策(在哪个 Node 上运行哪个 Pod),它本身不做调度决策。

其他选项说明:

  • A. 扩展现有的 kube-scheduler: 有效的 Custom Scheduler 实现方法。
  • B. 实现一个全新的 scheduler: 有效的 Custom Scheduler 实现方法。
  • C. 开发 scheduling framework plugin: 有效的 Custom Scheduler 实现方法。

3. 在 Pod 中,用于指定特定 scheduler 的字段是什么?

A. spec.scheduler B. spec.schedulerName C. metadata.scheduler D. spec.nodeName

显示答案

答案: B. spec.schedulerName

解析: 在 Pod 中用于指定特定 scheduler 的字段是 spec.schedulerName。设置此字段后,Pod 只会由具有指定名称的 scheduler 进行调度。默认值是 "default-scheduler"。

Pod Spec 示例:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: custom-scheduled-pod
  labels:
    app: my-app
spec:
  schedulerName: my-custom-scheduler  # Specify custom scheduler
  containers:
  - name: main-container
    image: nginx:1.19
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

此 Pod 只会由名为 "my-custom-scheduler" 的 scheduler 调度。如果集群中不存在该名称的 scheduler,Pod 将保持在 Pending 状态。

部署多个 Scheduler 的示例:

yaml
# Custom scheduler deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-custom-scheduler
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      component: my-custom-scheduler
  template:
    metadata:
      labels:
        component: my-custom-scheduler
    spec:
      serviceAccountName: my-custom-scheduler
      containers:
      - name: scheduler
        image: my-custom-scheduler:v1.0
        args:
        - --scheduler-name=my-custom-scheduler
        - --leader-elect=false

选择 Scheduler 时的注意事项:

  1. Availability: 如果指定的 scheduler 未运行,Pod 将不会被调度。
  2. Functionality: 每个 scheduler 可以有不同的调度算法和策略。
  3. Resource isolation: 可以使用不同的 scheduler 来隔离 workloads。
  4. Special hardware: 可以为 GPU 或 FPGA 等特殊硬件使用专用 scheduler。

检查 Scheduler 状态:

bash
# Check pod status
kubectl get pod custom-scheduled-pod

# Check scheduling events
kubectl describe pod custom-scheduled-pod | grep -A 5 Events

# Check scheduler logs
kubectl logs -n kube-system -l component=my-custom-scheduler

其他选项的问题:

  • A. spec.scheduler: Kubernetes API 中不存在的字段。
  • C. metadata.scheduler: Kubernetes API 中不存在的字段。
  • D. spec.nodeName: 此字段用于绕过 scheduler 并将 Pod 直接分配给特定 Node。它不是用于指定 scheduler 的字段。
### 4. Kubernetes scheduling framework 中 "Filter" extension point 的作用是什么?

A. 对 Node 进行评分 B. 将 Pod 绑定到 Node C. 排除 Pod 无法运行的 Node D. 对 scheduling queue 中的 Pod 进行排序

显示答案

答案: C. 排除 Pod 无法运行的 Node

解析: 在 Kubernetes scheduling framework 中,"Filter" extension point(以前称为 "Predicate")的作用是排除 Pod 无法运行的 Node。Filter plugins 会检查每个 Node 是否满足 Pod 的需求,并将不满足需求的 Node 从候选列表中排除。

Scheduling Framework Extension Points: Scheduling framework 提供了多种 extension points,可以在调度周期的不同阶段集成 plugins:

  1. Queue Sort: 决定 Pod 在 scheduling queue 中的顺序。
  2. PreFilter: 在 filtering 之前对 Pod 和集群状态执行预处理。
  3. Filter: 排除 Pod 无法运行的 Node。
  4. PreScore: 执行 scoring 前所需的计算。
  5. Score: 为通过 filtering 的 Node 分配分数。
  6. NormalizeScore: 规范化每个 scoring plugin 的分数。
  7. Reserve: 在所选 Node 上为 Pod 预留资源。
  8. Permit: 允许、拒绝或延迟 Pod 调度。
  9. PreBind: 执行 binding 前所需的工作。
  10. Bind: 将 Pod 绑定到 Node。
  11. PostBind: 在 binding 后执行清理工作。

默认 Filter Plugins: Kubernetes 提供以下默认 filter plugins:

  1. NodeResourcesFit: 检查 Node 是否有足够资源满足 Pod 的 resource requests。
  2. NodeName: 检查 Pod 的 spec.nodeName 字段是否匹配 Node 名称。
  3. NodeUnschedulable: 检查 Node 是否被标记为不可调度。
  4. TaintToleration: 检查 Pod 是否 tolerates Node 的 taints。
  5. NodeAffinity: 检查是否满足 Pod 的 node affinity 要求。
  6. PodAffinity: 检查是否满足 Pod 的 pod affinity 要求。
  7. VolumeRestrictions: 检查 volume 约束。
  8. EBSLimits: 检查 Amazon EBS volume 限制。
  9. NoVolumeZoneConflict: 检查 volume zone 约束。
  10. CheckNodeMemoryPressure: 检查 Node memory pressure 状态。
  11. CheckNodeDiskPressure: 检查 Node disk pressure 状态。

Custom Filter Plugin 示例:

go
// Custom filter plugin example
type MyFilterPlugin struct{}

func (pl *MyFilterPlugin) Name() string {
    return "MyFilterPlugin"
}

// Filter method implementation
func (pl *MyFilterPlugin) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
    // Check if the node meets certain conditions
    node := nodeInfo.Node()
    if node == nil {
        return framework.NewStatus(framework.Error, "node not found")
    }

    // Example: Only allow nodes with a specific label
    if value, exists := node.Labels["custom-label"]; !exists || value != "required-value" {
        return framework.NewStatus(framework.Unschedulable, "node does not have required label")
    }

    return nil // Returning nil means the node is suitable
}

在 Scheduler 配置中启用 Filter Plugin:

yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: custom-scheduler
  plugins:
    filter:
      enabled:
      - name: MyFilterPlugin
      disabled:
      - name: NodeResourcesFit  # Disable default plugin

其他选项的问题:

  • A. 对 Node 进行评分: 这是 "Score" extension point 的作用。
  • B. 将 Pod 绑定到 Node: 这是 "Bind" extension point 的作用。
  • D. 对 scheduling queue 中的 Pod 进行排序: 这是 "Queue Sort" extension point 的作用。

5. 以下哪一项不是实现 Custom Scheduler 时需要考虑的内容?

A. Node 资源使用情况 B. Pod 优先级和抢占 C. Container image 大小 D. Node affinity 和 anti-affinity

显示答案

答案: C. Container image 大小

解析: Container image 大小通常不是实现 Custom Scheduler 时需要考虑的内容。Image 大小影响的是 image 下载和 container 启动时间,而不是调度决策;这些由 kubelet 和 container runtime 负责。

实现 Custom Scheduler 时的关键考虑事项:

  1. Node 资源使用情况:

    • CPU、memory、disk、network 等资源使用情况
    • 根据当前使用情况和 requests 进行最优放置
    • Resource overcommit policy
    go
    // Resource usage based filtering example
    func filterByResourceUsage(pod *v1.Pod, node *v1.Node) bool {
        // Check node's allocatable resources
        allocatable := node.Status.Allocatable
        // Calculate sum of resource requests for pods running on the node
        // Check if new pod's resource requests exceed available resources
        return podFitsResources(pod, allocatable, usedResources)
    }
  2. Pod 优先级和抢占:

    • 优先调度更高优先级的 Pod
    • 必要时抢占较低优先级的 Pod
    • 考虑 PriorityClass 和 preemptionPolicy
    yaml
    # Priority class example
    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: high-priority
    value: 1000000
    globalDefault: false
    description: "High priority pods"
  3. Node affinity 和 anti-affinity:

    • 满足 Pod 的 nodeSelector、nodeAffinity 要求
    • 应用 inter-pod affinity 和 anti-affinity 规则
    • 考虑 topology spread constraints
    yaml
    # Node affinity example
    apiVersion: v1
    kind: Pod
    metadata:
      name: with-node-affinity
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/e2e-az-name
                operator: In
                values:
                - e2e-az1
                - e2e-az2
  4. 其他重要考虑事项:

    • Taints and tolerations: 匹配 Node taints 和 Pod tolerations
    • Topology spread: 将 Pod 分散到不同 topology domains
    • Node status: Node 状态(Ready、MemoryPressure、DiskPressure 等)
    • Workload characteristics: batch、service、daemonset 等各种 workload 类型的需求
    • Network topology: Node 之间的 network latency 和 bandwidth
    • Hardware characteristics: GPU、FPGA 等特殊硬件需求

与 container image 大小相关的考虑: 通常,container image 大小不会出于以下原因直接影响调度决策:

  1. Image availability: image 是否已缓存在 Node 上由 kubelet 处理,而不是 scheduler。
  2. Download time: Image 下载发生在调度决策之后,并由 kubelet 负责。
  3. Storage usage: Image 存储通常不包含在 Node allocatable resources 的计算中。

不过,在特殊情况下,可以实现一个考虑 image locality 的 custom scheduler。这可以通过优先选择已缓存该 image 的 Node 来帮助缩短启动时间。

其他选项说明:

  • A. Node 资源使用情况: 调度决策中的重要因素,对选择能够满足 Pod resource requests 的 Node 至关重要。
  • B. Pod 优先级和抢占: 在资源竞争期间决定哪些 Pod 先调度,以及必要时抢占哪些 Pod 很重要。
  • D. Node affinity 和 anti-affinity: 对于处理 Pod 应该与特定 Node 或其他 Pod 一起调度或分开调度的约束很重要。
### 6. Kubernetes scheduling framework 中 "Score" extension point 的作用是什么?

A. 排除 Pod 无法运行的 Node B. 对通过 filtering 的 Node 进行评分 C. 将 Pod 绑定到 Node D. 对 scheduling queue 中的 Pod 进行排序

显示答案

答案: B. 对通过 filtering 的 Node 进行评分

解析: 在 Kubernetes scheduling framework 中,"Score" extension point(以前称为 "Priority")的作用是为通过 filtering 的 Node 分配分数。Scoring plugins 会为每个 Node 分配分数,并根据这些分数选择最优 Node。

Scoring 流程:

  1. 每个 scoring plugin 为每个 Node 计算一个分数(通常范围为 0-100)。
  2. 每个 plugin 的分数根据配置的 weight 进行加权。
  3. 汇总所有 plugins 的加权分数。
  4. 选择总分最高的 Node 用于 Pod 放置。

默认 Scoring Plugins: Kubernetes 提供以下默认 scoring plugins:

  1. NodeResourcesBalancedAllocation: 给 CPU 和 memory 使用均衡的 Node 更高分数。
  2. NodeResourcesFit: 根据相对于 requested resources 的可用资源多少,给 Node 更高分数。
  3. NodeAffinity: 基于 node affinity 规则评分。
  4. InterPodAffinity: 基于 inter-pod affinity/anti-affinity 规则评分。
  5. PodTopologySpread: 给能让 Pod 在 topology domains 间均匀分布的 Node 更高分数。
  6. TaintToleration: 给 taints 更少的 Node 更高分数。
  7. ImageLocality: 给已经有所需 container images 的 Node 更高分数。

Custom Scoring Plugin 示例:

go
// Custom scoring plugin example
type MyScorePlugin struct{}

func (pl *MyScorePlugin) Name() string {
    return "MyScorePlugin"
}

// Score method implementation
func (pl *MyScorePlugin) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
    // Get node info
    nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
    if err != nil {
        return 0, framework.NewStatus(framework.Error, fmt.Sprintf("getting node %q from Snapshot: %v", nodeName, err))
    }

    node := nodeInfo.Node()

    // Example: Score based on specific label value
    if value, exists := node.Labels["custom-score-label"]; exists {
        score, err := strconv.ParseInt(value, 10, 64)
        if err != nil {
            return 0, framework.NewStatus(framework.Error, fmt.Sprintf("invalid score value: %v", err))
        }
        // Score range should be 0-100
        if score < 0 {
            score = 0
        } else if score > 100 {
            score = 100
        }
        return score, nil
    }

    return 0, nil
}

// ScoreExtensions interface implementation
func (pl *MyScorePlugin) ScoreExtensions() framework.ScoreExtensions {
    return pl
}

// NormalizeScore method implementation
func (pl *MyScorePlugin) NormalizeScore(ctx context.Context, state *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status {
    // Score normalization logic
    var highest int64 = 0
    for _, nodeScore := range scores {
        if nodeScore.Score > highest {
            highest = nodeScore.Score
        }
    }

    if highest == 0 {
        return nil
    }

    // Adjust all scores relative to the highest score
    for i := range scores {
        scores[i].Score = scores[i].Score * 100 / highest
    }

    return nil
}

在 Scheduler 配置中启用 Scoring Plugin 并设置 Weight:

yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: custom-scheduler
  plugins:
    score:
      enabled:
      - name: MyScorePlugin
        weight: 5  # Set weight
      - name: NodeResourcesBalancedAllocation
        weight: 2  # Change default plugin weight
      disabled:
      - name: NodeResourcesFit  # Disable default plugin

Scoring 结果示例: 假设 Node A、B、C 通过了 filtering,并且有两个 scoring plugins:

  1. MyScorePlugin (weight: 5)

    • Node A: 80 分
    • Node B: 60 分
    • Node C: 90 分
  2. NodeResourcesBalancedAllocation (weight: 2)

    • Node A: 70 分
    • Node B: 90 分
    • Node C: 50 分

加权总分:

  • Node A: (80 x 5) + (70 x 2) = 400 + 140 = 540 分
  • Node B: (60 x 5) + (90 x 2) = 300 + 180 = 480 分
  • Node C: (90 x 5) + (50 x 2) = 450 + 100 = 550 分

在这种情况下,Node C 得分最高,因此 Pod 被调度到 Node C。

其他选项的问题:

  • A. 排除 Pod 无法运行的 Node: 这是 "Filter" extension point 的作用。
  • C. 将 Pod 绑定到 Node: 这是 "Bind" extension point 的作用。
  • D. 对 scheduling queue 中的 Pod 进行排序: 这是 "Queue Sort" extension point 的作用。

7. 以下哪一项不是在 Kubernetes 中扩展 scheduler 的方法?

A. Scheduling framework plugin B. Scheduler extender C. 部署多个 scheduler D. 修改 node controller

显示答案

答案: D. 修改 node controller

解析: 修改 node controller 不是在 Kubernetes 中扩展 scheduler 的方法。node controller 是一个 control plane 组件,用于监控和管理 Node 状态,与调度决策没有直接关系。

在 Kubernetes 中扩展 Scheduler 的方法:

  1. Scheduling framework plugin:

    • 在 Kubernetes 1.15 中引入,允许在调度周期的各个阶段插入 plugins。
    • 提供 filter、score、bind 等 extension points。
    • 为提高效率,直接与 scheduler codebase 集成。
    go
    // Scheduling framework plugin registration example
    func NewPlugin(args runtime.Object, handle framework.Handle) (framework.Plugin, error) {
        // Parse plugin configuration
        config, ok := args.(*Config)
        if !ok {
            return nil, fmt.Errorf("want args to be of type Config, got %T", args)
        }
    
        // Create plugin instance
        return &Plugin{
            handle: handle,
            config: config,
        }, nil
    }
    
    // Plugin interface implementation
    type Plugin struct {
        handle framework.Handle
        config *Config
    }
    
    func (pl *Plugin) Name() string { return "MyPlugin" }
    
    // Implement required extension point methods
    func (pl *Plugin) Filter(...) { ... }
    func (pl *Plugin) Score(...) { ... }
  2. Scheduler extender:

    • 通过外部 HTTP service 扩展 scheduler 功能。
    • 可以扩展 filtering、prioritization、binding 阶段。
    • 因为它与 scheduler 分开运行,可能产生性能开销。
    yaml
    # Scheduler extender configuration example
    apiVersion: kubescheduler.config.k8s.io/v1
    kind: KubeSchedulerConfiguration
    profiles:
    - schedulerName: default-scheduler
      extenders:
      - urlPrefix: "http://extender-service:8080"
        filterVerb: "filter"
        prioritizeVerb: "prioritize"
        weight: 5
        bindVerb: "bind"
        enableHTTPS: false
  3. 部署多个 scheduler:

    • 将 custom schedulers 与默认 scheduler 一起部署。
    • 每个 scheduler 独立运行,Pod 可以通过 spec.schedulerName 指定特定 scheduler。
    • 提供完全灵活性,但实现和维护可能较复杂。
    yaml
    # Custom scheduler deployment example
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-custom-scheduler
      namespace: kube-system
    spec:
      replicas: 1
      selector:
        matchLabels:
          component: my-custom-scheduler
      template:
        metadata:
          labels:
            component: my-custom-scheduler
        spec:
          serviceAccountName: my-custom-scheduler
          containers:
          - name: scheduler
            image: my-custom-scheduler:v1.0
            args:
            - --scheduler-name=my-custom-scheduler
            - --leader-elect=false

Node Controller 的作用: node controller 是一个 control plane 组件,执行以下职责:

  • Node 注册和状态监控
  • Node 状态更新(Ready、NotReady 等)
  • 根据 Node 状态移除 Pod(当 Node 长时间处于 NotReady 时)
  • Node lifecycle management

node controller 不直接参与调度决策;它会更新 scheduler 使用的 Node 信息。因此,修改 node controller 不是扩展 scheduler 的方法。

选择 Scheduler 扩展方法时的注意事项:

  1. Complexity: Scheduling framework plugins 实现起来可能复杂,但与 scheduler 紧密集成。
  2. Performance: Scheduler extenders 可能有 HTTP 调用开销,会影响性能。
  3. Maintenance: 多个 schedulers 需要维护独立的 codebases。
  4. Upgrades: Kubernetes 升级时可能出现兼容性问题。
  5. Features: 每种方法提供不同级别的功能和灵活性。

其他选项说明:

  • A. Scheduling framework plugin: 有效的 scheduler 扩展方法。
  • B. Scheduler extender: 有效的 scheduler 扩展方法。
  • C. 部署多个 scheduler: 有效的 scheduler 扩展方法。
### 8. Kubernetes scheduler 中 `--leader-elect` flag 的用途是什么?

A. 授予 scheduler 领导权限 B. 在多个 scheduler instances 中只激活一个 instance C. 仅在集群的 leader Node 上运行 scheduler D. 赋予 scheduler 比其他组件更高的优先级

显示答案

答案: B. 在多个 scheduler instances 中只激活一个 instance

解析: Kubernetes scheduler 中 --leader-elect flag 的用途是,在 high availability (HA) 配置中确保只有一个 scheduler instance 处于活跃状态并执行工作。这可以防止多个 scheduler instances 同时工作时可能发生的冲突和 race conditions。

Leader Election 机制:

  1. 部署多个 scheduler instances 时,leader election 算法只选举一个 instance 作为 leader。
  2. 只有被选为 leader 的 instance 执行实际调度工作。
  3. 其他 instances 保持 standby mode,如果当前 leader 失败,会选举新的 leader。
  4. 该机制使用 Kubernetes resource locks 实现。

Leader Election 相关 Flags:

--leader-elect=true                      # Whether to enable leader election (default: true)
--leader-elect-lease-duration=15s        # Leadership lease duration
--leader-elect-renew-deadline=10s        # Leadership renewal deadline
--leader-elect-retry-period=2s           # Leadership retry period
--leader-elect-resource-lock=leases      # Resource type to use for leadership lock
--leader-elect-resource-name=kube-scheduler  # Leadership lock resource name
--leader-elect-resource-namespace=kube-system  # Leadership lock resource namespace

High Availability Scheduler 部署示例:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-scheduler
  namespace: kube-system
spec:
  replicas: 3  # Deploy multiple instances
  selector:
    matchLabels:
      component: kube-scheduler
  template:
    metadata:
      labels:
        component: kube-scheduler
    spec:
      containers:
      - name: kube-scheduler
        image: k8s.gcr.io/kube-scheduler:v1.23.0
        command:
        - kube-scheduler
        - --leader-elect=true  # Enable leader election
        - --leader-elect-lease-duration=15s
        - --leader-elect-renew-deadline=10s
        - --leader-elect-retry-period=2s

检查 Leader Election 状态:

bash
# Check leadership resource
kubectl get leases -n kube-system | grep kube-scheduler

# Check leadership details
kubectl describe lease kube-scheduler -n kube-system

# Check leadership related messages in scheduler logs
kubectl logs -n kube-system -l component=kube-scheduler | grep -i leader

Custom Scheduler 中的 Leader Election: 实现 custom scheduler 时,可以使用相同的 leader election 机制。这会使用 client-go library 中的 leaderelection package。

go
// Leader election implementation example in custom scheduler
import (
    "context"
    "time"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    clientset "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/leaderelection"
    "k8s.io/client-go/tools/leaderelection/resourcelock"
)

func runWithLeaderElection(ctx context.Context, client clientset.Interface, schedulerName string) {
    // Leader election configuration
    lock := &resourcelock.LeaseLock{
        LeaseMeta: metav1.ObjectMeta{
            Name:      schedulerName,
            Namespace: "kube-system",
        },
        Client: client.CoordinationV1(),
        LockConfig: resourcelock.ResourceLockConfig{
            Identity: schedulerName + "-" + uuid.New().String(),
        },
    }

    // Execute leader election
    leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{
        Lock:            lock,
        ReleaseOnCancel: true,
        LeaseDuration:   15 * time.Second,
        RenewDeadline:   10 * time.Second,
        RetryPeriod:     2 * time.Second,
        Callbacks: leaderelection.LeaderCallbacks{
            OnStartedLeading: func(ctx context.Context) {
                // Execute scheduler logic when becoming leader
                runScheduler(ctx)
            },
            OnStoppedLeading: func() {
                // Handle when leadership is lost
                log.Printf("Lost leadership, shutting down")
                os.Exit(0)
            },
            OnNewLeader: func(identity string) {
                // Handle when a new leader is elected
                log.Printf("New leader elected: %s", identity)
            },
        },
    })
}

应禁用 Leader Election 的情况:

  1. Single instance deployment: 当 scheduler 只部署为一个 instance 时
  2. Using a different leader election mechanism: 当外部 orchestration tool 管理 instance 激活时
  3. Different scheduler names: 当每个 scheduler instance 使用不同的 schedulerName

在这些情况下,可以通过设置 --leader-elect=false 来禁用 leader election。

其他选项的问题:

  • A. 授予 scheduler 领导权限: 这是模糊描述,没有解释 leader election 的具体用途。
  • C. 仅在集群的 leader Node 上运行 scheduler: Kubernetes 中没有 "leader node" 的概念;scheduler 运行在 control plane nodes 上。
  • D. 赋予 scheduler 比其他组件更高的优先级: Leader election 与优先级无关;它用于多个 scheduler instances 之间的协调。

9. Kubernetes 中用于设置 Pod 调度优先级的资源是什么?

A. PodSchedulingPolicy B. PriorityClass C. SchedulingPriority D. PodPriority

显示答案

答案: B. PriorityClass

解析: Kubernetes 中用于设置 Pod 调度优先级的资源是 PriorityClass。PriorityClass 定义 Pod 的相对重要性,使 scheduler 在做出调度和抢占决策时可以考虑优先级。

PriorityClass 资源:

yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000  # Priority value (higher value means higher priority)
globalDefault: false  # Whether to use this class as the default
description: "High priority pods"  # Description
preemptionPolicy: PreemptLowerPriority  # Preemption policy (default: PreemptLowerPriority)

关键字段:

  1. value: 优先级值;值越大表示优先级越高。System Pods 通常使用 1000000000(10 亿)或更高的值。
  2. globalDefault: 设置为 true 时,此 priority class 会应用到未指定 priority class 的 Pod。
  3. description: priority class 的描述。
  4. preemptionPolicy: 抢占策略,可设置为 PreemptLowerPriority(默认)或 Never

将 PriorityClass 应用于 Pod:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: high-priority-pod
spec:
  priorityClassName: high-priority  # Reference PriorityClass name
  containers:
  - name: nginx
    image: nginx

Priority 和 Preemption 行为:

  1. Scheduling priority: 更高优先级的 Pod 会在 scheduling queue 中先处理。
  2. Preemption: 当没有 Node 可以调度高优先级 Pod 时,scheduler 可以移除(抢占)较低优先级的 Pod 以释放空间。
  3. Preemption policy: 使用带有 preemptionPolicy: Never 的 PriorityClass 的 Pod 不会抢占其他 Pod。

System PriorityClasses: Kubernetes 提供以下 system PriorityClasses:

  • system-cluster-critical: 用于对集群运行至关重要的 Pod(value: 2000000000)
  • system-node-critical: 用于对 Node 运行至关重要的 Pod(value: 2000001000)
bash
# Check system PriorityClasses
kubectl get priorityclasses | grep system

PriorityClass 使用示例:

yaml
# Define multiple priority classes
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "High priority pods"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: medium-priority
value: 100000
globalDefault: true
description: "Medium priority pods"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: low-priority
value: 10000
globalDefault: false
description: "Low priority pods"
preemptionPolicy: Never  # Do not preempt

监控 Priority 和 Preemption 相关指标:

bash
# Check preemption events
kubectl get events | grep -i preempt

# Check pod priorities
kubectl get pods -o custom-columns=NAME:.metadata.name,PRIORITY:.spec.priority

在 Custom Scheduler 中处理 Priority: 实现 custom scheduler 时,在做出调度决策时应考虑 Pod 优先级。

go
// Pod priority check example
func getPodPriority(pod *v1.Pod) int32 {
    if pod.Spec.Priority != nil {
        return *pod.Spec.Priority
    }
    return 0
}

// Priority-based pod sorting example
func sortPodsByPriority(pods []*v1.Pod) {
    sort.Slice(pods, func(i, j int) bool {
        return getPodPriority(pods[i]) > getPodPriority(pods[j])
    })
}

其他选项的问题:

  • A. PodSchedulingPolicy: Kubernetes API 中不存在的资源。
  • C. SchedulingPriority: Kubernetes API 中不存在的资源。
  • D. PodPriority: 这不是资源类型,而是 Pod spec 中的字段(spec.priority)。此字段会由 PriorityClass 自动设置。

10. Kubernetes scheduler 的 NodeResourcesFit plugin 的作用是什么?

A. 根据 Node 的物理位置放置 Pod B. 比较 Node resource capacity 和 Pod resource requests C. 检查 Node operating system 与 Pod 的兼容性 D. 测量 Node network bandwidth

显示答案

答案: B. 比较 Node resource capacity 和 Pod resource requests

解析: Kubernetes scheduler 的 NodeResourcesFit plugin 的作用是比较 Node resource capacity 和 Pod resource requests,以检查 Pod 是否可以在该 Node 上运行。此 plugin 会考虑 CPU、memory、ephemeral storage 和 extended resources(GPU 等)在内的各种 resource types。

NodeResourcesFit Plugin 的主要功能:

  1. Resource request verification: 检查 Pod 的 resource requests 是否不超过 Node 的 allocatable resources。
  2. Resource limit verification: 检查 Pod 的 resource limits 是否不超过 Node 的 capacity。
  3. Extended resource verification: 检查 GPU、FPGA 等 extended resource requests 在 Node 上是否可用。
  4. Scoring: 基于资源使用情况,为通过 filtering 阶段的 Node 分配分数。

资源验证流程:

  1. 汇总 Pod 中所有 containers 的 resource requests。
  2. 检查 Node 的 allocatable resources。
  3. 检查 Pod 的 resource requests 是否不超过 Node 的 allocatable resources。
  4. 如果超过,该 Node 会被过滤掉。

Scheduler 中的 NodeResourcesFit 配置:

yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
  plugins:
    filter:
      enabled:
      - name: NodeResourcesFit
    score:
      enabled:
      - name: NodeResourcesFit
        weight: 1
  pluginConfig:
  - name: NodeResourcesFit
    args:
      scoringStrategy:
        type: MostAllocated  # or LeastAllocated, RequestedToCapacityRatio
        resources:
        - name: cpu
          weight: 1
        - name: memory
          weight: 1

Scoring Strategies: NodeResourcesFit plugin 支持以下 scoring strategies:

  1. LeastAllocated: 给已使用资源较少的 Node 更高分数。这适用于分散资源使用。

    score = (capacity - requested) / capacity
  2. MostAllocated: 给已使用资源较多的 Node 更高分数。这适用于集中资源使用,以最小化 Node 数量。

    score = requested / capacity
  3. RequestedToCapacityRatio: 使用自定义函数根据 requested resources 与 capacity 的比率分配分数。

Resource Types: NodeResourcesFit plugin 会考虑以下 resource types:

  1. CPU: 以 cores 或 millicores 度量。
  2. Memory: 以 bytes 度量。
  3. Ephemeral storage: Node 的本地 ephemeral storage。
  4. Extended resources: GPU、FPGA 等 custom resources。

检查 Node Resources:

bash
# Check node's allocatable resources
kubectl describe node <node-name> | grep Allocatable -A 5

# Check node's resource usage
kubectl top node <node-name>

检查 Pod Resource Requests:

bash
# Check pod's resource requests
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].resources.requests}'

在 Custom Scheduler 中实现 Resource Fit Check:

go
// Node resource fit check example
func checkNodeResourcesFit(pod *v1.Pod, node *v1.Node) bool {
    // Get node's allocatable resources
    allocatable := node.Status.Allocatable

    // Calculate pod's resource requests
    var requestedCPU, requestedMemory resource.Quantity
    for _, container := range pod.Spec.Containers {
        if request, ok := container.Resources.Requests[v1.ResourceCPU]; ok {
            requestedCPU.Add(request)
        }
        if request, ok := container.Resources.Requests[v1.ResourceMemory]; ok {
            requestedMemory.Add(request)
        }
    }

    // Calculate resources already in use on the node
    // (In actual implementation, sum resource requests of all pods running on the node)

    // Check resource fit
    if allocatableCPU, ok := allocatable[v1.ResourceCPU]; ok {
        if requestedCPU.Cmp(allocatableCPU) > 0 {
            return false  // CPU request exceeds allocatable amount
        }
    }

    if allocatableMemory, ok := allocatable[v1.ResourceMemory]; ok {
        if requestedMemory.Cmp(allocatableMemory) > 0 {
            return false  // Memory request exceeds allocatable amount
        }
    }

    return true  // All resource requests are satisfied
}

其他选项的问题:

  • A. 根据 Node 的物理位置放置 Pod: 这是 topology 相关 plugins(例如 NodeAffinity、PodTopologySpread)的作用。
  • C. 检查 Node operating system 与 Pod 的兼容性: 这是通过 NodeSelector 或 NodeAffinity 处理的,而不是单独的 plugin。
  • D. 测量 Node network bandwidth: Kubernetes scheduler 默认不考虑 network bandwidth。需要 custom metrics 和 plugins 来实现这一点。