...
1
16
17 package imagelocality
18
19 import (
20 "context"
21 "fmt"
22 "strings"
23
24 v1 "k8s.io/api/core/v1"
25 "k8s.io/apimachinery/pkg/runtime"
26 "k8s.io/kubernetes/pkg/scheduler/framework"
27 "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
28 )
29
30
31
32 const (
33 mb int64 = 1024 * 1024
34 minThreshold int64 = 23 * mb
35 maxContainerThreshold int64 = 1000 * mb
36 )
37
38
39 type ImageLocality struct {
40 handle framework.Handle
41 }
42
43 var _ framework.ScorePlugin = &ImageLocality{}
44
45
46 const Name = names.ImageLocality
47
48
49 func (pl *ImageLocality) Name() string {
50 return Name
51 }
52
53
54 func (pl *ImageLocality) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
55 nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
56 if err != nil {
57 return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err))
58 }
59
60 nodeInfos, err := pl.handle.SnapshotSharedLister().NodeInfos().List()
61 if err != nil {
62 return 0, framework.AsStatus(err)
63 }
64 totalNumNodes := len(nodeInfos)
65
66 imageScores := sumImageScores(nodeInfo, pod, totalNumNodes)
67 score := calculatePriority(imageScores, len(pod.Spec.InitContainers)+len(pod.Spec.Containers))
68
69 return score, nil
70 }
71
72
73 func (pl *ImageLocality) ScoreExtensions() framework.ScoreExtensions {
74 return nil
75 }
76
77
78 func New(_ context.Context, _ runtime.Object, h framework.Handle) (framework.Plugin, error) {
79 return &ImageLocality{handle: h}, nil
80 }
81
82
83
84 func calculatePriority(sumScores int64, numContainers int) int64 {
85 maxThreshold := maxContainerThreshold * int64(numContainers)
86 if sumScores < minThreshold {
87 sumScores = minThreshold
88 } else if sumScores > maxThreshold {
89 sumScores = maxThreshold
90 }
91
92 return framework.MaxNodeScore * (sumScores - minThreshold) / (maxThreshold - minThreshold)
93 }
94
95
96
97
98 func sumImageScores(nodeInfo *framework.NodeInfo, pod *v1.Pod, totalNumNodes int) int64 {
99 var sum int64
100 for _, container := range pod.Spec.InitContainers {
101 if state, ok := nodeInfo.ImageStates[normalizedImageName(container.Image)]; ok {
102 sum += scaledImageScore(state, totalNumNodes)
103 }
104 }
105 for _, container := range pod.Spec.Containers {
106 if state, ok := nodeInfo.ImageStates[normalizedImageName(container.Image)]; ok {
107 sum += scaledImageScore(state, totalNumNodes)
108 }
109 }
110 return sum
111 }
112
113
114
115
116
117 func scaledImageScore(imageState *framework.ImageStateSummary, totalNumNodes int) int64 {
118 spread := float64(imageState.NumNodes) / float64(totalNumNodes)
119 return int64(float64(imageState.Size) * spread)
120 }
121
122
123
124
125
126
127 func normalizedImageName(name string) string {
128 if strings.LastIndex(name, ":") <= strings.LastIndex(name, "/") {
129 name = name + ":latest"
130 }
131 return name
132 }
133
View as plain text