custom_resource_allocation.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. Copyright 2020 Achilleas Tzenetopoulos
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. /*
  14. Extension of the scheduler developed during my diploma thesis
  15. Make it pluggable with Kubernetes logic in scheduler extension
  16. Date started: 30/1/2020
  17. Using the scheduling framework and plugins logic
  18. */
  19. package noderesources
  20. import (
  21. "context"
  22. "fmt"
  23. v1 "k8s.io/api/core/v1"
  24. "k8s.io/apimachinery/pkg/runtime"
  25. "k8s.io/klog"
  26. framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
  27. "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
  28. )
  29. // Custom allocation is a score plugin that favors nodes with a custom scoring function taking into account custom resources.
  30. type CustomAllocated struct {
  31. handle framework.FrameworkHandle
  32. resourceAllocationScorer
  33. //customResourceAllocationScorer
  34. }
  35. type nodeMetrics struct {
  36. L3cacheMisses int64
  37. memoryReads int64
  38. memoryWrites int64
  39. averageIPC float32
  40. }
  41. type wrongValueError struct{}
  42. var _ = framework.ScorePlugin(&CustomAllocated{})
  43. // CustomAllocatedName is the name of the plugin used in the plugin registry and configurations.
  44. const CustomAllocatedName = "NodeResourcesCustomAllocated"
  45. // Name returns name of the plugin. It is used in logs, etc.
  46. func (ca *CustomAllocated) Name() string {
  47. return CustomAllocatedName
  48. }
  49. func getCustomMetrics(name string) *nodeMetrics {
  50. nd := nodeMetrics{}
  51. if name == "kube-01" {
  52. nd.L3cacheMisses = 1
  53. nd.memoryReads = 1
  54. nd.memoryWrites = 1
  55. nd.averageIPC = 2.0
  56. } else {
  57. //some sample values for testing purposes
  58. nd.L3cacheMisses = 200
  59. nd.memoryReads = 50
  60. nd.memoryWrites = 60
  61. nd.averageIPC = 1.2
  62. }
  63. //query metrics for this node provided in the input
  64. if nd.L3cacheMisses < 0 || nd.memoryReads < 0 || nd.memoryWrites < 0 || nd.averageIPC < 0 {
  65. //err := errors.New("Failed to get the values")
  66. return nil
  67. }
  68. return &nd
  69. }
  70. func (ca *CustomAllocated) scoringFunction(pod *v1.Pod, node *nodeMetrics, nodeInfo *nodeinfo.NodeInfo) int64 {
  71. //rawScore := float32(node.memoryReads+node.memoryWrites) / node.averageIPC
  72. intScore := int64(float32(node.memoryReads+node.memoryWrites) / node.averageIPC)
  73. //Sample implementation in order to check functionality
  74. klog.Infof("Score: %d", intScore)
  75. return intScore
  76. }
  77. // Score invoked at the score extension point.
  78. func (ca *CustomAllocated) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
  79. nodeInfo, err := ca.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
  80. if err != nil {
  81. return 0, framework.NewStatus(framework.Error, fmt.Sprintf("getting node %q from Snapshot: %v", nodeName, err))
  82. }
  83. //Search into the monitored metrics for the specified node
  84. nodeMetrics := getCustomMetrics(nodeName)
  85. // ca.score favors nodes with 'better' monitored resources score.
  86. // It calculates the percentage of micro-architecture metrics like L3 cache misses and/or IPC and memory bandwidth, and
  87. // prioritizes based on the lowest score provided by a custom scoring function.
  88. //
  89. // Details:
  90. // TODO
  91. klog.Infof("Node: %s", nodeName)
  92. return ca.scoringFunction(pod, nodeMetrics, nodeInfo), nil
  93. //return ca.score(pod, nodeInfo)
  94. }
  95. // ScoreExtensions of the Score plugin.
  96. func (ca *CustomAllocated) ScoreExtensions() framework.ScoreExtensions {
  97. return nil
  98. }
  99. // NewCustomAllocated initializes a new plugin and returns it.
  100. func NewCustomAllocated(_ *runtime.Unknown, h framework.FrameworkHandle) (framework.Plugin, error) {
  101. return &CustomAllocated{
  102. handle: h,
  103. resourceAllocationScorer: resourceAllocationScorer{
  104. CustomAllocatedName,
  105. customResourceScorer,
  106. defaultRequestedRatioResources,
  107. },
  108. }, nil
  109. }
  110. func customResourceScorer(requested, allocable resourceToValueMap, includeVolumes bool, requestedVolumes int, allocatableVolumes int) int64 {
  111. //There I should call a function which will get my custom metrics
  112. var nodeScore, weightSum int64
  113. for resource, weight := range defaultRequestedRatioResources {
  114. resourceScore := customRequestedScore(requested[resource], allocable[resource])
  115. nodeScore += resourceScore * weight
  116. weightSum += weight
  117. }
  118. return nodeScore / weightSum
  119. }
  120. // The unused capacity is calculated on a scale of 0-10
  121. // 0 being the lowest priority and 10 being the highest.
  122. // The more unused resources the higher the score is.
  123. func customRequestedScore(requested, capacity int64) int64 {
  124. if capacity == 0 {
  125. return 0
  126. }
  127. if requested > capacity {
  128. return 0
  129. }
  130. return ((capacity - requested) * int64(framework.MaxNodeScore)) / capacity
  131. }