Merge pull request #265 from MaciekPytel/ignore_unneded_if_min_size
Skip nodes in min-sized groups in scale-down simulation
This commit is contained in:
commit
6ad7ca21e8
|
|
@ -144,7 +144,7 @@ func (sd *ScaleDown) CleanUpUnneededNodes() {
|
||||||
// managed by CA.
|
// managed by CA.
|
||||||
func (sd *ScaleDown) UpdateUnneededNodes(
|
func (sd *ScaleDown) UpdateUnneededNodes(
|
||||||
nodes []*apiv1.Node,
|
nodes []*apiv1.Node,
|
||||||
managedNodes []*apiv1.Node,
|
nodesToCheck []*apiv1.Node,
|
||||||
pods []*apiv1.Pod,
|
pods []*apiv1.Pod,
|
||||||
timestamp time.Time,
|
timestamp time.Time,
|
||||||
pdbs []*policyv1.PodDisruptionBudget) errors.AutoscalerError {
|
pdbs []*policyv1.PodDisruptionBudget) errors.AutoscalerError {
|
||||||
|
|
@ -154,24 +154,24 @@ func (sd *ScaleDown) UpdateUnneededNodes(
|
||||||
utilizationMap := make(map[string]float64)
|
utilizationMap := make(map[string]float64)
|
||||||
|
|
||||||
// Filter out nodes that were recently checked
|
// Filter out nodes that were recently checked
|
||||||
nodesToCheck := make([]*apiv1.Node, 0)
|
filteredNodesToCheck := make([]*apiv1.Node, 0)
|
||||||
for _, node := range managedNodes {
|
for _, node := range nodesToCheck {
|
||||||
if unremovableTimestamp, found := sd.unremovableNodes[node.Name]; found {
|
if unremovableTimestamp, found := sd.unremovableNodes[node.Name]; found {
|
||||||
if unremovableTimestamp.After(timestamp) {
|
if unremovableTimestamp.After(timestamp) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
delete(sd.unremovableNodes, node.Name)
|
delete(sd.unremovableNodes, node.Name)
|
||||||
}
|
}
|
||||||
nodesToCheck = append(nodesToCheck, node)
|
filteredNodesToCheck = append(filteredNodesToCheck, node)
|
||||||
}
|
}
|
||||||
skipped := len(managedNodes) - len(nodesToCheck)
|
skipped := len(nodesToCheck) - len(filteredNodesToCheck)
|
||||||
if skipped > 0 {
|
if skipped > 0 {
|
||||||
glog.V(1).Infof("Scale-down calculation: ignoring %v nodes, that were unremovable in the last %v", skipped, UnremovableNodeRecheckTimeout)
|
glog.V(1).Infof("Scale-down calculation: ignoring %v nodes, that were unremovable in the last %v", skipped, UnremovableNodeRecheckTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase1 - look at the nodes utilization. Calculate the utilization
|
// Phase1 - look at the nodes utilization. Calculate the utilization
|
||||||
// only for the managed nodes.
|
// only for the managed nodes.
|
||||||
for _, node := range nodesToCheck {
|
for _, node := range filteredNodesToCheck {
|
||||||
|
|
||||||
// Skip nodes marked to be deleted, if they were marked recently.
|
// Skip nodes marked to be deleted, if they were marked recently.
|
||||||
// Old-time marked nodes are again eligible for deletion - something went wrong with them
|
// Old-time marked nodes are again eligible for deletion - something went wrong with them
|
||||||
|
|
|
||||||
|
|
@ -266,9 +266,9 @@ func (a *StaticAutoscaler) RunOnce(currentTime time.Time) errors.AutoscalerError
|
||||||
glog.V(4).Infof("Calculating unneeded nodes")
|
glog.V(4).Infof("Calculating unneeded nodes")
|
||||||
|
|
||||||
scaleDown.CleanUp(time.Now())
|
scaleDown.CleanUp(time.Now())
|
||||||
managedNodes := getManagedNodes(autoscalingContext, allNodes)
|
potentiallyUnneeded := getPotentiallyUnneededNodes(autoscalingContext, allNodes)
|
||||||
|
|
||||||
typedErr := scaleDown.UpdateUnneededNodes(allNodes, managedNodes, allScheduled, time.Now(), pdbs)
|
typedErr := scaleDown.UpdateUnneededNodes(allNodes, potentiallyUnneeded, allScheduled, time.Now(), pdbs)
|
||||||
if typedErr != nil {
|
if typedErr != nil {
|
||||||
glog.Errorf("Failed to scale down: %v", typedErr)
|
glog.Errorf("Failed to scale down: %v", typedErr)
|
||||||
return typedErr
|
return typedErr
|
||||||
|
|
|
||||||
|
|
@ -359,8 +359,10 @@ func fixNodeGroupSize(context *AutoscalingContext, currentTime time.Time) (bool,
|
||||||
return fixed, nil
|
return fixed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getManagedNodes returns the nodes managed by the cluster autoscaler.
|
// getPotentiallyUnneededNodes returns nodes that are:
|
||||||
func getManagedNodes(context *AutoscalingContext, nodes []*apiv1.Node) []*apiv1.Node {
|
// - managed by the cluster autoscaler
|
||||||
|
// - in groups with size > min size
|
||||||
|
func getPotentiallyUnneededNodes(context *AutoscalingContext, nodes []*apiv1.Node) []*apiv1.Node {
|
||||||
result := make([]*apiv1.Node, 0, len(nodes))
|
result := make([]*apiv1.Node, 0, len(nodes))
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
nodeGroup, err := context.CloudProvider.NodeGroupForNode(node)
|
nodeGroup, err := context.CloudProvider.NodeGroupForNode(node)
|
||||||
|
|
@ -372,6 +374,15 @@ func getManagedNodes(context *AutoscalingContext, nodes []*apiv1.Node) []*apiv1.
|
||||||
glog.V(4).Infof("Skipping %s - no node group config", node.Name)
|
glog.V(4).Infof("Skipping %s - no node group config", node.Name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
size, err := nodeGroup.TargetSize()
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("Error while checking node group size %s: %v", nodeGroup.Id(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if size <= nodeGroup.MinSize() {
|
||||||
|
glog.V(1).Infof("Skipping %s - node group min size reached", node.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
result = append(result, node)
|
result = append(result, node)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|
|
||||||
|
|
@ -256,3 +256,26 @@ func TestRemoveFixNodeTargetSize(t *testing.T) {
|
||||||
change := getStringFromChan(sizeChanges)
|
change := getStringFromChan(sizeChanges)
|
||||||
assert.Equal(t, "ng1/-2", change)
|
assert.Equal(t, "ng1/-2", change)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetPotentiallyUnneededNodes(t *testing.T) {
|
||||||
|
ng1_1 := BuildTestNode("ng1-1", 1000, 1000)
|
||||||
|
ng1_2 := BuildTestNode("ng1-2", 1000, 1000)
|
||||||
|
ng2_1 := BuildTestNode("ng2-1", 1000, 1000)
|
||||||
|
noNg := BuildTestNode("no-ng", 1000, 1000)
|
||||||
|
provider := testprovider.NewTestCloudProvider(nil, nil)
|
||||||
|
provider.AddNodeGroup("ng1", 1, 10, 2)
|
||||||
|
provider.AddNodeGroup("ng2", 1, 10, 1)
|
||||||
|
provider.AddNode("ng1", ng1_1)
|
||||||
|
provider.AddNode("ng1", ng1_2)
|
||||||
|
provider.AddNode("ng2", ng2_1)
|
||||||
|
|
||||||
|
context := &AutoscalingContext{
|
||||||
|
CloudProvider: provider,
|
||||||
|
}
|
||||||
|
|
||||||
|
result := getPotentiallyUnneededNodes(context, []*apiv1.Node{ng1_1, ng1_2, ng2_1, noNg})
|
||||||
|
assert.Equal(t, 2, len(result))
|
||||||
|
ok1 := result[0].Name == "ng1-1" && result[1].Name == "ng1-2"
|
||||||
|
ok2 := result[1].Name == "ng1-1" && result[0].Name == "ng1-2"
|
||||||
|
assert.True(t, ok1 || ok2)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue