Kubernetes SchedulerのPredicatesとPriorities Policies解読

9815 ワード

本文はKubernetes V 1についてである.5 Schedulerの事前選択ポリシーPredicates Policiesと好ましいポリシーPriorities Policiesの意味を解読し、サンプルコード解析の一部を添付します.kubernetesスケジューラのもっと全面的な解析について私の他のブログを参照してください:Kubernetes Schedulerソースコード分析,Kubernetes Scheduler原理解析

Predicates Policies分析

/plugin/pkg/scheduler/algorithm/predicates.goでは、以下の事前選択ポリシーが実装されています.
  • NoDiskConflict:このホストでボリューム競合がないかどうかを確認します.このホストがボリュームをマウントしている場合、同じボリュームを使用する他のPodはこのホストにスケジュールできません.GCE,Amazon EBS,and Ceph RBDで使用されるルールは以下の通りである.
  • GCEでは、これらのボリュームが読み取り専用である限り、複数のボリュームを同時にマウントできます.
  • Amazon EBSでは、異なるPodで同じボリュームをマウントすることはできません.
  • Ceph RBDでは、同じmonitor、match pool、imageを2つのpodsで共有することはできません.

  • NoVolumeZoneConflict:指定されたzone制限を確認した上で、このホスト上にPodが配備されている場合にボリューム競合がないかどうかを確認します.いくつかのvolumesにzoneスケジューリング制約がある可能性があると仮定し、VolumeZonePredicateはvolumes自身のニーズに基づいてpodが条件を満たすかどうかを評価する.必要な条件は、任意のvolumesのzone-labelsがノード上のzone-labelsと完全に一致しなければならないことです.ノードには、複数のzone-labelsの制約があります(たとえば、複製ボリュームが領域範囲内のアクセスを許可すると仮定しています).現在、これはPersistentVolumeClaimsにのみサポートされており、PersistentVolumeの範囲内でのみラベルが検索されています.Podのプロパティで定義されたvolumes(PersistentVolumeを使用しない)の処理は、スケジューリング中にvolumeのzoneを特定するため、クラウドプロバイダを呼び出す必要がある可能性が高いため、より困難になる可能性があります.
  • PodFitsResources:ホストのリソースがPodの要件を満たしているかどうかを確認します.実際に割り当てられたリソース量に基づいてスケジューリングを行い、実際に使用されたリソース量を使用してスケジューリングを行うわけではありません.
  • PodFitsHostPorts:Pod内の各コンテナに必要なHostPortが他のコンテナによって占有されているかどうかを確認します.必要なHostPortが需要を満たしていない場合、Podはこのホストにスケジューリングできません.
  • HostName:ホスト名がPodで指定されたHostNameかどうかを確認します.
  • MatchNodeSelector:ホストのラベルがPodのnodeSelector属性要件を満たしているかどうかを確認します.
  • MaxEBSVolumeCount:マウントされているEBSストレージボリュームが設定された最大値を超えないことを確認します.既定値は39です.直接使用するストレージボリュームと、このタイプのストレージを間接的に使用するPVCをチェックします.異なるボリュームの合計を計算し、新しいPodが配備された後のボリュームの数が設定された最大値を超える場合、Podはこのホストにスケジュールできません.
  • MaxGCEDVolumeCount:マウントされているGCEストレージボリュームが設定された最大値を超えないことを確認します.既定値は16です.ルールは同じです.

  • 以下はNoDiskConflictのコード実装であり、他のPredicates Policies実装と同様に、
    type FitPredicate func(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (bool, []PredicateFailureReason, error)
    の関数プロトタイプが得られる.
    
    func NoDiskConflict(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (bool, []algorithm.PredicateFailureReason, error) {
        for _, v := range pod.Spec.Volumes {
            for _, ev := range nodeInfo.Pods() {
                if isVolumeConflict(v, ev) {
                    return false, []algorithm.PredicateFailureReason{ErrDiskConflict}, nil
                }
            }
        }
        return true, nil, nil
    }
    
    
    func isVolumeConflict(volume v1.Volume, pod *v1.Pod) bool {
        // fast path if there is no conflict checking targets.
        if volume.GCEPersistentDisk == nil && volume.AWSElasticBlockStore == nil && volume.RBD == nil && volume.ISCSI == nil {
            return false
        }
    
        for _, existingVolume := range pod.Spec.Volumes {
            ...
    
            if volume.RBD != nil && existingVolume.RBD != nil {
                mon, pool, image := volume.RBD.CephMonitors, volume.RBD.RBDPool, volume.RBD.RBDImage
                emon, epool, eimage := existingVolume.RBD.CephMonitors, existingVolume.RBD.RBDPool, existingVolume.RBD.RBDImage
                // two RBDs images are the same if they share the same Ceph monitor, are in the same RADOS Pool, and have the same image name
                // only one read-write mount is permitted for the same RBD image.
                // same RBD image mounted by multiple Pods conflicts unless all Pods mount the image read-only
                if haveSame(mon, emon) && pool == epool && image == eimage && !(volume.RBD.ReadOnly && existingVolume.RBD.ReadOnly) {
                    return true
                }
            }
        }
    
        return false
    }

    Priorities Policies分析


    現在サポートされている優先順位関数は、次のとおりです.
  • LeastRequestedPriority:新しいpodがノードに割り当てられる場合、このノードの優先度は、ノードの空き部分と総容量との比(すなわち、総容量-ノード上のpodの容量合計-新しいpodの容量)/総容量)によって決定されます.CPUはmemory重みに相当し,比が最大のノードの得点が最も高い.この優先度関数は、リソース消費に応じてpodsをノード間で割り当てる役割を果たすことに注意されたい.計算式は、cpu((capacity–sum)*10/capacity)+memory((capacity–sum(requested)*10/capacity)/2
  • です.
  • BalancedResourceAllocation:Podを導入した後、各リソースがよりバランスのとれたマシンをできるだけ選択します.BalancedResourceAllocationは単独では使用できません.また、ホスト上のcpuとmemoryの比重をそれぞれ計算するLeastRequestedPriorityと同時に使用する必要があります.ホストのスコアはcpuの比重とmemoryの比重の「距離」によって決まります.計算式は、score=10–abs(cpuFraction-memoryFraction)*10
  • SelectorSpreadPriority:同じサービス、replication controllerに属するPodについては、できるだけ異なるホストに分散します.領域が指定されている場合、Podはできるだけ異なる領域の異なるホストに分散されます.Podをスケジュールするときは、まずPodペアのサービスまたはreplication controllerを検索し、次にサービスまたはreplication controllerにすでに存在するPodを検索します.ホスト上で実行されている既存のPodが少ないほど、ホストのスコアが高くなります.
  • CalculateAntiAffinityPriority:同じサービスに属するPodについては、指定されたラベルを持つ異なるホストにできるだけ分散します.
  • ImageLocalityPriority:ホスト上にPodが実行されている環境があるかどうかによって採点されます.ImageLocalityPriorityは、ホスト上にPod実行に必要なミラーがすでに存在するかどうかを判断し、既存のミラーのサイズに応じて0-10のスコアを返します.ホストにPodに必要なミラーが存在しない場合は、0を返します.ホスト上に必要なミラーが一部存在する場合、これらのミラーのサイズに応じてスコアが決定され、ミラーが大きいほどスコアが高くなります.
  • NodeAffinityPriority(Kubernetes 1.2実験における新しい特性):Kubernetesスケジューリングにおける親和性機構.Node Selectors(スケジューリング時にpodを指定ノードに限定)は、ノードlabelsの正確なマッチングに限定されることなく、複数のオペレータ(In,NotIn,Exists,DoesNotExist,Gt,Lt)をサポートします.また、Kubernetesでは、2種類のセレクタがサポートされています.1つは、「hard(r e q u i r e d DuringSchedulingIgnoredDuringExecution)」セレクタで、選択したホストがすべてのPodのホストに対するルール要件を満たす必要があることを保証します.このセレクタは以前のnodeselectorのように,nodeselectorに基づいてより適切な表現文法を追加した.もう1つは、スケジューラのヒントとして、NodeSelectorのすべての要件を満たすことを保証しないスケジューラです.

  • 次はImageLocalityPriorityのコード実装です.他のPriorities Policies実装と同様に、type PriorityMapFunction func(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error)
    の関数プロトタイプが必要です.
    func ImageLocalityPriorityMap(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) {
        node := nodeInfo.Node()
        if node == nil {
            return schedulerapi.HostPriority{}, fmt.Errorf("node not found")
        }
    
        var sumSize int64
        for i := range pod.Spec.Containers {
            sumSize += checkContainerImageOnNode(node, &pod.Spec.Containers[i])
        }
        return schedulerapi.HostPriority{
            Host:  node.Name,
            Score: calculateScoreFromSize(sumSize),
        }, nil
    }
    
    func calculateScoreFromSize(sumSize int64) int {
        var score int
        switch {
        case sumSize == 0 || sumSize < minImgSize:
            // score == 0 means none of the images required by this pod are present on this
            // node or the total size of the images present is too small to be taken into further consideration.
            score = 0
        // If existing images' total size is larger than max, just make it highest priority.
        case sumSize >= maxImgSize:
            score = 10
        default:
            score = int((10 * (sumSize - minImgSize) / (maxImgSize - minImgSize)) + 1)
        }
        // Return which bucket the given size belongs to
        return score
    }

    各ノードを計算するScoreアルゴリズムは、score = int((10 * (sumSize - minImgSize) / (maxImgSize - minImgSize)) + 1)である.
    そのうち:minImgSize int64 = 23 * mb, maxImgSize int64 = 1000 * mb, sumSize Pod container Images' size .
    ノード上でこのPodが要求するコンテナミラーサイズの和が大きいほど,スコアが高いほどターゲットノードである可能性があることがわかる.
    その他のPriorities Policiesの実装とアルゴリズムは同様に分析してください.