Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enhanced in-place update module to support vertical scaling #1353

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion apis/apps/pub/inplace_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ type InPlaceUpdateState struct {
// NextContainerRefMetadata is the containers with lower priority that waiting for in-place update labels/annotations in next batch.
NextContainerRefMetadata map[string]metav1.ObjectMeta `json:"nextContainerRefMetadata,omitempty"`

// NextContainerResources is the containers with lower priority that waiting for in-place update resources in next batch.
NextContainerResources map[string]v1.ResourceRequirements `json:"nextContainerResources,omitempty"`

// PreCheckBeforeNext is the pre-check that must pass before the next containers can be in-place update.
PreCheckBeforeNext *InPlaceUpdatePreCheckBeforeNext `json:"preCheckBeforeNext,omitempty"`

Expand All @@ -91,7 +94,8 @@ type InPlaceUpdateContainerBatch struct {
// InPlaceUpdateContainerStatus records the statuses of the container that are mainly used
// to determine whether the InPlaceUpdate is completed.
type InPlaceUpdateContainerStatus struct {
ImageID string `json:"imageID,omitempty"`
ImageID string `json:"imageID,omitempty"`
Resource v1.ResourceRequirements `json:"resource,omitempty"`
}

// InPlaceUpdateStrategy defines the strategies for in-place update.
Expand Down
11 changes: 10 additions & 1 deletion apis/apps/pub/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/features/kruise_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ const (

// DeletionProtectionForCRDCascadingGate enable deletionProtection for crd Cascading
DeletionProtectionForCRDCascadingGate featuregate.Feature = "DeletionProtectionForCRDCascadingGate"

// InPlaceWorkloadVerticalScaling enable CloneSet/Advanced StatefulSet controller to support vertical scaling
// of managed Pods.
InPlaceWorkloadVerticalScaling featuregate.Feature = "InPlaceWorkloadVerticalScaling"
)

var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
Expand Down Expand Up @@ -140,6 +144,7 @@ var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
ImagePullJobGate: {Default: false, PreRelease: featuregate.Alpha},
ResourceDistributionGate: {Default: false, PreRelease: featuregate.Alpha},
DeletionProtectionForCRDCascadingGate: {Default: false, PreRelease: featuregate.Alpha},
InPlaceWorkloadVerticalScaling: {Default: false, PreRelease: featuregate.Alpha},
}

func init() {
Expand Down
23 changes: 14 additions & 9 deletions pkg/util/inplaceupdate/inplace_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ import (
)

var (
containerImagePatchRexp = regexp.MustCompile("^/spec/containers/([0-9]+)/image$")
rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
containerImagePatchRexp = regexp.MustCompile("^/spec/containers/([0-9]+)/image$")
containerResourcesPatchRexp = regexp.MustCompile("^/spec/containers/([0-9]+)/resources/.*$")
rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")

Clock clock.Clock = clock.RealClock{}
)
Expand Down Expand Up @@ -79,11 +80,13 @@ type Interface interface {
type UpdateSpec struct {
Revision string `json:"revision"`

ContainerImages map[string]string `json:"containerImages,omitempty"`
ContainerRefMetadata map[string]metav1.ObjectMeta `json:"containerRefMetadata,omitempty"`
MetaDataPatch []byte `json:"metaDataPatch,omitempty"`
UpdateEnvFromMetadata bool `json:"updateEnvFromMetadata,omitempty"`
GraceSeconds int32 `json:"graceSeconds,omitempty"`
ContainerImages map[string]string `json:"containerImages,omitempty"`
ContainerRefMetadata map[string]metav1.ObjectMeta `json:"containerRefMetadata,omitempty"`
ContainerResources map[string]v1.ResourceRequirements `json:"containerResources,omitempty"`
MetaDataPatch []byte `json:"metaDataPatch,omitempty"`
UpdateEnvFromMetadata bool `json:"updateEnvFromMetadata,omitempty"`
GraceSeconds int32 `json:"graceSeconds,omitempty"`
VerticalUpdateOnly bool `json:"verticalUpdate,omitempty"`

OldTemplate *v1.PodTemplateSpec `json:"oldTemplate,omitempty"`
NewTemplate *v1.PodTemplateSpec `json:"newTemplate,omitempty"`
Expand Down Expand Up @@ -131,7 +134,7 @@ func (c *realControl) Refresh(pod *v1.Pod, opts *UpdateOptions) RefreshResult {
}

// check if there are containers with lower-priority that have to in-place update in next batch
if len(state.NextContainerImages) > 0 || len(state.NextContainerRefMetadata) > 0 {
if len(state.NextContainerImages) > 0 || len(state.NextContainerRefMetadata) > 0 || len(state.NextContainerResources) > 0 {

// pre-check the previous updated containers
if checkErr := doPreCheckBeforeNext(pod, state.PreCheckBeforeNext); checkErr != nil {
Expand Down Expand Up @@ -254,6 +257,7 @@ func (c *realControl) updateNextBatch(pod *v1.Pod, opts *UpdateOptions) (bool, e
ContainerImages: state.NextContainerImages,
ContainerRefMetadata: state.NextContainerRefMetadata,
UpdateEnvFromMetadata: state.UpdateEnvFromMetadata,
ContainerResources: state.NextContainerResources,
}
if clone, err = opts.PatchSpecToPod(clone, &spec, &state); err != nil {
return err
Expand Down Expand Up @@ -283,7 +287,8 @@ func (c *realControl) Update(pod *v1.Pod, oldRevision, newRevision *apps.Control
// TODO(FillZpp): maybe we should check if the previous in-place update has completed

// 2. update condition for pod with readiness-gate
if containsReadinessGate(pod) {
// When only workload resources are updated, they are marked as not needing to remove traffic
if !spec.VerticalUpdateOnly && containsReadinessGate(pod) {
newCondition := v1.PodCondition{
Type: appspub.InPlaceUpdateReady,
LastTransitionTime: metav1.NewTime(Clock.Now()),
Expand Down
Loading
Loading