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
|
package simulator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
|
@ -29,6 +30,14 @@ import (
|
||||||
"github.com/golang/glog"
|
"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.
|
// FindNodesToRemove finds nodes that can be removed.
|
||||||
func FindNodesToRemove(candidates []*kube_api.Node, allNodes []*kube_api.Node, pods []*kube_api.Pod,
|
func FindNodesToRemove(candidates []*kube_api.Node, allNodes []*kube_api.Node, pods []*kube_api.Pod,
|
||||||
client *kube_client.Client, predicateChecker *PredicateChecker, maxCount int,
|
client *kube_client.Client, predicateChecker *PredicateChecker, maxCount int,
|
||||||
|
|
@ -56,7 +65,7 @@ candidateloop:
|
||||||
|
|
||||||
if fastCheck {
|
if fastCheck {
|
||||||
if nodeInfo, found := nodeNameToNodeInfo[node.Name]; found {
|
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 {
|
if err != nil {
|
||||||
glog.V(2).Infof("%s: node %s cannot be removed: %v", evaluationType, node.Name, err)
|
glog.V(2).Infof("%s: node %s cannot be removed: %v", evaluationType, node.Name, err)
|
||||||
continue candidateloop
|
continue candidateloop
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import (
|
||||||
// along with their pods (no abandoned pods with dangling created-by annotation). Usefull for fast
|
// along with their pods (no abandoned pods with dangling created-by annotation). Usefull for fast
|
||||||
// checks.
|
// checks.
|
||||||
func FastGetPodsToMove(nodeInfo *schedulercache.NodeInfo, force bool,
|
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)
|
pods := make([]*api.Pod, 0)
|
||||||
unreplicatedPodNames := []string{}
|
unreplicatedPodNames := []string{}
|
||||||
for _, pod := range nodeInfo.Pods() {
|
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)
|
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 {
|
switch {
|
||||||
case daemonsetPod:
|
case daemonsetPod:
|
||||||
break
|
break
|
||||||
|
|
@ -82,3 +86,16 @@ func FastGetPodsToMove(nodeInfo *schedulercache.NodeInfo, force bool,
|
||||||
}
|
}
|
||||||
return pods, nil
|
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",
|
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)
|
assert.Error(t, err)
|
||||||
|
|
||||||
// Replicated pod
|
// 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.NoError(t, err)
|
||||||
assert.Equal(t, 1, len(r2))
|
assert.Equal(t, 1, len(r2))
|
||||||
assert.Equal(t, pod2, r2[0])
|
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.NoError(t, err)
|
||||||
assert.Equal(t, 0, len(r3))
|
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.NoError(t, err)
|
||||||
assert.Equal(t, 1, len(r4))
|
assert.Equal(t, 1, len(r4))
|
||||||
assert.Equal(t, pod2, r4[0])
|
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)
|
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