Don't delete nodes with pods with local storage
This commit is contained in:
parent
79687d6b37
commit
ca15ccd27a
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package simulator
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
|
|
@ -29,6 +30,14 @@ import (
|
|||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
var (
|
||||
skipNodesWithSystemPods = flag.Bool("skip-nodes-with-system-pods", true,
|
||||
"If true cluster autoscaler will never delete nodes with pods from kube-system (except for DeamonSet "+
|
||||
"or mirror pods)")
|
||||
skipNodesWithLocalStorage = flag.Bool("skip-nodes-with-local-storage", true,
|
||||
"If true cluster autoscaler will never delete nodes with pods with local storage, e.g. EmptyDir or HostPath")
|
||||
)
|
||||
|
||||
// FindNodesToRemove finds nodes that can be removed.
|
||||
func FindNodesToRemove(candidates []*kube_api.Node, allNodes []*kube_api.Node, pods []*kube_api.Pod,
|
||||
client *kube_client.Client, predicateChecker *PredicateChecker, maxCount int,
|
||||
|
|
@ -56,7 +65,7 @@ candidateloop:
|
|||
|
||||
if fastCheck {
|
||||
if nodeInfo, found := nodeNameToNodeInfo[node.Name]; found {
|
||||
podsToRemove, err = FastGetPodsToMove(nodeInfo, false, true, kube_api.Codecs.UniversalDecoder())
|
||||
podsToRemove, err = FastGetPodsToMove(nodeInfo, false, *skipNodesWithSystemPods, *skipNodesWithLocalStorage, kube_api.Codecs.UniversalDecoder())
|
||||
if err != nil {
|
||||
glog.V(2).Infof("%s: node %s cannot be removed: %v", evaluationType, node.Name, err)
|
||||
continue candidateloop
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import (
|
|||
// along with their pods (no abandoned pods with dangling created-by annotation). Usefull for fast
|
||||
// checks.
|
||||
func FastGetPodsToMove(nodeInfo *schedulercache.NodeInfo, force bool,
|
||||
failOnKubeSystemAddons bool, decoder runtime.Decoder) ([]*api.Pod, error) {
|
||||
skipNodesWithSystemPods bool, skipNodesWithLocalStorage bool, decoder runtime.Decoder) ([]*api.Pod, error) {
|
||||
pods := make([]*api.Pod, 0)
|
||||
unreplicatedPodNames := []string{}
|
||||
for _, pod := range nodeInfo.Pods() {
|
||||
|
|
@ -61,10 +61,14 @@ func FastGetPodsToMove(nodeInfo *schedulercache.NodeInfo, force bool,
|
|||
}
|
||||
}
|
||||
|
||||
if !daemonsetPod && pod.Namespace == "kube-system" && failOnKubeSystemAddons {
|
||||
if !daemonsetPod && pod.Namespace == "kube-system" && skipNodesWithSystemPods {
|
||||
return []*api.Pod{}, fmt.Errorf("non-deamons set, non-mirrored, kube-system pod present: %s", pod.Name)
|
||||
}
|
||||
|
||||
if !daemonsetPod && hasLocalStorage(pod) && skipNodesWithLocalStorage {
|
||||
return []*api.Pod{}, fmt.Errorf("pod with local storage present: %s", pod.Name)
|
||||
}
|
||||
|
||||
switch {
|
||||
case daemonsetPod:
|
||||
break
|
||||
|
|
@ -82,3 +86,16 @@ func FastGetPodsToMove(nodeInfo *schedulercache.NodeInfo, force bool,
|
|||
}
|
||||
return pods, nil
|
||||
}
|
||||
|
||||
func hasLocalStorage(pod *api.Pod) bool {
|
||||
for _, volume := range pod.Spec.Volumes {
|
||||
if isLocalVolume(&volume) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isLocalVolume(volume *api.Volume) bool {
|
||||
return volume.HostPath != nil || volume.EmptyDir != nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func TestFastGetPodsToMove(t *testing.T) {
|
|||
Namespace: "ns",
|
||||
},
|
||||
}
|
||||
_, err := FastGetPodsToMove(schedulercache.NewNodeInfo(pod1), false, true, kube_api.Codecs.UniversalDecoder())
|
||||
_, err := FastGetPodsToMove(schedulercache.NewNodeInfo(pod1), false, true, true, kube_api.Codecs.UniversalDecoder())
|
||||
assert.Error(t, err)
|
||||
|
||||
// Replicated pod
|
||||
|
|
@ -48,7 +48,7 @@ func TestFastGetPodsToMove(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r2, err := FastGetPodsToMove(schedulercache.NewNodeInfo(pod2), false, true, kube_api.Codecs.UniversalDecoder())
|
||||
r2, err := FastGetPodsToMove(schedulercache.NewNodeInfo(pod2), false, true, true, kube_api.Codecs.UniversalDecoder())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(r2))
|
||||
assert.Equal(t, pod2, r2[0])
|
||||
|
|
@ -63,7 +63,7 @@ func TestFastGetPodsToMove(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r3, err := FastGetPodsToMove(schedulercache.NewNodeInfo(pod3), false, true, kube_api.Codecs.UniversalDecoder())
|
||||
r3, err := FastGetPodsToMove(schedulercache.NewNodeInfo(pod3), false, true, true, kube_api.Codecs.UniversalDecoder())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, len(r3))
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ func TestFastGetPodsToMove(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r4, err := FastGetPodsToMove(schedulercache.NewNodeInfo(pod2, pod3, pod4), false, true, kube_api.Codecs.UniversalDecoder())
|
||||
r4, err := FastGetPodsToMove(schedulercache.NewNodeInfo(pod2, pod3, pod4), false, true, true, kube_api.Codecs.UniversalDecoder())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(r4))
|
||||
assert.Equal(t, pod2, r4[0])
|
||||
|
|
@ -92,6 +92,53 @@ func TestFastGetPodsToMove(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
_, err = FastGetPodsToMove(schedulercache.NewNodeInfo(pod5), false, true, kube_api.Codecs.UniversalDecoder())
|
||||
_, err = FastGetPodsToMove(schedulercache.NewNodeInfo(pod5), false, true, true, kube_api.Codecs.UniversalDecoder())
|
||||
assert.Error(t, err)
|
||||
|
||||
// Local storage
|
||||
pod6 := &kube_api.Pod{
|
||||
ObjectMeta: kube_api.ObjectMeta{
|
||||
Name: "pod6",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicaSet\"}}",
|
||||
},
|
||||
},
|
||||
Spec: kube_api.PodSpec{
|
||||
Volumes: []kube_api.Volume{
|
||||
{
|
||||
VolumeSource: kube_api.VolumeSource{
|
||||
EmptyDir: &kube_api.EmptyDirVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err = FastGetPodsToMove(schedulercache.NewNodeInfo(pod6), false, true, true, kube_api.Codecs.UniversalDecoder())
|
||||
assert.Error(t, err)
|
||||
|
||||
// Non-local storage
|
||||
pod7 := &kube_api.Pod{
|
||||
ObjectMeta: kube_api.ObjectMeta{
|
||||
Name: "pod7",
|
||||
Namespace: "ns",
|
||||
Annotations: map[string]string{
|
||||
"kubernetes.io/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicaSet\"}}",
|
||||
},
|
||||
},
|
||||
Spec: kube_api.PodSpec{
|
||||
Volumes: []kube_api.Volume{
|
||||
{
|
||||
VolumeSource: kube_api.VolumeSource{
|
||||
GitRepo: &kube_api.GitRepoVolumeSource{
|
||||
Repository: "my-repo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
r7, err := FastGetPodsToMove(schedulercache.NewNodeInfo(pod7), false, true, true, kube_api.Codecs.UniversalDecoder())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(r7))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue