mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-10-08 14:29:45 +00:00
daemonset: Implement MaxSurge on daemonset update
If MaxSurge is set, the controller will attempt to double up nodes up to the allowed limit with a new pod, and then when the most recent (by hash) pod is ready, trigger deletion on the old pod. If the old pod goes unready before the new pod is ready, the old pod is immediately deleted. If an old pod goes unready before a new pod is placed on that node, a new pod is immediately added for that node even past the MaxSurge limit. The backoff clock is used consistently throughout the daemonset controller as an injectable clock for the purposes of testing.
This commit is contained in:
@@ -19,13 +19,17 @@ package util
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
apps "k8s.io/api/apps/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
intstrutil "k8s.io/apimachinery/pkg/util/intstr"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// GetTemplateGeneration gets the template generation associated with a v1.DaemonSet by extracting it from the
|
||||
@@ -122,6 +126,43 @@ func CreatePodTemplate(template v1.PodTemplateSpec, generation *int64, hash stri
|
||||
return newTemplate
|
||||
}
|
||||
|
||||
// AllowsSurge returns true if the daemonset allows more than a single pod on any node.
|
||||
func AllowsSurge(ds *apps.DaemonSet) bool {
|
||||
maxSurge, err := SurgeCount(ds, 1)
|
||||
return err == nil && maxSurge > 0
|
||||
}
|
||||
|
||||
// SurgeCount returns 0 if surge is not requested, the expected surge number to allow
|
||||
// out of numberToSchedule if surge is configured, or an error if the surge percentage
|
||||
// requested is invalid.
|
||||
func SurgeCount(ds *apps.DaemonSet, numberToSchedule int) (int, error) {
|
||||
if ds.Spec.UpdateStrategy.Type != apps.RollingUpdateDaemonSetStrategyType {
|
||||
return 0, nil
|
||||
}
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.DaemonSetUpdateSurge) {
|
||||
return 0, nil
|
||||
}
|
||||
r := ds.Spec.UpdateStrategy.RollingUpdate
|
||||
if r == nil {
|
||||
return 0, nil
|
||||
}
|
||||
return intstrutil.GetScaledValueFromIntOrPercent(r.MaxSurge, numberToSchedule, true)
|
||||
}
|
||||
|
||||
// UnavailableCount returns 0 if unavailability is not requested, the expected
|
||||
// unavailability number to allow out of numberToSchedule if requested, or an error if
|
||||
// the unavailability percentage requested is invalid.
|
||||
func UnavailableCount(ds *apps.DaemonSet, numberToSchedule int) (int, error) {
|
||||
if ds.Spec.UpdateStrategy.Type != apps.RollingUpdateDaemonSetStrategyType {
|
||||
return 0, nil
|
||||
}
|
||||
r := ds.Spec.UpdateStrategy.RollingUpdate
|
||||
if r == nil {
|
||||
return 0, nil
|
||||
}
|
||||
return intstrutil.GetScaledValueFromIntOrPercent(r.MaxUnavailable, numberToSchedule, true)
|
||||
}
|
||||
|
||||
// IsPodUpdated checks if pod contains label value that either matches templateGeneration or hash
|
||||
func IsPodUpdated(pod *v1.Pod, hash string, dsTemplateGeneration *int64) bool {
|
||||
// Compare with hash to see if the pod is updated, need to maintain backward compatibility of templateGeneration
|
||||
@@ -131,12 +172,12 @@ func IsPodUpdated(pod *v1.Pod, hash string, dsTemplateGeneration *int64) bool {
|
||||
return hashMatches || templateMatches
|
||||
}
|
||||
|
||||
// SplitByAvailablePods splits provided daemon set pods by availability
|
||||
func SplitByAvailablePods(minReadySeconds int32, pods []*v1.Pod) ([]*v1.Pod, []*v1.Pod) {
|
||||
unavailablePods := []*v1.Pod{}
|
||||
availablePods := []*v1.Pod{}
|
||||
// SplitByAvailablePods splits provided daemon set pods by availability.
|
||||
func SplitByAvailablePods(minReadySeconds int32, pods []*v1.Pod, now time.Time) ([]*v1.Pod, []*v1.Pod) {
|
||||
availablePods := make([]*v1.Pod, 0, len(pods))
|
||||
var unavailablePods []*v1.Pod
|
||||
for _, pod := range pods {
|
||||
if podutil.IsPodAvailable(pod, minReadySeconds, metav1.Now()) {
|
||||
if podutil.IsPodAvailable(pod, minReadySeconds, metav1.Time{Time: now}) {
|
||||
availablePods = append(availablePods, pod)
|
||||
} else {
|
||||
unavailablePods = append(unavailablePods, pod)
|
||||
|
Reference in New Issue
Block a user