From f15db24f8814c3c96460e2574760bfbb068f2a0e Mon Sep 17 00:00:00 2001
From: free6om
Date: Wed, 4 Dec 2024 16:13:36 +0800
Subject: [PATCH 01/11] feat: support InstanceUpdateStrategy
---
apis/apps/v1/cluster_types.go | 5 +++++
apis/apps/v1/component_types.go | 6 ++++++
apis/apps/v1/types.go | 22 ++++++++++++++++++++++
3 files changed, 33 insertions(+)
diff --git a/apis/apps/v1/cluster_types.go b/apis/apps/v1/cluster_types.go
index e1867dc74c8..fa8fcba2bab 100644
--- a/apis/apps/v1/cluster_types.go
+++ b/apis/apps/v1/cluster_types.go
@@ -426,6 +426,11 @@ type ClusterComponentSpec struct {
// +optional
ParallelPodManagementConcurrency *intstr.IntOrString `json:"parallelPodManagementConcurrency,omitempty"`
+ // Controls how the instances should be updated when a new ServiceVersion specified.
+ //
+ // +optional
+ InstanceUpdateStrategy *InstanceUpdateStrategy `json:"instanceUpdateStrategy,omitempty"`
+
// PodUpdatePolicy indicates how pods should be updated
//
// - `StrictInPlace` indicates that only allows in-place upgrades.
diff --git a/apis/apps/v1/component_types.go b/apis/apps/v1/component_types.go
index a0f9117f700..f416970c517 100644
--- a/apis/apps/v1/component_types.go
+++ b/apis/apps/v1/component_types.go
@@ -189,6 +189,12 @@ type ComponentSpec struct {
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
+ // Indicates the InstanceUpdateStrategy that will be
+ // employed to update instances in the InstanceSet when a new ServiceVersion is specified.
+ //
+ // +optional
+ InstanceUpdateStrategy *InstanceUpdateStrategy `json:"instanceUpdateStrategy,omitempty"`
+
// Controls the concurrency of pods during initial scale up, when replacing pods on nodes,
// or when scaling down. It only used when `PodManagementPolicy` is set to `Parallel`.
// The default Concurrency is 100%.
diff --git a/apis/apps/v1/types.go b/apis/apps/v1/types.go
index 0cc99cfc120..47dc1f6edd5 100644
--- a/apis/apps/v1/types.go
+++ b/apis/apps/v1/types.go
@@ -18,6 +18,7 @@ package v1
import (
corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/util/intstr"
)
const (
@@ -661,3 +662,24 @@ type InstanceTemplate struct {
// +optional
VolumeClaimTemplates []ClusterComponentVolumeClaimTemplate `json:"volumeClaimTemplates,omitempty"`
}
+
+// InstanceUpdateStrategy defines how instances of a component should be updated when a new ServiceVersion specified.
+type InstanceUpdateStrategy struct {
+ // Indicates the number of instances that should be updated during a rolling update.
+ // The remaining instances will remain untouched. This is helpful in defining how many instances
+ // should participate in the update process.
+ // Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ // Absolute number is calculated from percentage by rounding up.
+ // The default value is ComponentSpec.Replicas (i.e., update all instances).
+ //
+ // +optional
+ Replicas *intstr.IntOrString `json:"replicas,omitempty"`
+
+ // The maximum number of instances that can be unavailable during the update.
+ // Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ // Absolute number is calculated from percentage by rounding up. This can not be 0.
+ // Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ // it will be counted towards MaxUnavailable.
+ // +optional
+ MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
+}
From 95b47a114eefd4ecfc0c4b00d17b45748d64058e Mon Sep 17 00:00:00 2001
From: free6om
Date: Wed, 4 Dec 2024 16:42:09 +0800
Subject: [PATCH 02/11] rename to RollingUpdate
---
apis/apps/v1/cluster_types.go | 4 ++--
apis/apps/v1/component_types.go | 5 ++---
apis/apps/v1/types.go | 4 ++--
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/apis/apps/v1/cluster_types.go b/apis/apps/v1/cluster_types.go
index fa8fcba2bab..b2b3eb16cc0 100644
--- a/apis/apps/v1/cluster_types.go
+++ b/apis/apps/v1/cluster_types.go
@@ -426,10 +426,10 @@ type ClusterComponentSpec struct {
// +optional
ParallelPodManagementConcurrency *intstr.IntOrString `json:"parallelPodManagementConcurrency,omitempty"`
- // Controls how the instances should be updated when a new ServiceVersion specified.
+ // Provides fine-grained control over the RollingUpdate process when a new ServiceVersion specified.
//
// +optional
- InstanceUpdateStrategy *InstanceUpdateStrategy `json:"instanceUpdateStrategy,omitempty"`
+ RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"`
// PodUpdatePolicy indicates how pods should be updated
//
diff --git a/apis/apps/v1/component_types.go b/apis/apps/v1/component_types.go
index f416970c517..ec8a8cfd53f 100644
--- a/apis/apps/v1/component_types.go
+++ b/apis/apps/v1/component_types.go
@@ -189,11 +189,10 @@ type ComponentSpec struct {
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
- // Indicates the InstanceUpdateStrategy that will be
- // employed to update instances in the InstanceSet when a new ServiceVersion is specified.
+ // Provides fine-grained control over the RollingUpdate process when a new ServiceVersion specified.
//
// +optional
- InstanceUpdateStrategy *InstanceUpdateStrategy `json:"instanceUpdateStrategy,omitempty"`
+ RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"`
// Controls the concurrency of pods during initial scale up, when replacing pods on nodes,
// or when scaling down. It only used when `PodManagementPolicy` is set to `Parallel`.
diff --git a/apis/apps/v1/types.go b/apis/apps/v1/types.go
index 47dc1f6edd5..e64ca586fb2 100644
--- a/apis/apps/v1/types.go
+++ b/apis/apps/v1/types.go
@@ -663,8 +663,8 @@ type InstanceTemplate struct {
VolumeClaimTemplates []ClusterComponentVolumeClaimTemplate `json:"volumeClaimTemplates,omitempty"`
}
-// InstanceUpdateStrategy defines how instances of a component should be updated when a new ServiceVersion specified.
-type InstanceUpdateStrategy struct {
+// RollingUpdate defines fine-grained control over the RollingUpdate process when a new ServiceVersion specified.
+type RollingUpdate struct {
// Indicates the number of instances that should be updated during a rolling update.
// The remaining instances will remain untouched. This is helpful in defining how many instances
// should participate in the update process.
From 02208d3bac87b25c6e6af26682028335b5a83795 Mon Sep 17 00:00:00 2001
From: free6om
Date: Thu, 5 Dec 2024 14:30:22 +0800
Subject: [PATCH 03/11] move&refactor all update related fields into a single
struct
---
apis/apps/v1/cluster_types.go | 16 +---
apis/apps/v1/component_types.go | 15 +---
apis/apps/v1/componentdefinition_types.go | 49 +---------
apis/apps/v1/shardingdefinition_types.go | 4 +-
apis/apps/v1/types.go | 90 +++++++++++++++++--
apis/apps/v1/zz_generated.deepcopy.go | 10 +--
apis/apps/v1alpha1/cluster_conversion.go | 8 +-
.../componentdefinition_controller_test.go | 10 +--
.../apps/shardingdefinition_controller.go | 4 +-
.../shardingdefinition_controller_test.go | 8 +-
pkg/controller/builder/builder_component.go | 2 +-
.../builder/builder_component_definition.go | 2 +-
pkg/controller/component/its_convertor.go | 6 +-
pkg/controller/component/type.go | 22 ++---
.../apps/componentdefinition_factory.go | 2 +-
pkg/testutil/apps/constant.go | 2 +-
.../apps/shardingdefinition_factory.go | 4 +-
17 files changed, 130 insertions(+), 124 deletions(-)
diff --git a/apis/apps/v1/cluster_types.go b/apis/apps/v1/cluster_types.go
index b2b3eb16cc0..f30673a1393 100644
--- a/apis/apps/v1/cluster_types.go
+++ b/apis/apps/v1/cluster_types.go
@@ -426,22 +426,10 @@ type ClusterComponentSpec struct {
// +optional
ParallelPodManagementConcurrency *intstr.IntOrString `json:"parallelPodManagementConcurrency,omitempty"`
- // Provides fine-grained control over the RollingUpdate process when a new ServiceVersion specified.
+ // Provides fine-grained control over the spec update process of all instances.
//
// +optional
- RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"`
-
- // PodUpdatePolicy indicates how pods should be updated
- //
- // - `StrictInPlace` indicates that only allows in-place upgrades.
- // Any attempt to modify other fields will be rejected.
- // - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- // If that fails, it will fall back to the ReCreate, where pod will be recreated.
- // Default value is "PreferInPlace"
- //
- // +kubebuilder:validation:Enum={StrictInPlace,PreferInPlace}
- // +optional
- PodUpdatePolicy *PodUpdatePolicyType `json:"podUpdatePolicy,omitempty"`
+ UpdateStrategy *UpdateStrategy `json:"updateStrategy,omitempty"`
// Allows for the customization of configuration values for each instance within a Component.
// An instance represent a single replica (Pod and associated K8s resources like PVCs, Services, and ConfigMaps).
diff --git a/apis/apps/v1/component_types.go b/apis/apps/v1/component_types.go
index ec8a8cfd53f..26d9c96854b 100644
--- a/apis/apps/v1/component_types.go
+++ b/apis/apps/v1/component_types.go
@@ -189,10 +189,10 @@ type ComponentSpec struct {
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
- // Provides fine-grained control over the RollingUpdate process when a new ServiceVersion specified.
+ // Provides fine-grained control over the spec update process of all instances.
//
// +optional
- RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"`
+ UpdateStrategy *UpdateStrategy `json:"updateStrategy,omitempty"`
// Controls the concurrency of pods during initial scale up, when replacing pods on nodes,
// or when scaling down. It only used when `PodManagementPolicy` is set to `Parallel`.
@@ -201,17 +201,6 @@ type ComponentSpec struct {
// +optional
ParallelPodManagementConcurrency *intstr.IntOrString `json:"parallelPodManagementConcurrency,omitempty"`
- // PodUpdatePolicy indicates how pods should be updated
- //
- // - `StrictInPlace` indicates that only allows in-place upgrades.
- // Any attempt to modify other fields will be rejected.
- // - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- // If that fails, it will fall back to the ReCreate, where pod will be recreated.
- // Default value is "PreferInPlace"
- //
- // +optional
- PodUpdatePolicy *PodUpdatePolicyType `json:"podUpdatePolicy,omitempty"`
-
// Specifies the scheduling policy for the Component.
//
// +optional
diff --git a/apis/apps/v1/componentdefinition_types.go b/apis/apps/v1/componentdefinition_types.go
index 4299b460b86..b0a714c5542 100644
--- a/apis/apps/v1/componentdefinition_types.go
+++ b/apis/apps/v1/componentdefinition_types.go
@@ -444,21 +444,10 @@ type ComponentDefinitionSpec struct {
// +optional
MinReadySeconds int32 `json:"minReadySeconds,omitempty"`
- // Specifies the concurrency strategy for updating multiple instances of the Component.
- // Available strategies:
+ // Specifies fine-grained control over the spec update process of all instances.
//
- // - `Serial`: Updates replicas one at a time, ensuring minimal downtime by waiting for each replica to become ready
- // before updating the next.
- // - `Parallel`: Updates all replicas simultaneously, optimizing for speed but potentially reducing availability
- // during the update.
- // - `BestEffortParallel`: Updates replicas concurrently with a limit on simultaneous updates to ensure a minimum
- // number of operational replicas for maintaining quorum.
- // For example, in a 5-replica component, updating a maximum of 2 replicas simultaneously keeps
- // at least 3 operational for quorum.
- //
- // This field is immutable and defaults to 'Serial'.
+ // This field is immutable.
//
- // +kubebuilder:default=Serial
// +optional
UpdateStrategy *UpdateStrategy `json:"updateStrategy,omitempty"`
@@ -1482,40 +1471,6 @@ type ReplicaRole struct {
Votable bool `json:"votable,omitempty"`
}
-// UpdateStrategy defines the update strategy for cluster components. This strategy determines how updates are applied
-// across the cluster.
-// The available strategies are `Serial`, `BestEffortParallel`, and `Parallel`.
-//
-// +enum
-// +kubebuilder:validation:Enum={Serial,BestEffortParallel,Parallel}
-type UpdateStrategy string
-
-const (
- // SerialStrategy indicates that updates are applied one at a time in a sequential manner.
- // The operator waits for each replica to be updated and ready before proceeding to the next one.
- // This ensures that only one replica is unavailable at a time during the update process.
- SerialStrategy UpdateStrategy = "Serial"
-
- // ParallelStrategy indicates that updates are applied simultaneously to all Pods of a Component.
- // The replicas are updated in parallel, with the operator updating all replicas concurrently.
- // This strategy provides the fastest update time but may lead to a period of reduced availability or
- // capacity during the update process.
- ParallelStrategy UpdateStrategy = "Parallel"
-
- // BestEffortParallelStrategy indicates that the replicas are updated in parallel, with the operator making
- // a best-effort attempt to update as many replicas as possible concurrently
- // while maintaining the component's availability.
- // Unlike the `Parallel` strategy, the `BestEffortParallel` strategy aims to ensure that a minimum number
- // of replicas remain available during the update process to maintain the component's quorum and functionality.
- //
- // For example, consider a component with 5 replicas. To maintain the component's availability and quorum,
- // the operator may allow a maximum of 2 replicas to be simultaneously updated. This ensures that at least
- // 3 replicas (a quorum) remain available and functional during the update process.
- //
- // The `BestEffortParallel` strategy strikes a balance between update speed and component availability.
- BestEffortParallelStrategy UpdateStrategy = "BestEffortParallel"
-)
-
// ComponentLifecycleActions defines a collection of Actions for customizing the behavior of a Component.
type ComponentLifecycleActions struct {
// Specifies the hook to be executed after a component's creation.
diff --git a/apis/apps/v1/shardingdefinition_types.go b/apis/apps/v1/shardingdefinition_types.go
index 6c1adf14cb2..b3f88fb4691 100644
--- a/apis/apps/v1/shardingdefinition_types.go
+++ b/apis/apps/v1/shardingdefinition_types.go
@@ -75,7 +75,7 @@ type ShardingDefinitionSpec struct {
//
// +kubebuilder:default=Serial
// +optional
- ProvisionStrategy *UpdateStrategy `json:"provisionStrategy,omitempty"`
+ ProvisionStrategy *UpdateConcurrency `json:"provisionStrategy,omitempty"`
// Specifies the strategy for updating shards of the sharding. Only `Serial` and `Parallel` are supported.
//
@@ -83,7 +83,7 @@ type ShardingDefinitionSpec struct {
//
// +kubebuilder:default=Serial
// +optional
- UpdateStrategy *UpdateStrategy `json:"updateStrategy,omitempty"`
+ UpdateStrategy *UpdateConcurrency `json:"updateStrategy,omitempty"`
// Defines a set of hooks and procedures that customize the behavior of a sharding throughout its lifecycle.
//
diff --git a/apis/apps/v1/types.go b/apis/apps/v1/types.go
index e64ca586fb2..6369e87b4bb 100644
--- a/apis/apps/v1/types.go
+++ b/apis/apps/v1/types.go
@@ -457,16 +457,16 @@ type ClusterComponentConfigSource struct {
// - Local file
}
-type PodUpdatePolicyType string
+type InstanceUpdatePolicyType string
const (
- // StrictInPlacePodUpdatePolicyType indicates that only allows in-place upgrades.
- // Any attempt to modify other fields will be rejected.
- StrictInPlacePodUpdatePolicyType PodUpdatePolicyType = "StrictInPlace"
+ // StrictInPlaceInstanceUpdatePolicyType indicates that only allows in-place update.
+ // Any attempt to modify other fields that not support in-place update will be rejected.
+ StrictInPlaceInstanceUpdatePolicyType InstanceUpdatePolicyType = "StrictInPlace"
- // PreferInPlacePodUpdatePolicyType indicates that we will first attempt an in-place upgrade of the Pod.
- // If that fails, it will fall back to the ReCreate, where pod will be recreated.
- PreferInPlacePodUpdatePolicyType PodUpdatePolicyType = "PreferInPlace"
+ // PreferInPlaceInstanceUpdatePolicyType indicates that we will first attempt an in-place update of the instance.
+ // If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ PreferInPlaceInstanceUpdatePolicyType InstanceUpdatePolicyType = "PreferInPlace"
)
type SchedulingPolicy struct {
@@ -663,7 +663,27 @@ type InstanceTemplate struct {
VolumeClaimTemplates []ClusterComponentVolumeClaimTemplate `json:"volumeClaimTemplates,omitempty"`
}
-// RollingUpdate defines fine-grained control over the RollingUpdate process when a new ServiceVersion specified.
+// UpdateStrategy defines fine-grained control over the spec update process of all instances.
+type UpdateStrategy struct {
+ // Indicates how instances should be updated.
+ //
+ // - `StrictInPlace` indicates that only allows in-place update.
+ // Any attempt to modify other fields that not support in-place update will be rejected.
+ // - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ // If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ // Default value is "PreferInPlace".
+ //
+ // +kubebuilder:validation:Enum={StrictInPlace,PreferInPlace}
+ // +optional
+ InstanceUpdatePolicy *InstanceUpdatePolicyType `json:"instanceUpdatePolicy,omitempty"`
+
+ // Specifies how the rolling update should be applied.
+ //
+ // +optional
+ RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"`
+}
+
+// RollingUpdate specifies how the rolling update should be applied.
type RollingUpdate struct {
// Indicates the number of instances that should be updated during a rolling update.
// The remaining instances will remain untouched. This is helpful in defining how many instances
@@ -675,11 +695,65 @@ type RollingUpdate struct {
// +optional
Replicas *intstr.IntOrString `json:"replicas,omitempty"`
+ // Specifies the concurrency level for updating instances during a rolling update.
+ // Available levels:
+ //
+ // - `Serial`: Updates instances one at a time, ensuring minimal downtime by waiting for each instance to become ready
+ // before updating the next.
+ // - `Parallel`: Updates all instances simultaneously, optimizing for speed but potentially reducing availability
+ // during the update.
+ // - `BestEffortParallel`: Updates instances concurrently with a limit on simultaneous updates to ensure a minimum
+ // number of operational replicas for maintaining quorum.
+ // For example, in a 5-instances setup, updating a maximum of 2 instances simultaneously keeps
+ // at least 3 operational for quorum.
+ //
+ // Defaults to 'Serial'.
+ //
+ // +kubebuilder:validation:Enum={Serial,Parallel,BestEffortParallel}
+ // +kubebuilder:default=Serial
+ // +optional
+ UpdateConcurrency *UpdateConcurrency `json:"updateConcurrency,omitempty"`
+
// The maximum number of instances that can be unavailable during the update.
// Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
// Absolute number is calculated from percentage by rounding up. This can not be 0.
// Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
// it will be counted towards MaxUnavailable.
+ //
// +optional
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
}
+
+// UpdateConcurrency defines the update concurrency level for cluster components. This concurrency level determines how updates are applied
+// across the cluster.
+// The available concurrency levels are `Serial`, `BestEffortParallel`, and `Parallel`.
+//
+// +enum
+// +kubebuilder:validation:Enum={Serial,BestEffortParallel,Parallel}
+type UpdateConcurrency string
+
+const (
+ // SerialConcurrency indicates that updates are applied one at a time in a sequential manner.
+ // The operator waits for each replica to be updated and ready before proceeding to the next one.
+ // This ensures that only one replica is unavailable at a time during the update process.
+ SerialConcurrency UpdateConcurrency = "Serial"
+
+ // ParallelConcurrency indicates that updates are applied simultaneously to all Pods of a Component.
+ // The replicas are updated in parallel, with the operator updating all replicas concurrently.
+ // This strategy provides the fastest update time but may lead to a period of reduced availability or
+ // capacity during the update process.
+ ParallelConcurrency UpdateConcurrency = "Parallel"
+
+ // BestEffortParallelConcurrency indicates that the replicas are updated in parallel, with the operator making
+ // a best-effort attempt to update as many replicas as possible concurrently
+ // while maintaining the component's availability.
+ // Unlike the `Parallel` strategy, the `BestEffortParallel` strategy aims to ensure that a minimum number
+ // of replicas remain available during the update process to maintain the component's quorum and functionality.
+ //
+ // For example, consider a component with 5 replicas. To maintain the component's availability and quorum,
+ // the operator may allow a maximum of 2 replicas to be simultaneously updated. This ensures that at least
+ // 3 replicas (a quorum) remain available and functional during the update process.
+ //
+ // The `BestEffortParallel` strategy strikes a balance between update speed and component availability.
+ BestEffortParallelConcurrency UpdateConcurrency = "BestEffortParallel"
+)
diff --git a/apis/apps/v1/zz_generated.deepcopy.go b/apis/apps/v1/zz_generated.deepcopy.go
index 7d309c6a4c3..a908b87111c 100644
--- a/apis/apps/v1/zz_generated.deepcopy.go
+++ b/apis/apps/v1/zz_generated.deepcopy.go
@@ -326,7 +326,7 @@ func (in *ClusterComponentSpec) DeepCopyInto(out *ClusterComponentSpec) {
}
if in.PodUpdatePolicy != nil {
in, out := &in.PodUpdatePolicy, &out.PodUpdatePolicy
- *out = new(PodUpdatePolicyType)
+ *out = new(InstanceUpdatePolicyType)
**out = **in
}
if in.Instances != nil {
@@ -1198,7 +1198,7 @@ func (in *ComponentDefinitionSpec) DeepCopyInto(out *ComponentDefinitionSpec) {
}
if in.UpdateStrategy != nil {
in, out := &in.UpdateStrategy, &out.UpdateStrategy
- *out = new(UpdateStrategy)
+ *out = new(UpdateConcurrency)
**out = **in
}
if in.PodManagementPolicy != nil {
@@ -1469,7 +1469,7 @@ func (in *ComponentSpec) DeepCopyInto(out *ComponentSpec) {
}
if in.PodUpdatePolicy != nil {
in, out := &in.PodUpdatePolicy, &out.PodUpdatePolicy
- *out = new(PodUpdatePolicyType)
+ *out = new(InstanceUpdatePolicyType)
**out = **in
}
if in.SchedulingPolicy != nil {
@@ -2948,12 +2948,12 @@ func (in *ShardingDefinitionSpec) DeepCopyInto(out *ShardingDefinitionSpec) {
}
if in.ProvisionStrategy != nil {
in, out := &in.ProvisionStrategy, &out.ProvisionStrategy
- *out = new(UpdateStrategy)
+ *out = new(UpdateConcurrency)
**out = **in
}
if in.UpdateStrategy != nil {
in, out := &in.UpdateStrategy, &out.UpdateStrategy
- *out = new(UpdateStrategy)
+ *out = new(UpdateConcurrency)
**out = **in
}
if in.LifecycleActions != nil {
diff --git a/apis/apps/v1alpha1/cluster_conversion.go b/apis/apps/v1alpha1/cluster_conversion.go
index 44b5e75d0b3..b5ef1e578fa 100644
--- a/apis/apps/v1alpha1/cluster_conversion.go
+++ b/apis/apps/v1alpha1/cluster_conversion.go
@@ -104,13 +104,13 @@ func (r *Cluster) changesToCluster(cluster *appsv1.Cluster) {
// - volumeClaimTemplates
// spec:
// resources: corev1.ResourceRequirements -> corev1.VolumeResourceRequirements
- // podUpdatePolicy: *workloads.PodUpdatePolicyType -> *PodUpdatePolicyType
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *InstanceUpdatePolicyType
// sharings
// - template
// volumeClaimTemplates
// spec:
// resources: corev1.ResourceRequirements -> corev1.VolumeResourceRequirements
- // podUpdatePolicy: *workloads.PodUpdatePolicyType -> *PodUpdatePolicyType
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *InstanceUpdatePolicyType
// status
// components
// - message: ComponentMessageMap -> map[string]string
@@ -132,13 +132,13 @@ func (r *Cluster) changesFromCluster(cluster *appsv1.Cluster) {
// - volumeClaimTemplates
// spec:
// resources: corev1.ResourceRequirements -> corev1.VolumeResourceRequirements
- // podUpdatePolicy: *workloads.PodUpdatePolicyType -> *PodUpdatePolicyType
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *InstanceUpdatePolicyType
// sharings
// - template
// volumeClaimTemplates
// spec:
// resources: corev1.ResourceRequirements -> corev1.VolumeResourceRequirements
- // podUpdatePolicy: *workloads.PodUpdatePolicyType -> *PodUpdatePolicyType
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *InstanceUpdatePolicyType
// status
// components
// - message: ComponentMessageMap -> map[string]string
diff --git a/controllers/apps/componentdefinition_controller_test.go b/controllers/apps/componentdefinition_controller_test.go
index 204a50169e0..a847daf5f75 100644
--- a/controllers/apps/componentdefinition_controller_test.go
+++ b/controllers/apps/componentdefinition_controller_test.go
@@ -522,7 +522,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
Expect(testapps.GetAndChangeObj(&testCtx, client.ObjectKeyFromObject(componentDefObj), func(cmpd *kbappsv1.ComponentDefinition) {
cmpd.Spec.Description = "v0.0.2"
cmpd.Spec.Runtime.Containers[0].Image = "image:v0.0.2"
- parallel := kbappsv1.ParallelStrategy
+ parallel := kbappsv1.ParallelConcurrency
cmpd.Spec.UpdateStrategy = ¶llel
})()).Should(Succeed())
@@ -539,7 +539,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
}
g.Expect(cmpd.Spec.Runtime.Containers[0]).Should(BeEquivalentTo(c))
g.Expect(cmpd.Spec.UpdateStrategy).ShouldNot(BeNil())
- g.Expect(*cmpd.Spec.UpdateStrategy).Should(Equal(kbappsv1.ParallelStrategy))
+ g.Expect(*cmpd.Spec.UpdateStrategy).Should(Equal(kbappsv1.ParallelConcurrency))
})).Should(Succeed())
})
@@ -550,7 +550,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
Expect(testapps.GetAndChangeObj(&testCtx, client.ObjectKeyFromObject(componentDefObj), func(cmpd *kbappsv1.ComponentDefinition) {
cmpd.Spec.Description = "v0.0.2"
cmpd.Spec.Runtime.Containers[0].Image = "image:v0.0.2"
- parallel := kbappsv1.ParallelStrategy
+ parallel := kbappsv1.ParallelConcurrency
cmpd.Spec.UpdateStrategy = ¶llel
})()).Should(Succeed())
@@ -567,7 +567,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
}
g.Expect(cmpd.Spec.Runtime.Containers[0]).Should(BeEquivalentTo(c))
g.Expect(cmpd.Spec.UpdateStrategy).ShouldNot(BeNil())
- g.Expect(*cmpd.Spec.UpdateStrategy).Should(Equal(kbappsv1.ParallelStrategy))
+ g.Expect(*cmpd.Spec.UpdateStrategy).Should(Equal(kbappsv1.ParallelConcurrency))
})).Should(Succeed())
By("revert the change to immutable fields back")
@@ -589,7 +589,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
}
g.Expect(cmpd.Spec.Runtime.Containers[0]).Should(BeEquivalentTo(c))
g.Expect(cmpd.Spec.UpdateStrategy).ShouldNot(BeNil())
- g.Expect(*cmpd.Spec.UpdateStrategy).Should(Equal(kbappsv1.SerialStrategy))
+ g.Expect(*cmpd.Spec.UpdateStrategy).Should(Equal(kbappsv1.SerialConcurrency))
})).Should(Succeed())
})
})
diff --git a/controllers/apps/shardingdefinition_controller.go b/controllers/apps/shardingdefinition_controller.go
index cbf14138dda..54d65a93127 100644
--- a/controllers/apps/shardingdefinition_controller.go
+++ b/controllers/apps/shardingdefinition_controller.go
@@ -188,11 +188,11 @@ func (r *ShardingDefinitionReconciler) validateShardsLimit(ctx context.Context,
func (r *ShardingDefinitionReconciler) validateProvisionNUpdateStrategy(ctx context.Context, cli client.Client,
shardingDef *appsv1.ShardingDefinition) error {
- supported := func(strategy *appsv1.UpdateStrategy) bool {
+ supported := func(strategy *appsv1.UpdateConcurrency) bool {
if strategy == nil {
return true
}
- return *strategy == appsv1.SerialStrategy || *strategy == appsv1.ParallelStrategy
+ return *strategy == appsv1.SerialConcurrency || *strategy == appsv1.ParallelConcurrency
}
if !supported(shardingDef.Spec.ProvisionStrategy) {
return fmt.Errorf("unsupported provision strategy: %s", *shardingDef.Spec.ProvisionStrategy)
diff --git a/controllers/apps/shardingdefinition_controller_test.go b/controllers/apps/shardingdefinition_controller_test.go
index ee8aff37eba..e2fbd84e831 100644
--- a/controllers/apps/shardingdefinition_controller_test.go
+++ b/controllers/apps/shardingdefinition_controller_test.go
@@ -115,8 +115,8 @@ var _ = Describe("ShardingDefinition Controller", func() {
It("ok", func() {
By("create a ShardingDefinition obj")
shardingDefObj := testapps.NewShardingDefinitionFactory(shardingDefName, compDefObj.GetName()).
- SetProvisionStrategy(appsv1.SerialStrategy).
- SetUpdateStrategy(appsv1.ParallelStrategy).
+ SetProvisionStrategy(appsv1.SerialConcurrency).
+ SetUpdateStrategy(appsv1.ParallelConcurrency).
Create(&testCtx).GetObject()
checkObjectStatus(shardingDefObj, appsv1.AvailablePhase)
@@ -125,8 +125,8 @@ var _ = Describe("ShardingDefinition Controller", func() {
It("unsupported strategy", func() {
By("create a ShardingDefinition obj")
shardingDefObj := testapps.NewShardingDefinitionFactory(shardingDefName, compDefObj.GetName()).
- SetProvisionStrategy(appsv1.BestEffortParallelStrategy).
- SetUpdateStrategy(appsv1.BestEffortParallelStrategy).
+ SetProvisionStrategy(appsv1.BestEffortParallelConcurrency).
+ SetUpdateStrategy(appsv1.BestEffortParallelConcurrency).
Create(&testCtx).GetObject()
checkObjectStatus(shardingDefObj, appsv1.UnavailablePhase)
diff --git a/pkg/controller/builder/builder_component.go b/pkg/controller/builder/builder_component.go
index ce41b00d655..5d8ae199a05 100644
--- a/pkg/controller/builder/builder_component.go
+++ b/pkg/controller/builder/builder_component.go
@@ -86,7 +86,7 @@ func (builder *ComponentBuilder) SetParallelPodManagementConcurrency(parallelPod
return builder
}
-func (builder *ComponentBuilder) SetPodUpdatePolicy(policy *appsv1.PodUpdatePolicyType) *ComponentBuilder {
+func (builder *ComponentBuilder) SetPodUpdatePolicy(policy *appsv1.InstanceUpdatePolicyType) *ComponentBuilder {
builder.get().Spec.PodUpdatePolicy = policy
return builder
}
diff --git a/pkg/controller/builder/builder_component_definition.go b/pkg/controller/builder/builder_component_definition.go
index 92497251145..c8087da54b6 100644
--- a/pkg/controller/builder/builder_component_definition.go
+++ b/pkg/controller/builder/builder_component_definition.go
@@ -205,7 +205,7 @@ func (builder *ComponentDefinitionBuilder) AddSystemAccount(accountName string,
return builder
}
-func (builder *ComponentDefinitionBuilder) SetUpdateStrategy(strategy *appsv1.UpdateStrategy) *ComponentDefinitionBuilder {
+func (builder *ComponentDefinitionBuilder) SetUpdateStrategy(strategy *appsv1.UpdateConcurrency) *ComponentDefinitionBuilder {
builder.get().Spec.UpdateStrategy = strategy
return builder
}
diff --git a/pkg/controller/component/its_convertor.go b/pkg/controller/component/its_convertor.go
index af8af9b5d16..3d51af61c54 100644
--- a/pkg/controller/component/its_convertor.go
+++ b/pkg/controller/component/its_convertor.go
@@ -259,11 +259,11 @@ func getMemberUpdateStrategy(synthesizedComp *SynthesizedComponent) *workloads.M
bestEffortParallelUpdate = workloads.BestEffortParallelUpdateStrategy
)
switch *synthesizedComp.UpdateStrategy {
- case kbappsv1.SerialStrategy:
+ case kbappsv1.SerialConcurrency:
return &serial
- case kbappsv1.ParallelStrategy:
+ case kbappsv1.ParallelConcurrency:
return ¶llelUpdate
- case kbappsv1.BestEffortParallelStrategy:
+ case kbappsv1.BestEffortParallelConcurrency:
return &bestEffortParallelUpdate
default:
return nil
diff --git a/pkg/controller/component/type.go b/pkg/controller/component/type.go
index 7b6d06d9f20..2fbc633c63b 100644
--- a/pkg/controller/component/type.go
+++ b/pkg/controller/component/type.go
@@ -42,7 +42,7 @@ type SynthesizedComponent struct {
Replicas int32 `json:"replicas"`
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
PodSpec *corev1.PodSpec `json:"podSpec,omitempty"`
- SidecarVars []kbappsv1.EnvVar // vars defined by sidecars
+ SidecarVars []kbappsv1.EnvVar // vars defined by sidecars
VolumeClaimTemplates []corev1.PersistentVolumeClaimTemplate `json:"volumeClaimTemplates,omitempty"`
LogConfigs []kbappsv1.LogConfig `json:"logConfigs,omitempty"`
ConfigTemplates []kbappsv1.ComponentConfigSpec `json:"configTemplates,omitempty"`
@@ -51,22 +51,22 @@ type SynthesizedComponent struct {
ServiceAccountName string `json:"serviceAccountName,omitempty"`
ServiceReferences map[string]*kbappsv1.ServiceDescriptor `json:"serviceReferences,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
- StaticLabels map[string]string // labels defined by the component definition
- DynamicLabels map[string]string // labels defined by the cluster and component API
+ StaticLabels map[string]string // labels defined by the component definition
+ DynamicLabels map[string]string // labels defined by the cluster and component API
Annotations map[string]string `json:"annotations,omitempty"`
- StaticAnnotations map[string]string // annotations defined by the component definition
- DynamicAnnotations map[string]string // annotations defined by the cluster and component API
+ StaticAnnotations map[string]string // annotations defined by the component definition
+ DynamicAnnotations map[string]string // annotations defined by the cluster and component API
TemplateVars map[string]any `json:"templateVars,omitempty"`
EnvVars []corev1.EnvVar `json:"envVars,omitempty"`
EnvFromSources []corev1.EnvFromSource `json:"envFromSources,omitempty"`
Instances []kbappsv1.InstanceTemplate `json:"instances,omitempty"`
OfflineInstances []string `json:"offlineInstances,omitempty"`
- Roles []kbappsv1.ReplicaRole `json:"roles,omitempty"`
- UpdateStrategy *kbappsv1.UpdateStrategy `json:"updateStrategy,omitempty"`
- PodManagementPolicy *appsv1.PodManagementPolicyType `json:"podManagementPolicy,omitempty"`
- ParallelPodManagementConcurrency *intstr.IntOrString `json:"parallelPodManagementConcurrency,omitempty"`
- PodUpdatePolicy *kbappsv1.PodUpdatePolicyType `json:"podUpdatePolicy,omitempty"`
- PolicyRules []rbacv1.PolicyRule `json:"policyRules,omitempty"`
+ Roles []kbappsv1.ReplicaRole `json:"roles,omitempty"`
+ UpdateStrategy *kbappsv1.UpdateConcurrency `json:"updateStrategy,omitempty"`
+ PodManagementPolicy *appsv1.PodManagementPolicyType `json:"podManagementPolicy,omitempty"`
+ ParallelPodManagementConcurrency *intstr.IntOrString `json:"parallelPodManagementConcurrency,omitempty"`
+ PodUpdatePolicy *kbappsv1.InstanceUpdatePolicyType `json:"podUpdatePolicy,omitempty"`
+ PolicyRules []rbacv1.PolicyRule `json:"policyRules,omitempty"`
LifecycleActions *kbappsv1.ComponentLifecycleActions `json:"lifecycleActions,omitempty"`
SystemAccounts []kbappsv1.SystemAccount `json:"systemAccounts,omitempty"`
Volumes []kbappsv1.ComponentVolume `json:"volumes,omitempty"`
diff --git a/pkg/testutil/apps/componentdefinition_factory.go b/pkg/testutil/apps/componentdefinition_factory.go
index 8871c693202..3f177cf257d 100644
--- a/pkg/testutil/apps/componentdefinition_factory.go
+++ b/pkg/testutil/apps/componentdefinition_factory.go
@@ -276,7 +276,7 @@ func (f *MockComponentDefinitionFactory) AddSystemAccount(accountName string, in
return f
}
-func (f *MockComponentDefinitionFactory) SetUpdateStrategy(strategy *kbappsv1.UpdateStrategy) *MockComponentDefinitionFactory {
+func (f *MockComponentDefinitionFactory) SetUpdateStrategy(strategy *kbappsv1.UpdateConcurrency) *MockComponentDefinitionFactory {
f.Get().Spec.UpdateStrategy = strategy
return f
}
diff --git a/pkg/testutil/apps/constant.go b/pkg/testutil/apps/constant.go
index c18fa35603d..f833612f73f 100644
--- a/pkg/testutil/apps/constant.go
+++ b/pkg/testutil/apps/constant.go
@@ -206,7 +206,7 @@ var (
},
},
},
- UpdateStrategy: &[]appsv1.UpdateStrategy{appsv1.BestEffortParallelStrategy}[0],
+ UpdateStrategy: &[]appsv1.UpdateConcurrency{appsv1.BestEffortParallelConcurrency}[0],
Roles: []appsv1.ReplicaRole{
{
Name: "leader",
diff --git a/pkg/testutil/apps/shardingdefinition_factory.go b/pkg/testutil/apps/shardingdefinition_factory.go
index d1cbc3e61a4..3f41b75ef82 100644
--- a/pkg/testutil/apps/shardingdefinition_factory.go
+++ b/pkg/testutil/apps/shardingdefinition_factory.go
@@ -40,12 +40,12 @@ func NewShardingDefinitionFactory(name, compDef string) *MockShardingDefinitionF
return f
}
-func (f *MockShardingDefinitionFactory) SetProvisionStrategy(strategy appsv1.UpdateStrategy) *MockShardingDefinitionFactory {
+func (f *MockShardingDefinitionFactory) SetProvisionStrategy(strategy appsv1.UpdateConcurrency) *MockShardingDefinitionFactory {
f.Get().Spec.ProvisionStrategy = &strategy
return f
}
-func (f *MockShardingDefinitionFactory) SetUpdateStrategy(strategy appsv1.UpdateStrategy) *MockShardingDefinitionFactory {
+func (f *MockShardingDefinitionFactory) SetUpdateStrategy(strategy appsv1.UpdateConcurrency) *MockShardingDefinitionFactory {
f.Get().Spec.UpdateStrategy = &strategy
return f
}
From 374702c20ccbd3483f8524841c627980dbd044ab Mon Sep 17 00:00:00 2001
From: free6om
Date: Thu, 5 Dec 2024 17:32:31 +0800
Subject: [PATCH 04/11] update stratey constraint
---
apis/apps/v1/componentdefinition_types.go | 69 ++++++++++++++++++-
apis/apps/v1/zz_generated.deepcopy.go | 4 +-
.../componentdefinition_controller_test.go | 18 ++---
.../builder/builder_component_definition.go | 2 +-
.../component/synthesize_component.go | 2 +-
.../apps/componentdefinition_factory.go | 2 +-
pkg/testutil/apps/constant.go | 2 +-
7 files changed, 82 insertions(+), 17 deletions(-)
diff --git a/apis/apps/v1/componentdefinition_types.go b/apis/apps/v1/componentdefinition_types.go
index b0a714c5542..6defdb14251 100644
--- a/apis/apps/v1/componentdefinition_types.go
+++ b/apis/apps/v1/componentdefinition_types.go
@@ -444,12 +444,12 @@ type ComponentDefinitionSpec struct {
// +optional
MinReadySeconds int32 `json:"minReadySeconds,omitempty"`
- // Specifies fine-grained control over the spec update process of all instances.
+ // Specifies constraint on Component's UpdateStrategy.
//
// This field is immutable.
//
// +optional
- UpdateStrategy *UpdateStrategy `json:"updateStrategy,omitempty"`
+ UpdateStrategyConstraint *UpdateStrategyConstraint `json:"updateStrategyConstraint,omitempty"`
// InstanceSet controls the creation of pods during initial scale up, replacement of pods on nodes, and scaling down.
//
@@ -2087,3 +2087,68 @@ const (
HTTPProtocol PrometheusScheme = "http"
HTTPSProtocol PrometheusScheme = "https"
)
+
+// UpdateStrategyConstraint defines constraint on Component's UpdateStrategy.
+type UpdateStrategyConstraint struct {
+ // Specifies how an instance should be updated.
+ //
+ // - `StrictInPlace` indicates that only allows in-place update.
+ // Any attempt to modify other fields that not support in-place update will be rejected.
+ // - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ // If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ // Default value is "PreferInPlace".
+ //
+ // +kubebuilder:validation:Enum={StrictInPlace,PreferInPlace}
+ // +optional
+ InstanceUpdatePolicy *InstanceUpdatePolicyType `json:"instanceUpdatePolicy,omitempty"`
+
+ // Defines what InstanceUpdatePolicyTypes are allowed to be specified in Component.
+ //
+ // +optional
+ InstanceUpdatePoliciesAllowed []InstanceUpdatePolicyType `json:"instanceUpdatePoliciesAllowed,omitempty"`
+
+ // Specifies constraint on Component's RollingUpdate.
+ //
+ // +optional
+ RollingUpdateConstraint *RollingUpdateConstraint `json:"rollingUpdateConstraint,omitempty"`
+}
+
+type RollingUpdateConstraint struct {
+ // Specifies the concurrency level for updating instances during a rolling update.
+ // Available levels:
+ //
+ // - `Serial`: Updates instances one at a time, ensuring minimal downtime by waiting for each instance to become ready
+ // before updating the next.
+ // - `Parallel`: Updates all instances simultaneously, optimizing for speed but potentially reducing availability
+ // during the update.
+ // - `BestEffortParallel`: Updates instances concurrently with a limit on simultaneous updates to ensure a minimum
+ // number of operational replicas for maintaining quorum.
+ // For example, in a 5-instances setup, updating a maximum of 2 instances simultaneously keeps
+ // at least 3 operational for quorum.
+ //
+ // Defaults to 'Serial'.
+ //
+ // +kubebuilder:validation:Enum={Serial,Parallel,BestEffortParallel}
+ // +kubebuilder:default=Serial
+ // +optional
+ UpdateConcurrency *UpdateConcurrency `json:"updateConcurrency,omitempty"`
+
+ // Defines what UpdateConcurrences are allowed to be specified in Component.
+ //
+ // +optional
+ UpdateConcurrencesAllowed []UpdateConcurrency `json:"updateConcurrencesAllowed,omitempty"`
+
+ // The maximum number of instances that can be unavailable during the update.
+ // Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ // Absolute number is calculated from percentage by rounding up. This can not be 0.
+ // Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ // it will be counted towards MaxUnavailable.
+ //
+ // +optional
+ MaxUnavailable *string `json:"maxUnavailable,omitempty"`
+
+ // Defines the upper bound of the MaxUnavailable in Component.
+ //
+ // +optional
+ MaxUnavailableLimit *string `json:"maxUnavailableLimit,omitempty"`
+}
diff --git a/apis/apps/v1/zz_generated.deepcopy.go b/apis/apps/v1/zz_generated.deepcopy.go
index a908b87111c..c4a81a7b534 100644
--- a/apis/apps/v1/zz_generated.deepcopy.go
+++ b/apis/apps/v1/zz_generated.deepcopy.go
@@ -1196,8 +1196,8 @@ func (in *ComponentDefinitionSpec) DeepCopyInto(out *ComponentDefinitionSpec) {
*out = make([]ReplicaRole, len(*in))
copy(*out, *in)
}
- if in.UpdateStrategy != nil {
- in, out := &in.UpdateStrategy, &out.UpdateStrategy
+ if in.UpdateStrategyConstraint != nil {
+ in, out := &in.UpdateStrategyConstraint, &out.UpdateStrategyConstraint
*out = new(UpdateConcurrency)
**out = **in
}
diff --git a/controllers/apps/componentdefinition_controller_test.go b/controllers/apps/componentdefinition_controller_test.go
index a847daf5f75..66ae9938fa7 100644
--- a/controllers/apps/componentdefinition_controller_test.go
+++ b/controllers/apps/componentdefinition_controller_test.go
@@ -523,7 +523,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
cmpd.Spec.Description = "v0.0.2"
cmpd.Spec.Runtime.Containers[0].Image = "image:v0.0.2"
parallel := kbappsv1.ParallelConcurrency
- cmpd.Spec.UpdateStrategy = ¶llel
+ cmpd.Spec.UpdateStrategyConstraint = ¶llel
})()).Should(Succeed())
By(fmt.Sprintf("checking the updated object as %s", strings.ToLower(string(kbappsv1.AvailablePhase))))
@@ -538,8 +538,8 @@ var _ = Describe("ComponentDefinition Controller", func() {
Command: []string{"command"},
}
g.Expect(cmpd.Spec.Runtime.Containers[0]).Should(BeEquivalentTo(c))
- g.Expect(cmpd.Spec.UpdateStrategy).ShouldNot(BeNil())
- g.Expect(*cmpd.Spec.UpdateStrategy).Should(Equal(kbappsv1.ParallelConcurrency))
+ g.Expect(cmpd.Spec.UpdateStrategyConstraint).ShouldNot(BeNil())
+ g.Expect(*cmpd.Spec.UpdateStrategyConstraint).Should(Equal(kbappsv1.ParallelConcurrency))
})).Should(Succeed())
})
@@ -551,7 +551,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
cmpd.Spec.Description = "v0.0.2"
cmpd.Spec.Runtime.Containers[0].Image = "image:v0.0.2"
parallel := kbappsv1.ParallelConcurrency
- cmpd.Spec.UpdateStrategy = ¶llel
+ cmpd.Spec.UpdateStrategyConstraint = ¶llel
})()).Should(Succeed())
By(fmt.Sprintf("checking the updated object as %s", strings.ToLower(string(kbappsv1.UnavailablePhase))))
@@ -566,14 +566,14 @@ var _ = Describe("ComponentDefinition Controller", func() {
Command: []string{"command"},
}
g.Expect(cmpd.Spec.Runtime.Containers[0]).Should(BeEquivalentTo(c))
- g.Expect(cmpd.Spec.UpdateStrategy).ShouldNot(BeNil())
- g.Expect(*cmpd.Spec.UpdateStrategy).Should(Equal(kbappsv1.ParallelConcurrency))
+ g.Expect(cmpd.Spec.UpdateStrategyConstraint).ShouldNot(BeNil())
+ g.Expect(*cmpd.Spec.UpdateStrategyConstraint).Should(Equal(kbappsv1.ParallelConcurrency))
})).Should(Succeed())
By("revert the change to immutable fields back")
Expect(testapps.GetAndChangeObj(&testCtx, client.ObjectKeyFromObject(componentDefObj), func(cmpd *kbappsv1.ComponentDefinition) {
cmpd.Spec.Runtime.Containers[0].Image = "image:v0.0.1"
- cmpd.Spec.UpdateStrategy = nil
+ cmpd.Spec.UpdateStrategyConstraint = nil
})()).Should(Succeed())
By(fmt.Sprintf("checking the updated object as %s", strings.ToLower(string(kbappsv1.AvailablePhase))))
@@ -588,8 +588,8 @@ var _ = Describe("ComponentDefinition Controller", func() {
Command: []string{"command"},
}
g.Expect(cmpd.Spec.Runtime.Containers[0]).Should(BeEquivalentTo(c))
- g.Expect(cmpd.Spec.UpdateStrategy).ShouldNot(BeNil())
- g.Expect(*cmpd.Spec.UpdateStrategy).Should(Equal(kbappsv1.SerialConcurrency))
+ g.Expect(cmpd.Spec.UpdateStrategyConstraint).ShouldNot(BeNil())
+ g.Expect(*cmpd.Spec.UpdateStrategyConstraint).Should(Equal(kbappsv1.SerialConcurrency))
})).Should(Succeed())
})
})
diff --git a/pkg/controller/builder/builder_component_definition.go b/pkg/controller/builder/builder_component_definition.go
index c8087da54b6..d1aaa6eff5a 100644
--- a/pkg/controller/builder/builder_component_definition.go
+++ b/pkg/controller/builder/builder_component_definition.go
@@ -206,7 +206,7 @@ func (builder *ComponentDefinitionBuilder) AddSystemAccount(accountName string,
}
func (builder *ComponentDefinitionBuilder) SetUpdateStrategy(strategy *appsv1.UpdateConcurrency) *ComponentDefinitionBuilder {
- builder.get().Spec.UpdateStrategy = strategy
+ builder.get().Spec.UpdateStrategyConstraint = strategy
return builder
}
diff --git a/pkg/controller/component/synthesize_component.go b/pkg/controller/component/synthesize_component.go
index f3f102ccd8f..18f248dac13 100644
--- a/pkg/controller/component/synthesize_component.go
+++ b/pkg/controller/component/synthesize_component.go
@@ -91,7 +91,7 @@ func BuildSynthesizedComponent(ctx context.Context, cli client.Reader,
ConfigTemplates: compDefObj.Spec.Configs,
ScriptTemplates: compDefObj.Spec.Scripts,
Roles: compDefObj.Spec.Roles,
- UpdateStrategy: compDefObj.Spec.UpdateStrategy,
+ UpdateStrategy: compDefObj.Spec.UpdateStrategyConstraint,
MinReadySeconds: compDefObj.Spec.MinReadySeconds,
PolicyRules: compDefObj.Spec.PolicyRules,
LifecycleActions: compDefObj.Spec.LifecycleActions,
diff --git a/pkg/testutil/apps/componentdefinition_factory.go b/pkg/testutil/apps/componentdefinition_factory.go
index 3f177cf257d..1aa6b160a66 100644
--- a/pkg/testutil/apps/componentdefinition_factory.go
+++ b/pkg/testutil/apps/componentdefinition_factory.go
@@ -277,7 +277,7 @@ func (f *MockComponentDefinitionFactory) AddSystemAccount(accountName string, in
}
func (f *MockComponentDefinitionFactory) SetUpdateStrategy(strategy *kbappsv1.UpdateConcurrency) *MockComponentDefinitionFactory {
- f.Get().Spec.UpdateStrategy = strategy
+ f.Get().Spec.UpdateStrategyConstraint = strategy
return f
}
diff --git a/pkg/testutil/apps/constant.go b/pkg/testutil/apps/constant.go
index f833612f73f..8e6ad00814f 100644
--- a/pkg/testutil/apps/constant.go
+++ b/pkg/testutil/apps/constant.go
@@ -206,7 +206,7 @@ var (
},
},
},
- UpdateStrategy: &[]appsv1.UpdateConcurrency{appsv1.BestEffortParallelConcurrency}[0],
+ UpdateStrategyConstraint: &[]appsv1.UpdateConcurrency{appsv1.BestEffortParallelConcurrency}[0],
Roles: []appsv1.ReplicaRole{
{
Name: "leader",
From 4f3546d7d352556a9d56fc9b1c2f8a6e576e5050 Mon Sep 17 00:00:00 2001
From: free6om
Date: Fri, 6 Dec 2024 10:20:33 +0800
Subject: [PATCH 05/11] flattern update strategy in cmpd
---
apis/apps/v1/componentdefinition_types.go | 95 +++++++----------------
1 file changed, 27 insertions(+), 68 deletions(-)
diff --git a/apis/apps/v1/componentdefinition_types.go b/apis/apps/v1/componentdefinition_types.go
index 6defdb14251..6c129bf2d38 100644
--- a/apis/apps/v1/componentdefinition_types.go
+++ b/apis/apps/v1/componentdefinition_types.go
@@ -444,12 +444,36 @@ type ComponentDefinitionSpec struct {
// +optional
MinReadySeconds int32 `json:"minReadySeconds,omitempty"`
- // Specifies constraint on Component's UpdateStrategy.
+ // Specifies how an instance should be updated.
//
- // This field is immutable.
+ // - `StrictInPlace` indicates that only allows in-place update.
+ // Any attempt to modify other fields that not support in-place update will be rejected.
+ // - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ // If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ // Default value is "PreferInPlace".
+ //
+ // +kubebuilder:validation:Enum={StrictInPlace,PreferInPlace}
+ // +optional
+ InstanceUpdatePolicy *InstanceUpdatePolicyType `json:"instanceUpdatePolicy,omitempty"`
+
+ // Specifies the concurrency level for updating instances during a rolling update.
+ // Available levels:
+ //
+ // - `Serial`: Updates instances one at a time, ensuring minimal downtime by waiting for each instance to become ready
+ // before updating the next.
+ // - `Parallel`: Updates all instances simultaneously, optimizing for speed but potentially reducing availability
+ // during the update.
+ // - `BestEffortParallel`: Updates instances concurrently with a limit on simultaneous updates to ensure a minimum
+ // number of operational replicas for maintaining quorum.
+ // For example, in a 5-instances setup, updating a maximum of 2 instances simultaneously keeps
+ // at least 3 operational for quorum.
+ //
+ // Defaults to 'Serial'.
//
+ // +kubebuilder:validation:Enum={Serial,Parallel,BestEffortParallel}
+ // +kubebuilder:default=Serial
// +optional
- UpdateStrategyConstraint *UpdateStrategyConstraint `json:"updateStrategyConstraint,omitempty"`
+ UpdateConcurrency *UpdateConcurrency `json:"updateConcurrency,omitempty"`
// InstanceSet controls the creation of pods during initial scale up, replacement of pods on nodes, and scaling down.
//
@@ -2087,68 +2111,3 @@ const (
HTTPProtocol PrometheusScheme = "http"
HTTPSProtocol PrometheusScheme = "https"
)
-
-// UpdateStrategyConstraint defines constraint on Component's UpdateStrategy.
-type UpdateStrategyConstraint struct {
- // Specifies how an instance should be updated.
- //
- // - `StrictInPlace` indicates that only allows in-place update.
- // Any attempt to modify other fields that not support in-place update will be rejected.
- // - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
- // If that fails, it will fall back to the ReCreate, where instance will be recreated.
- // Default value is "PreferInPlace".
- //
- // +kubebuilder:validation:Enum={StrictInPlace,PreferInPlace}
- // +optional
- InstanceUpdatePolicy *InstanceUpdatePolicyType `json:"instanceUpdatePolicy,omitempty"`
-
- // Defines what InstanceUpdatePolicyTypes are allowed to be specified in Component.
- //
- // +optional
- InstanceUpdatePoliciesAllowed []InstanceUpdatePolicyType `json:"instanceUpdatePoliciesAllowed,omitempty"`
-
- // Specifies constraint on Component's RollingUpdate.
- //
- // +optional
- RollingUpdateConstraint *RollingUpdateConstraint `json:"rollingUpdateConstraint,omitempty"`
-}
-
-type RollingUpdateConstraint struct {
- // Specifies the concurrency level for updating instances during a rolling update.
- // Available levels:
- //
- // - `Serial`: Updates instances one at a time, ensuring minimal downtime by waiting for each instance to become ready
- // before updating the next.
- // - `Parallel`: Updates all instances simultaneously, optimizing for speed but potentially reducing availability
- // during the update.
- // - `BestEffortParallel`: Updates instances concurrently with a limit on simultaneous updates to ensure a minimum
- // number of operational replicas for maintaining quorum.
- // For example, in a 5-instances setup, updating a maximum of 2 instances simultaneously keeps
- // at least 3 operational for quorum.
- //
- // Defaults to 'Serial'.
- //
- // +kubebuilder:validation:Enum={Serial,Parallel,BestEffortParallel}
- // +kubebuilder:default=Serial
- // +optional
- UpdateConcurrency *UpdateConcurrency `json:"updateConcurrency,omitempty"`
-
- // Defines what UpdateConcurrences are allowed to be specified in Component.
- //
- // +optional
- UpdateConcurrencesAllowed []UpdateConcurrency `json:"updateConcurrencesAllowed,omitempty"`
-
- // The maximum number of instances that can be unavailable during the update.
- // Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
- // Absolute number is calculated from percentage by rounding up. This can not be 0.
- // Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
- // it will be counted towards MaxUnavailable.
- //
- // +optional
- MaxUnavailable *string `json:"maxUnavailable,omitempty"`
-
- // Defines the upper bound of the MaxUnavailable in Component.
- //
- // +optional
- MaxUnavailableLimit *string `json:"maxUnavailableLimit,omitempty"`
-}
From 0a07c96915512af0828369a567b0b36a1ed555b1 Mon Sep 17 00:00:00 2001
From: free6om
Date: Wed, 11 Dec 2024 15:41:28 +0800
Subject: [PATCH 06/11] adjust fields name in controllers according to apis
---
apis/apps/v1/zz_generated.deepcopy.go | 82 +-
apis/workloads/v1/instanceset_types.go | 147 +++-
apis/workloads/v1/zz_generated.deepcopy.go | 66 +-
.../bases/apps.kubeblocks.io_clusters.yaml | 175 +++-
...ps.kubeblocks.io_componentdefinitions.yaml | 52 +-
.../bases/apps.kubeblocks.io_components.yaml | 82 +-
.../workloads.kubeblocks.io_instancesets.yaml | 107 +--
.../componentdefinition_controller_test.go | 20 +-
.../apps/transformer_cluster_component.go | 2 +-
.../apps/transformer_component_workload.go | 5 +-
.../crds/apps.kubeblocks.io_clusters.yaml | 175 +++-
...ps.kubeblocks.io_componentdefinitions.yaml | 52 +-
.../crds/apps.kubeblocks.io_components.yaml | 82 +-
.../workloads.kubeblocks.io_instancesets.yaml | 107 +--
docs/developer_docs/api-reference/cluster.md | 773 +++++++++++-------
pkg/controller/builder/builder_component.go | 4 +-
.../builder/builder_component_definition.go | 4 +-
.../builder/builder_instance_set.go | 20 +-
.../builder/builder_instance_set_test.go | 39 +-
pkg/controller/component/component.go | 2 +-
pkg/controller/component/its_convertor.go | 71 +-
.../component/synthesize_component.go | 41 +-
pkg/controller/component/type.go | 21 +-
pkg/controller/factory/builder_test.go | 10 +-
.../instanceset/reconciler_update.go | 61 +-
.../instanceset/reconciler_update_test.go | 35 +-
pkg/controller/instanceset/update_plan.go | 15 +-
.../instanceset/update_plan_test.go | 40 +-
pkg/controller/instanceset/utils.go | 10 +
.../apps/componentdefinition_factory.go | 4 +-
pkg/testutil/apps/constant.go | 3 +-
pkg/testutil/apps/instance_set_factoy.go | 4 -
32 files changed, 1550 insertions(+), 761 deletions(-)
diff --git a/apis/apps/v1/zz_generated.deepcopy.go b/apis/apps/v1/zz_generated.deepcopy.go
index c4a81a7b534..e3b9e59f620 100644
--- a/apis/apps/v1/zz_generated.deepcopy.go
+++ b/apis/apps/v1/zz_generated.deepcopy.go
@@ -324,10 +324,10 @@ func (in *ClusterComponentSpec) DeepCopyInto(out *ClusterComponentSpec) {
*out = new(intstr.IntOrString)
**out = **in
}
- if in.PodUpdatePolicy != nil {
- in, out := &in.PodUpdatePolicy, &out.PodUpdatePolicy
- *out = new(InstanceUpdatePolicyType)
- **out = **in
+ if in.UpdateStrategy != nil {
+ in, out := &in.UpdateStrategy, &out.UpdateStrategy
+ *out = new(UpdateStrategy)
+ (*in).DeepCopyInto(*out)
}
if in.Instances != nil {
in, out := &in.Instances, &out.Instances
@@ -1196,8 +1196,13 @@ func (in *ComponentDefinitionSpec) DeepCopyInto(out *ComponentDefinitionSpec) {
*out = make([]ReplicaRole, len(*in))
copy(*out, *in)
}
- if in.UpdateStrategyConstraint != nil {
- in, out := &in.UpdateStrategyConstraint, &out.UpdateStrategyConstraint
+ if in.InstanceUpdatePolicy != nil {
+ in, out := &in.InstanceUpdatePolicy, &out.InstanceUpdatePolicy
+ *out = new(InstanceUpdatePolicyType)
+ **out = **in
+ }
+ if in.UpdateConcurrency != nil {
+ in, out := &in.UpdateConcurrency, &out.UpdateConcurrency
*out = new(UpdateConcurrency)
**out = **in
}
@@ -1462,16 +1467,16 @@ func (in *ComponentSpec) DeepCopyInto(out *ComponentSpec) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
+ if in.UpdateStrategy != nil {
+ in, out := &in.UpdateStrategy, &out.UpdateStrategy
+ *out = new(UpdateStrategy)
+ (*in).DeepCopyInto(*out)
+ }
if in.ParallelPodManagementConcurrency != nil {
in, out := &in.ParallelPodManagementConcurrency, &out.ParallelPodManagementConcurrency
*out = new(intstr.IntOrString)
**out = **in
}
- if in.PodUpdatePolicy != nil {
- in, out := &in.PodUpdatePolicy, &out.PodUpdatePolicy
- *out = new(InstanceUpdatePolicyType)
- **out = **in
- }
if in.SchedulingPolicy != nil {
in, out := &in.SchedulingPolicy, &out.SchedulingPolicy
*out = new(SchedulingPolicy)
@@ -2455,6 +2460,36 @@ func (in *RoledVar) DeepCopy() *RoledVar {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *RollingUpdate) DeepCopyInto(out *RollingUpdate) {
+ *out = *in
+ if in.Replicas != nil {
+ in, out := &in.Replicas, &out.Replicas
+ *out = new(intstr.IntOrString)
+ **out = **in
+ }
+ if in.UpdateConcurrency != nil {
+ in, out := &in.UpdateConcurrency, &out.UpdateConcurrency
+ *out = new(UpdateConcurrency)
+ **out = **in
+ }
+ if in.MaxUnavailable != nil {
+ in, out := &in.MaxUnavailable, &out.MaxUnavailable
+ *out = new(intstr.IntOrString)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdate.
+func (in *RollingUpdate) DeepCopy() *RollingUpdate {
+ if in == nil {
+ return nil
+ }
+ out := new(RollingUpdate)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SchedulingPolicy) DeepCopyInto(out *SchedulingPolicy) {
*out = *in
@@ -3370,6 +3405,31 @@ func (in *TLSVars) DeepCopy() *TLSVars {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *UpdateStrategy) DeepCopyInto(out *UpdateStrategy) {
+ *out = *in
+ if in.InstanceUpdatePolicy != nil {
+ in, out := &in.InstanceUpdatePolicy, &out.InstanceUpdatePolicy
+ *out = new(InstanceUpdatePolicyType)
+ **out = **in
+ }
+ if in.RollingUpdate != nil {
+ in, out := &in.RollingUpdate, &out.RollingUpdate
+ *out = new(RollingUpdate)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateStrategy.
+func (in *UpdateStrategy) DeepCopy() *UpdateStrategy {
+ if in == nil {
+ return nil
+ }
+ out := new(UpdateStrategy)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VarSource) DeepCopyInto(out *VarSource) {
*out = *in
diff --git a/apis/workloads/v1/instanceset_types.go b/apis/workloads/v1/instanceset_types.go
index b67f4a2fcd0..80353cc84e3 100644
--- a/apis/workloads/v1/instanceset_types.go
+++ b/apis/workloads/v1/instanceset_types.go
@@ -171,24 +171,10 @@ type InstanceSetSpec struct {
// +optional
ParallelPodManagementConcurrency *intstr.IntOrString `json:"parallelPodManagementConcurrency,omitempty"`
- // PodUpdatePolicy indicates how pods should be updated
- //
- // - `StrictInPlace` indicates that only allows in-place upgrades.
- // Any attempt to modify other fields will be rejected.
- // - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- // If that fails, it will fall back to the ReCreate, where pod will be recreated.
- // Default value is "PreferInPlace"
+ // Provides fine-grained control over the spec update process of all instances.
//
// +optional
- PodUpdatePolicy PodUpdatePolicyType `json:"podUpdatePolicy,omitempty"`
-
- // Indicates the StatefulSetUpdateStrategy that will be
- // employed to update Pods in the InstanceSet when a revision is made to
- // Template.
- // UpdateStrategy.Type will be set to appsv1.OnDeleteStatefulSetStrategyType if MemberUpdateStrategy is not nil
- //
- // Note: This field will be removed in future version.
- UpdateStrategy appsv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"`
+ UpdateStrategy *UpdateStrategy `json:"updateStrategy,omitempty"`
// A list of roles defined in the system.
//
@@ -205,16 +191,6 @@ type InstanceSetSpec struct {
// +optional
MembershipReconfiguration *MembershipReconfiguration `json:"membershipReconfiguration,omitempty"`
- // Members(Pods) update strategy.
- //
- // - serial: update Members one by one that guarantee minimum component unavailable time.
- // - bestEffortParallel: update Members in parallel that guarantee minimum component un-writable time.
- // - parallel: force parallel
- //
- // +kubebuilder:validation:Enum={Serial,BestEffortParallel,Parallel}
- // +optional
- MemberUpdateStrategy *MemberUpdateStrategy `json:"memberUpdateStrategy,omitempty"`
-
// Indicates that the InstanceSet is paused, meaning the reconciliation of this InstanceSet object will be paused.
// +optional
Paused bool `json:"paused,omitempty"`
@@ -456,16 +432,111 @@ type SchedulingPolicy struct {
TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"`
}
-type PodUpdatePolicyType string
+// UpdateStrategy defines fine-grained control over the spec update process of all instances.
+type UpdateStrategy struct {
+ // Indicates how instances should be updated.
+ //
+ // - `StrictInPlace` indicates that only allows in-place update.
+ // Any attempt to modify other fields that not support in-place update will be rejected.
+ // - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ // If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ // Default value is "PreferInPlace".
+ //
+ // +kubebuilder:validation:Enum={StrictInPlace,PreferInPlace}
+ // +optional
+ InstanceUpdatePolicy *InstanceUpdatePolicyType `json:"instanceUpdatePolicy,omitempty"`
+
+ // Specifies how the rolling update should be applied.
+ //
+ // +optional
+ RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"`
+}
+
+// RollingUpdate specifies how the rolling update should be applied.
+type RollingUpdate struct {
+ // Indicates the number of instances that should be updated during a rolling update.
+ // The remaining instances will remain untouched. This is helpful in defining how many instances
+ // should participate in the update process.
+ // Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ // Absolute number is calculated from percentage by rounding up.
+ // The default value is ComponentSpec.Replicas (i.e., update all instances).
+ //
+ // +optional
+ Replicas *intstr.IntOrString `json:"replicas,omitempty"`
+
+ // Specifies the concurrency level for updating instances during a rolling update.
+ // Available levels:
+ //
+ // - `Serial`: Updates instances one at a time, ensuring minimal downtime by waiting for each instance to become ready
+ // before updating the next.
+ // - `Parallel`: Updates all instances simultaneously, optimizing for speed but potentially reducing availability
+ // during the update.
+ // - `BestEffortParallel`: Updates instances concurrently with a limit on simultaneous updates to ensure a minimum
+ // number of operational replicas for maintaining quorum.
+ // For example, in a 5-instances setup, updating a maximum of 2 instances simultaneously keeps
+ // at least 3 operational for quorum.
+ //
+ // Defaults to 'Serial'.
+ //
+ // +kubebuilder:validation:Enum={Serial,Parallel,BestEffortParallel}
+ // +kubebuilder:default=Serial
+ // +optional
+ UpdateConcurrency *UpdateConcurrency `json:"updateConcurrency,omitempty"`
+
+ // The maximum number of instances that can be unavailable during the update.
+ // Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ // Absolute number is calculated from percentage by rounding up. This can not be 0.
+ // Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ // it will be counted towards MaxUnavailable.
+ //
+ // +optional
+ MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
+}
+
+type InstanceUpdatePolicyType string
const (
- // StrictInPlacePodUpdatePolicyType indicates that only allows in-place upgrades.
- // Any attempt to modify other fields will be rejected.
- StrictInPlacePodUpdatePolicyType PodUpdatePolicyType = "StrictInPlace"
+ // StrictInPlaceInstanceUpdatePolicyType indicates that only allows in-place update.
+ // Any attempt to modify other fields that not support in-place update will be rejected.
+ StrictInPlaceInstanceUpdatePolicyType InstanceUpdatePolicyType = "StrictInPlace"
- // PreferInPlacePodUpdatePolicyType indicates that we will first attempt an in-place upgrade of the Pod.
- // If that fails, it will fall back to the ReCreate, where pod will be recreated.
- PreferInPlacePodUpdatePolicyType PodUpdatePolicyType = "PreferInPlace"
+ // PreferInPlaceInstanceUpdatePolicyType indicates that we will first attempt an in-place update of the instance.
+ // If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ PreferInPlaceInstanceUpdatePolicyType InstanceUpdatePolicyType = "PreferInPlace"
+)
+
+// UpdateConcurrency defines the update concurrency level for cluster components. This concurrency level determines how updates are applied
+// across the cluster.
+// The available concurrency levels are `Serial`, `BestEffortParallel`, and `Parallel`.
+//
+// +enum
+// +kubebuilder:validation:Enum={Serial,BestEffortParallel,Parallel}
+type UpdateConcurrency string
+
+const (
+ // SerialConcurrency indicates that updates are applied one at a time in a sequential manner.
+ // The operator waits for each replica to be updated and ready before proceeding to the next one.
+ // This ensures that only one replica is unavailable at a time during the update process.
+ SerialConcurrency UpdateConcurrency = "Serial"
+
+ // ParallelConcurrency indicates that updates are applied simultaneously to all Pods of a Component.
+ // The replicas are updated in parallel, with the operator updating all replicas concurrently.
+ // This strategy provides the fastest update time but may lead to a period of reduced availability or
+ // capacity during the update process.
+ ParallelConcurrency UpdateConcurrency = "Parallel"
+
+ // BestEffortParallelConcurrency indicates that the replicas are updated in parallel, with the operator making
+ // a best-effort attempt to update as many replicas as possible concurrently
+ // while maintaining the component's availability.
+ // Unlike the `Parallel` strategy, the `BestEffortParallel` strategy aims to ensure that a minimum number
+ // of replicas remain available during the update process to maintain the component's quorum and functionality.
+ //
+ // For example, consider a component with 5 replicas. To maintain the component's availability and quorum,
+ // the operator may allow a maximum of 2 replicas to be simultaneously updated. This ensures that at least
+ // 3 replicas (a quorum) remain available and functional during the update process.
+ //
+ // The `BestEffortParallel` strategy strikes a balance between update speed and component availability.
+ BestEffortParallelConcurrency UpdateConcurrency = "BestEffortParallel"
)
type ReplicaRole struct {
@@ -628,16 +699,6 @@ type MembershipReconfiguration struct {
PromoteAction *Action `json:"promoteAction,omitempty"`
}
-// MemberUpdateStrategy defines Cluster Component update strategy.
-// +enum
-type MemberUpdateStrategy string
-
-const (
- SerialUpdateStrategy MemberUpdateStrategy = "Serial"
- BestEffortParallelUpdateStrategy MemberUpdateStrategy = "BestEffortParallel"
- ParallelUpdateStrategy MemberUpdateStrategy = "Parallel"
-)
-
type Credential struct {
// Defines the user's name for the credential.
// The corresponding environment variable will be KB_ITS_USERNAME.
diff --git a/apis/workloads/v1/zz_generated.deepcopy.go b/apis/workloads/v1/zz_generated.deepcopy.go
index f36aeda179e..8d306d6131f 100644
--- a/apis/workloads/v1/zz_generated.deepcopy.go
+++ b/apis/workloads/v1/zz_generated.deepcopy.go
@@ -190,7 +190,11 @@ func (in *InstanceSetSpec) DeepCopyInto(out *InstanceSetSpec) {
*out = new(intstr.IntOrString)
**out = **in
}
- in.UpdateStrategy.DeepCopyInto(&out.UpdateStrategy)
+ if in.UpdateStrategy != nil {
+ in, out := &in.UpdateStrategy, &out.UpdateStrategy
+ *out = new(UpdateStrategy)
+ (*in).DeepCopyInto(*out)
+ }
if in.Roles != nil {
in, out := &in.Roles, &out.Roles
*out = make([]ReplicaRole, len(*in))
@@ -206,11 +210,6 @@ func (in *InstanceSetSpec) DeepCopyInto(out *InstanceSetSpec) {
*out = new(MembershipReconfiguration)
(*in).DeepCopyInto(*out)
}
- if in.MemberUpdateStrategy != nil {
- in, out := &in.MemberUpdateStrategy, &out.MemberUpdateStrategy
- *out = new(MemberUpdateStrategy)
- **out = **in
- }
if in.Credential != nil {
in, out := &in.Credential, &out.Credential
*out = new(Credential)
@@ -506,6 +505,36 @@ func (in *RoleProbe) DeepCopy() *RoleProbe {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *RollingUpdate) DeepCopyInto(out *RollingUpdate) {
+ *out = *in
+ if in.Replicas != nil {
+ in, out := &in.Replicas, &out.Replicas
+ *out = new(intstr.IntOrString)
+ **out = **in
+ }
+ if in.UpdateConcurrency != nil {
+ in, out := &in.UpdateConcurrency, &out.UpdateConcurrency
+ *out = new(UpdateConcurrency)
+ **out = **in
+ }
+ if in.MaxUnavailable != nil {
+ in, out := &in.MaxUnavailable, &out.MaxUnavailable
+ *out = new(intstr.IntOrString)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdate.
+func (in *RollingUpdate) DeepCopy() *RollingUpdate {
+ if in == nil {
+ return nil
+ }
+ out := new(RollingUpdate)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SchedulingPolicy) DeepCopyInto(out *SchedulingPolicy) {
*out = *in
@@ -546,3 +575,28 @@ func (in *SchedulingPolicy) DeepCopy() *SchedulingPolicy {
in.DeepCopyInto(out)
return out
}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *UpdateStrategy) DeepCopyInto(out *UpdateStrategy) {
+ *out = *in
+ if in.InstanceUpdatePolicy != nil {
+ in, out := &in.InstanceUpdatePolicy, &out.InstanceUpdatePolicy
+ *out = new(InstanceUpdatePolicyType)
+ **out = **in
+ }
+ if in.RollingUpdate != nil {
+ in, out := &in.RollingUpdate, &out.RollingUpdate
+ *out = new(RollingUpdate)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateStrategy.
+func (in *UpdateStrategy) DeepCopy() *UpdateStrategy {
+ if in == nil {
+ return nil
+ }
+ out := new(UpdateStrategy)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/config/crd/bases/apps.kubeblocks.io_clusters.yaml b/config/crd/bases/apps.kubeblocks.io_clusters.yaml
index 2d4cc34c940..a8f51511f11 100644
--- a/config/crd/bases/apps.kubeblocks.io_clusters.yaml
+++ b/config/crd/bases/apps.kubeblocks.io_clusters.yaml
@@ -3783,20 +3783,6 @@ spec:
or when scaling down. It only used when `PodManagementPolicy` is set to `Parallel`.
The default Concurrency is 100%.
x-kubernetes-int-or-string: true
- podUpdatePolicy:
- description: |-
- PodUpdatePolicy indicates how pods should be updated
-
-
- - `StrictInPlace` indicates that only allows in-place upgrades.
- Any attempt to modify other fields will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- If that fails, it will fall back to the ReCreate, where pod will be recreated.
- Default value is "PreferInPlace"
- enum:
- - StrictInPlace
- - PreferInPlace
- type: string
replicas:
default: 1
description: Specifies the desired number of replicas in the
@@ -5352,6 +5338,79 @@ spec:
If TLS is enabled, the Component may require additional configuration, such as specifying TLS certificates and keys,
to properly set up the secure communication channel.
type: boolean
+ updateStrategy:
+ description: Provides fine-grained control over the spec update
+ process of all instances.
+ properties:
+ instanceUpdatePolicy:
+ description: |-
+ Indicates how instances should be updated.
+
+
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
+ rollingUpdate:
+ description: Specifies how the rolling update should be
+ applied.
+ properties:
+ maxUnavailable:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ The maximum number of instances that can be unavailable during the update.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up. This can not be 0.
+ Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ it will be counted towards MaxUnavailable.
+ x-kubernetes-int-or-string: true
+ replicas:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Indicates the number of instances that should be updated during a rolling update.
+ The remaining instances will remain untouched. This is helpful in defining how many instances
+ should participate in the update process.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up.
+ The default value is ComponentSpec.Replicas (i.e., update all instances).
+ x-kubernetes-int-or-string: true
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
+ default: Serial
+ description: "Specifies the concurrency level for updating
+ instances during a rolling update.\nAvailable levels:\n\n\n-
+ `Serial`: Updates instances one at a time, ensuring
+ minimal downtime by waiting for each instance to become
+ ready\n before updating the next.\n- `Parallel`:
+ Updates all instances simultaneously, optimizing for
+ speed but potentially reducing availability\n during
+ the update.\n- `BestEffortParallel`: Updates instances
+ concurrently with a limit on simultaneous updates
+ to ensure a minimum\n number of operational replicas
+ for maintaining quorum.\n\t For example, in a 5-instances
+ setup, updating a maximum of 2 instances simultaneously
+ keeps\n\t at least 3 operational for quorum.\n\n\nDefaults
+ to 'Serial'."
+ type: string
+ type: object
+ type: object
volumeClaimTemplates:
description: |-
Specifies a list of PersistentVolumeClaim templates that represent the storage requirements for the Component.
@@ -12473,20 +12532,6 @@ spec:
or when scaling down. It only used when `PodManagementPolicy` is set to `Parallel`.
The default Concurrency is 100%.
x-kubernetes-int-or-string: true
- podUpdatePolicy:
- description: |-
- PodUpdatePolicy indicates how pods should be updated
-
-
- - `StrictInPlace` indicates that only allows in-place upgrades.
- Any attempt to modify other fields will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- If that fails, it will fall back to the ReCreate, where pod will be recreated.
- Default value is "PreferInPlace"
- enum:
- - StrictInPlace
- - PreferInPlace
- type: string
replicas:
default: 1
description: Specifies the desired number of replicas in
@@ -14054,6 +14099,80 @@ spec:
If TLS is enabled, the Component may require additional configuration, such as specifying TLS certificates and keys,
to properly set up the secure communication channel.
type: boolean
+ updateStrategy:
+ description: Provides fine-grained control over the spec
+ update process of all instances.
+ properties:
+ instanceUpdatePolicy:
+ description: |-
+ Indicates how instances should be updated.
+
+
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
+ rollingUpdate:
+ description: Specifies how the rolling update should
+ be applied.
+ properties:
+ maxUnavailable:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ The maximum number of instances that can be unavailable during the update.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up. This can not be 0.
+ Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ it will be counted towards MaxUnavailable.
+ x-kubernetes-int-or-string: true
+ replicas:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Indicates the number of instances that should be updated during a rolling update.
+ The remaining instances will remain untouched. This is helpful in defining how many instances
+ should participate in the update process.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up.
+ The default value is ComponentSpec.Replicas (i.e., update all instances).
+ x-kubernetes-int-or-string: true
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
+ default: Serial
+ description: "Specifies the concurrency level for
+ updating instances during a rolling update.\nAvailable
+ levels:\n\n\n- `Serial`: Updates instances one
+ at a time, ensuring minimal downtime by waiting
+ for each instance to become ready\n before updating
+ the next.\n- `Parallel`: Updates all instances
+ simultaneously, optimizing for speed but potentially
+ reducing availability\n during the update.\n-
+ `BestEffortParallel`: Updates instances concurrently
+ with a limit on simultaneous updates to ensure
+ a minimum\n number of operational replicas for
+ maintaining quorum.\n\t For example, in a 5-instances
+ setup, updating a maximum of 2 instances simultaneously
+ keeps\n\t at least 3 operational for quorum.\n\n\nDefaults
+ to 'Serial'."
+ type: string
+ type: object
+ type: object
volumeClaimTemplates:
description: |-
Specifies a list of PersistentVolumeClaim templates that represent the storage requirements for the Component.
diff --git a/config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml b/config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml
index 636b9b48c8e..a592d737879 100644
--- a/config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml
+++ b/config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml
@@ -4489,6 +4489,20 @@ spec:
type: object
type: array
type: object
+ instanceUpdatePolicy:
+ description: |-
+ Specifies how an instance should be updated.
+
+
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
labels:
additionalProperties:
type: string
@@ -16847,24 +16861,28 @@ spec:
- mountPath
- volumeName
type: object
- updateStrategy:
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
default: Serial
- description: "Specifies the concurrency strategy for updating multiple
- instances of the Component.\nAvailable strategies:\n\n\n- `Serial`:
- Updates replicas one at a time, ensuring minimal downtime by waiting
- for each replica to become ready\n before updating the next.\n-
- `Parallel`: Updates all replicas simultaneously, optimizing for
- speed but potentially reducing availability\n during the update.\n-
- `BestEffortParallel`: Updates replicas concurrently with a limit
- on simultaneous updates to ensure a minimum\n number of operational
- replicas for maintaining quorum.\n\t For example, in a 5-replica
- component, updating a maximum of 2 replicas simultaneously keeps\n\t
- at least 3 operational for quorum.\n\n\nThis field is immutable
- and defaults to 'Serial'."
- enum:
- - Serial
- - BestEffortParallel
- - Parallel
+ description: "Specifies the concurrency level for updating instances
+ during a rolling update.\nAvailable levels:\n\n\n- `Serial`: Updates
+ instances one at a time, ensuring minimal downtime by waiting for
+ each instance to become ready\n before updating the next.\n- `Parallel`:
+ Updates all instances simultaneously, optimizing for speed but potentially
+ reducing availability\n during the update.\n- `BestEffortParallel`:
+ Updates instances concurrently with a limit on simultaneous updates
+ to ensure a minimum\n number of operational replicas for maintaining
+ quorum.\n\t For example, in a 5-instances setup, updating a maximum
+ of 2 instances simultaneously keeps\n\t at least 3 operational for
+ quorum.\n\n\nDefaults to 'Serial'."
type: string
vars:
description: |-
diff --git a/config/crd/bases/apps.kubeblocks.io_components.yaml b/config/crd/bases/apps.kubeblocks.io_components.yaml
index 9da4fd1e563..ca5f89dbec8 100644
--- a/config/crd/bases/apps.kubeblocks.io_components.yaml
+++ b/config/crd/bases/apps.kubeblocks.io_components.yaml
@@ -3562,17 +3562,6 @@ spec:
or when scaling down. It only used when `PodManagementPolicy` is set to `Parallel`.
The default Concurrency is 100%.
x-kubernetes-int-or-string: true
- podUpdatePolicy:
- description: |-
- PodUpdatePolicy indicates how pods should be updated
-
-
- - `StrictInPlace` indicates that only allows in-place upgrades.
- Any attempt to modify other fields will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- If that fails, it will fall back to the ReCreate, where pod will be recreated.
- Default value is "PreferInPlace"
- type: string
replicas:
default: 1
description: Specifies the desired number of replicas in the Component
@@ -5612,6 +5601,77 @@ spec:
- name
type: object
type: object
+ updateStrategy:
+ description: Provides fine-grained control over the spec update process
+ of all instances.
+ properties:
+ instanceUpdatePolicy:
+ description: |-
+ Indicates how instances should be updated.
+
+
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
+ rollingUpdate:
+ description: Specifies how the rolling update should be applied.
+ properties:
+ maxUnavailable:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ The maximum number of instances that can be unavailable during the update.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up. This can not be 0.
+ Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ it will be counted towards MaxUnavailable.
+ x-kubernetes-int-or-string: true
+ replicas:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Indicates the number of instances that should be updated during a rolling update.
+ The remaining instances will remain untouched. This is helpful in defining how many instances
+ should participate in the update process.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up.
+ The default value is ComponentSpec.Replicas (i.e., update all instances).
+ x-kubernetes-int-or-string: true
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
+ default: Serial
+ description: "Specifies the concurrency level for updating
+ instances during a rolling update.\nAvailable levels:\n\n\n-
+ `Serial`: Updates instances one at a time, ensuring minimal
+ downtime by waiting for each instance to become ready\n
+ \ before updating the next.\n- `Parallel`: Updates all instances
+ simultaneously, optimizing for speed but potentially reducing
+ availability\n during the update.\n- `BestEffortParallel`:
+ Updates instances concurrently with a limit on simultaneous
+ updates to ensure a minimum\n number of operational replicas
+ for maintaining quorum.\n\t For example, in a 5-instances
+ setup, updating a maximum of 2 instances simultaneously
+ keeps\n\t at least 3 operational for quorum.\n\n\nDefaults
+ to 'Serial'."
+ type: string
+ type: object
+ type: object
volumeClaimTemplates:
description: |-
Specifies a list of PersistentVolumeClaim templates that define the storage requirements for the Component.
diff --git a/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml b/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml
index 3da51ffb9f8..be1d243810e 100644
--- a/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml
+++ b/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml
@@ -3941,19 +3941,6 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
- memberUpdateStrategy:
- description: |-
- Members(Pods) update strategy.
-
-
- - serial: update Members one by one that guarantee minimum component unavailable time.
- - bestEffortParallel: update Members in parallel that guarantee minimum component un-writable time.
- - parallel: force parallel
- enum:
- - Serial
- - BestEffortParallel
- - Parallel
- type: string
membershipReconfiguration:
description: Provides actions to do membership dynamic reconfiguration.
properties:
@@ -4154,17 +4141,6 @@ spec:
Note: This field will be removed in future version.
type: string
- podUpdatePolicy:
- description: |-
- PodUpdatePolicy indicates how pods should be updated
-
-
- - `StrictInPlace` indicates that only allows in-place upgrades.
- Any attempt to modify other fields will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- If that fails, it will fall back to the ReCreate, where pod will be recreated.
- Default value is "PreferInPlace"
- type: string
replicas:
default: 1
description: |-
@@ -11843,46 +11819,75 @@ spec:
type: object
type: object
updateStrategy:
- description: |-
- Indicates the StatefulSetUpdateStrategy that will be
- employed to update Pods in the InstanceSet when a revision is made to
- Template.
- UpdateStrategy.Type will be set to appsv1.OnDeleteStatefulSetStrategyType if MemberUpdateStrategy is not nil
+ description: Provides fine-grained control over the spec update process
+ of all instances.
+ properties:
+ instanceUpdatePolicy:
+ description: |-
+ Indicates how instances should be updated.
- Note: This field will be removed in future version.
- properties:
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
rollingUpdate:
- description: RollingUpdate is used to communicate parameters when
- Type is RollingUpdateStatefulSetStrategyType.
+ description: Specifies how the rolling update should be applied.
properties:
maxUnavailable:
anyOf:
- type: integer
- type: string
description: |-
- The maximum number of pods that can be unavailable during the update.
- Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%).
+ The maximum number of instances that can be unavailable during the update.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
Absolute number is calculated from percentage by rounding up. This can not be 0.
- Defaults to 1. This field is alpha-level and is only honored by servers that enable the
- MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to
- Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it
- will be counted towards MaxUnavailable.
+ Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ it will be counted towards MaxUnavailable.
x-kubernetes-int-or-string: true
- partition:
+ replicas:
+ anyOf:
+ - type: integer
+ - type: string
description: |-
- Partition indicates the ordinal at which the StatefulSet should be partitioned
- for updates. During a rolling update, all pods from ordinal Replicas-1 to
- Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched.
- This is helpful in being able to do a canary based deployment. The default value is 0.
- format: int32
- type: integer
+ Indicates the number of instances that should be updated during a rolling update.
+ The remaining instances will remain untouched. This is helpful in defining how many instances
+ should participate in the update process.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up.
+ The default value is ComponentSpec.Replicas (i.e., update all instances).
+ x-kubernetes-int-or-string: true
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
+ default: Serial
+ description: "Specifies the concurrency level for updating
+ instances during a rolling update.\nAvailable levels:\n\n\n-
+ `Serial`: Updates instances one at a time, ensuring minimal
+ downtime by waiting for each instance to become ready\n
+ \ before updating the next.\n- `Parallel`: Updates all instances
+ simultaneously, optimizing for speed but potentially reducing
+ availability\n during the update.\n- `BestEffortParallel`:
+ Updates instances concurrently with a limit on simultaneous
+ updates to ensure a minimum\n number of operational replicas
+ for maintaining quorum.\n\t For example, in a 5-instances
+ setup, updating a maximum of 2 instances simultaneously
+ keeps\n\t at least 3 operational for quorum.\n\n\nDefaults
+ to 'Serial'."
+ type: string
type: object
- type:
- description: |-
- Type indicates the type of the StatefulSetUpdateStrategy.
- Default is RollingUpdate.
- type: string
type: object
volumeClaimTemplates:
description: |-
diff --git a/controllers/apps/componentdefinition_controller_test.go b/controllers/apps/componentdefinition_controller_test.go
index 66ae9938fa7..d4daa3085a6 100644
--- a/controllers/apps/componentdefinition_controller_test.go
+++ b/controllers/apps/componentdefinition_controller_test.go
@@ -473,7 +473,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
Image: "image:v0.0.1",
Command: []string{"command"},
}).
- SetUpdateStrategy(nil).
+ SetUpdateConcurrency(nil).
SetPodManagementPolicy(nil)
if processor != nil {
processor(builder)
@@ -523,7 +523,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
cmpd.Spec.Description = "v0.0.2"
cmpd.Spec.Runtime.Containers[0].Image = "image:v0.0.2"
parallel := kbappsv1.ParallelConcurrency
- cmpd.Spec.UpdateStrategyConstraint = ¶llel
+ cmpd.Spec.UpdateConcurrency = ¶llel
})()).Should(Succeed())
By(fmt.Sprintf("checking the updated object as %s", strings.ToLower(string(kbappsv1.AvailablePhase))))
@@ -538,8 +538,8 @@ var _ = Describe("ComponentDefinition Controller", func() {
Command: []string{"command"},
}
g.Expect(cmpd.Spec.Runtime.Containers[0]).Should(BeEquivalentTo(c))
- g.Expect(cmpd.Spec.UpdateStrategyConstraint).ShouldNot(BeNil())
- g.Expect(*cmpd.Spec.UpdateStrategyConstraint).Should(Equal(kbappsv1.ParallelConcurrency))
+ g.Expect(cmpd.Spec.UpdateConcurrency).ShouldNot(BeNil())
+ g.Expect(*cmpd.Spec.UpdateConcurrency).Should(Equal(kbappsv1.ParallelConcurrency))
})).Should(Succeed())
})
@@ -551,7 +551,7 @@ var _ = Describe("ComponentDefinition Controller", func() {
cmpd.Spec.Description = "v0.0.2"
cmpd.Spec.Runtime.Containers[0].Image = "image:v0.0.2"
parallel := kbappsv1.ParallelConcurrency
- cmpd.Spec.UpdateStrategyConstraint = ¶llel
+ cmpd.Spec.UpdateConcurrency = ¶llel
})()).Should(Succeed())
By(fmt.Sprintf("checking the updated object as %s", strings.ToLower(string(kbappsv1.UnavailablePhase))))
@@ -566,14 +566,14 @@ var _ = Describe("ComponentDefinition Controller", func() {
Command: []string{"command"},
}
g.Expect(cmpd.Spec.Runtime.Containers[0]).Should(BeEquivalentTo(c))
- g.Expect(cmpd.Spec.UpdateStrategyConstraint).ShouldNot(BeNil())
- g.Expect(*cmpd.Spec.UpdateStrategyConstraint).Should(Equal(kbappsv1.ParallelConcurrency))
+ g.Expect(cmpd.Spec.UpdateConcurrency).ShouldNot(BeNil())
+ g.Expect(*cmpd.Spec.UpdateConcurrency).Should(Equal(kbappsv1.ParallelConcurrency))
})).Should(Succeed())
By("revert the change to immutable fields back")
Expect(testapps.GetAndChangeObj(&testCtx, client.ObjectKeyFromObject(componentDefObj), func(cmpd *kbappsv1.ComponentDefinition) {
cmpd.Spec.Runtime.Containers[0].Image = "image:v0.0.1"
- cmpd.Spec.UpdateStrategyConstraint = nil
+ cmpd.Spec.UpdateConcurrency = nil
})()).Should(Succeed())
By(fmt.Sprintf("checking the updated object as %s", strings.ToLower(string(kbappsv1.AvailablePhase))))
@@ -588,8 +588,8 @@ var _ = Describe("ComponentDefinition Controller", func() {
Command: []string{"command"},
}
g.Expect(cmpd.Spec.Runtime.Containers[0]).Should(BeEquivalentTo(c))
- g.Expect(cmpd.Spec.UpdateStrategyConstraint).ShouldNot(BeNil())
- g.Expect(*cmpd.Spec.UpdateStrategyConstraint).Should(Equal(kbappsv1.SerialConcurrency))
+ g.Expect(cmpd.Spec.UpdateConcurrency).ShouldNot(BeNil())
+ g.Expect(*cmpd.Spec.UpdateConcurrency).Should(Equal(kbappsv1.SerialConcurrency))
})).Should(Succeed())
})
})
diff --git a/controllers/apps/transformer_cluster_component.go b/controllers/apps/transformer_cluster_component.go
index e359a43dde2..1a0cc8a57b5 100644
--- a/controllers/apps/transformer_cluster_component.go
+++ b/controllers/apps/transformer_cluster_component.go
@@ -200,7 +200,7 @@ func copyAndMergeComponent(oldCompObj, newCompObj *appsv1.Component) *appsv1.Com
compObjCopy.Spec.Configs = compProto.Spec.Configs
compObjCopy.Spec.ServiceAccountName = compProto.Spec.ServiceAccountName
compObjCopy.Spec.ParallelPodManagementConcurrency = compProto.Spec.ParallelPodManagementConcurrency
- compObjCopy.Spec.PodUpdatePolicy = compProto.Spec.PodUpdatePolicy
+ compObjCopy.Spec.UpdateStrategy = compProto.Spec.UpdateStrategy
compObjCopy.Spec.SchedulingPolicy = compProto.Spec.SchedulingPolicy
compObjCopy.Spec.TLSConfig = compProto.Spec.TLSConfig
compObjCopy.Spec.Instances = compProto.Spec.Instances
diff --git a/controllers/apps/transformer_component_workload.go b/controllers/apps/transformer_component_workload.go
index ea995677519..aac83613769 100644
--- a/controllers/apps/transformer_component_workload.go
+++ b/controllers/apps/transformer_component_workload.go
@@ -461,16 +461,15 @@ func copyAndMergeITS(oldITS, newITS *workloads.InstanceSet) *workloads.InstanceS
itsObjCopy.Spec.Roles = itsProto.Spec.Roles
itsObjCopy.Spec.RoleProbe = itsProto.Spec.RoleProbe
itsObjCopy.Spec.MembershipReconfiguration = itsProto.Spec.MembershipReconfiguration
- itsObjCopy.Spec.MemberUpdateStrategy = itsProto.Spec.MemberUpdateStrategy
itsObjCopy.Spec.Credential = itsProto.Spec.Credential
itsObjCopy.Spec.Instances = itsProto.Spec.Instances
itsObjCopy.Spec.OfflineInstances = itsProto.Spec.OfflineInstances
itsObjCopy.Spec.MinReadySeconds = itsProto.Spec.MinReadySeconds
itsObjCopy.Spec.VolumeClaimTemplates = itsProto.Spec.VolumeClaimTemplates
itsObjCopy.Spec.ParallelPodManagementConcurrency = itsProto.Spec.ParallelPodManagementConcurrency
- itsObjCopy.Spec.PodUpdatePolicy = itsProto.Spec.PodUpdatePolicy
+ itsObjCopy.Spec.UpdateStrategy = itsProto.Spec.UpdateStrategy
- if itsProto.Spec.UpdateStrategy.Type != "" || itsProto.Spec.UpdateStrategy.RollingUpdate != nil {
+ if itsProto.Spec.UpdateStrategy != nil || itsProto.Spec.UpdateStrategy.RollingUpdate != nil {
updateUpdateStrategy(itsObjCopy, itsProto)
}
diff --git a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml
index 2d4cc34c940..a8f51511f11 100644
--- a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml
+++ b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml
@@ -3783,20 +3783,6 @@ spec:
or when scaling down. It only used when `PodManagementPolicy` is set to `Parallel`.
The default Concurrency is 100%.
x-kubernetes-int-or-string: true
- podUpdatePolicy:
- description: |-
- PodUpdatePolicy indicates how pods should be updated
-
-
- - `StrictInPlace` indicates that only allows in-place upgrades.
- Any attempt to modify other fields will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- If that fails, it will fall back to the ReCreate, where pod will be recreated.
- Default value is "PreferInPlace"
- enum:
- - StrictInPlace
- - PreferInPlace
- type: string
replicas:
default: 1
description: Specifies the desired number of replicas in the
@@ -5352,6 +5338,79 @@ spec:
If TLS is enabled, the Component may require additional configuration, such as specifying TLS certificates and keys,
to properly set up the secure communication channel.
type: boolean
+ updateStrategy:
+ description: Provides fine-grained control over the spec update
+ process of all instances.
+ properties:
+ instanceUpdatePolicy:
+ description: |-
+ Indicates how instances should be updated.
+
+
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
+ rollingUpdate:
+ description: Specifies how the rolling update should be
+ applied.
+ properties:
+ maxUnavailable:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ The maximum number of instances that can be unavailable during the update.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up. This can not be 0.
+ Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ it will be counted towards MaxUnavailable.
+ x-kubernetes-int-or-string: true
+ replicas:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Indicates the number of instances that should be updated during a rolling update.
+ The remaining instances will remain untouched. This is helpful in defining how many instances
+ should participate in the update process.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up.
+ The default value is ComponentSpec.Replicas (i.e., update all instances).
+ x-kubernetes-int-or-string: true
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
+ default: Serial
+ description: "Specifies the concurrency level for updating
+ instances during a rolling update.\nAvailable levels:\n\n\n-
+ `Serial`: Updates instances one at a time, ensuring
+ minimal downtime by waiting for each instance to become
+ ready\n before updating the next.\n- `Parallel`:
+ Updates all instances simultaneously, optimizing for
+ speed but potentially reducing availability\n during
+ the update.\n- `BestEffortParallel`: Updates instances
+ concurrently with a limit on simultaneous updates
+ to ensure a minimum\n number of operational replicas
+ for maintaining quorum.\n\t For example, in a 5-instances
+ setup, updating a maximum of 2 instances simultaneously
+ keeps\n\t at least 3 operational for quorum.\n\n\nDefaults
+ to 'Serial'."
+ type: string
+ type: object
+ type: object
volumeClaimTemplates:
description: |-
Specifies a list of PersistentVolumeClaim templates that represent the storage requirements for the Component.
@@ -12473,20 +12532,6 @@ spec:
or when scaling down. It only used when `PodManagementPolicy` is set to `Parallel`.
The default Concurrency is 100%.
x-kubernetes-int-or-string: true
- podUpdatePolicy:
- description: |-
- PodUpdatePolicy indicates how pods should be updated
-
-
- - `StrictInPlace` indicates that only allows in-place upgrades.
- Any attempt to modify other fields will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- If that fails, it will fall back to the ReCreate, where pod will be recreated.
- Default value is "PreferInPlace"
- enum:
- - StrictInPlace
- - PreferInPlace
- type: string
replicas:
default: 1
description: Specifies the desired number of replicas in
@@ -14054,6 +14099,80 @@ spec:
If TLS is enabled, the Component may require additional configuration, such as specifying TLS certificates and keys,
to properly set up the secure communication channel.
type: boolean
+ updateStrategy:
+ description: Provides fine-grained control over the spec
+ update process of all instances.
+ properties:
+ instanceUpdatePolicy:
+ description: |-
+ Indicates how instances should be updated.
+
+
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
+ rollingUpdate:
+ description: Specifies how the rolling update should
+ be applied.
+ properties:
+ maxUnavailable:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ The maximum number of instances that can be unavailable during the update.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up. This can not be 0.
+ Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ it will be counted towards MaxUnavailable.
+ x-kubernetes-int-or-string: true
+ replicas:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Indicates the number of instances that should be updated during a rolling update.
+ The remaining instances will remain untouched. This is helpful in defining how many instances
+ should participate in the update process.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up.
+ The default value is ComponentSpec.Replicas (i.e., update all instances).
+ x-kubernetes-int-or-string: true
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
+ default: Serial
+ description: "Specifies the concurrency level for
+ updating instances during a rolling update.\nAvailable
+ levels:\n\n\n- `Serial`: Updates instances one
+ at a time, ensuring minimal downtime by waiting
+ for each instance to become ready\n before updating
+ the next.\n- `Parallel`: Updates all instances
+ simultaneously, optimizing for speed but potentially
+ reducing availability\n during the update.\n-
+ `BestEffortParallel`: Updates instances concurrently
+ with a limit on simultaneous updates to ensure
+ a minimum\n number of operational replicas for
+ maintaining quorum.\n\t For example, in a 5-instances
+ setup, updating a maximum of 2 instances simultaneously
+ keeps\n\t at least 3 operational for quorum.\n\n\nDefaults
+ to 'Serial'."
+ type: string
+ type: object
+ type: object
volumeClaimTemplates:
description: |-
Specifies a list of PersistentVolumeClaim templates that represent the storage requirements for the Component.
diff --git a/deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml b/deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml
index 636b9b48c8e..a592d737879 100644
--- a/deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml
+++ b/deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml
@@ -4489,6 +4489,20 @@ spec:
type: object
type: array
type: object
+ instanceUpdatePolicy:
+ description: |-
+ Specifies how an instance should be updated.
+
+
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
labels:
additionalProperties:
type: string
@@ -16847,24 +16861,28 @@ spec:
- mountPath
- volumeName
type: object
- updateStrategy:
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
default: Serial
- description: "Specifies the concurrency strategy for updating multiple
- instances of the Component.\nAvailable strategies:\n\n\n- `Serial`:
- Updates replicas one at a time, ensuring minimal downtime by waiting
- for each replica to become ready\n before updating the next.\n-
- `Parallel`: Updates all replicas simultaneously, optimizing for
- speed but potentially reducing availability\n during the update.\n-
- `BestEffortParallel`: Updates replicas concurrently with a limit
- on simultaneous updates to ensure a minimum\n number of operational
- replicas for maintaining quorum.\n\t For example, in a 5-replica
- component, updating a maximum of 2 replicas simultaneously keeps\n\t
- at least 3 operational for quorum.\n\n\nThis field is immutable
- and defaults to 'Serial'."
- enum:
- - Serial
- - BestEffortParallel
- - Parallel
+ description: "Specifies the concurrency level for updating instances
+ during a rolling update.\nAvailable levels:\n\n\n- `Serial`: Updates
+ instances one at a time, ensuring minimal downtime by waiting for
+ each instance to become ready\n before updating the next.\n- `Parallel`:
+ Updates all instances simultaneously, optimizing for speed but potentially
+ reducing availability\n during the update.\n- `BestEffortParallel`:
+ Updates instances concurrently with a limit on simultaneous updates
+ to ensure a minimum\n number of operational replicas for maintaining
+ quorum.\n\t For example, in a 5-instances setup, updating a maximum
+ of 2 instances simultaneously keeps\n\t at least 3 operational for
+ quorum.\n\n\nDefaults to 'Serial'."
type: string
vars:
description: |-
diff --git a/deploy/helm/crds/apps.kubeblocks.io_components.yaml b/deploy/helm/crds/apps.kubeblocks.io_components.yaml
index 9da4fd1e563..ca5f89dbec8 100644
--- a/deploy/helm/crds/apps.kubeblocks.io_components.yaml
+++ b/deploy/helm/crds/apps.kubeblocks.io_components.yaml
@@ -3562,17 +3562,6 @@ spec:
or when scaling down. It only used when `PodManagementPolicy` is set to `Parallel`.
The default Concurrency is 100%.
x-kubernetes-int-or-string: true
- podUpdatePolicy:
- description: |-
- PodUpdatePolicy indicates how pods should be updated
-
-
- - `StrictInPlace` indicates that only allows in-place upgrades.
- Any attempt to modify other fields will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- If that fails, it will fall back to the ReCreate, where pod will be recreated.
- Default value is "PreferInPlace"
- type: string
replicas:
default: 1
description: Specifies the desired number of replicas in the Component
@@ -5612,6 +5601,77 @@ spec:
- name
type: object
type: object
+ updateStrategy:
+ description: Provides fine-grained control over the spec update process
+ of all instances.
+ properties:
+ instanceUpdatePolicy:
+ description: |-
+ Indicates how instances should be updated.
+
+
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
+ rollingUpdate:
+ description: Specifies how the rolling update should be applied.
+ properties:
+ maxUnavailable:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ The maximum number of instances that can be unavailable during the update.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up. This can not be 0.
+ Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ it will be counted towards MaxUnavailable.
+ x-kubernetes-int-or-string: true
+ replicas:
+ anyOf:
+ - type: integer
+ - type: string
+ description: |-
+ Indicates the number of instances that should be updated during a rolling update.
+ The remaining instances will remain untouched. This is helpful in defining how many instances
+ should participate in the update process.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up.
+ The default value is ComponentSpec.Replicas (i.e., update all instances).
+ x-kubernetes-int-or-string: true
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
+ default: Serial
+ description: "Specifies the concurrency level for updating
+ instances during a rolling update.\nAvailable levels:\n\n\n-
+ `Serial`: Updates instances one at a time, ensuring minimal
+ downtime by waiting for each instance to become ready\n
+ \ before updating the next.\n- `Parallel`: Updates all instances
+ simultaneously, optimizing for speed but potentially reducing
+ availability\n during the update.\n- `BestEffortParallel`:
+ Updates instances concurrently with a limit on simultaneous
+ updates to ensure a minimum\n number of operational replicas
+ for maintaining quorum.\n\t For example, in a 5-instances
+ setup, updating a maximum of 2 instances simultaneously
+ keeps\n\t at least 3 operational for quorum.\n\n\nDefaults
+ to 'Serial'."
+ type: string
+ type: object
+ type: object
volumeClaimTemplates:
description: |-
Specifies a list of PersistentVolumeClaim templates that define the storage requirements for the Component.
diff --git a/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml b/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml
index 3da51ffb9f8..be1d243810e 100644
--- a/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml
+++ b/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml
@@ -3941,19 +3941,6 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
- memberUpdateStrategy:
- description: |-
- Members(Pods) update strategy.
-
-
- - serial: update Members one by one that guarantee minimum component unavailable time.
- - bestEffortParallel: update Members in parallel that guarantee minimum component un-writable time.
- - parallel: force parallel
- enum:
- - Serial
- - BestEffortParallel
- - Parallel
- type: string
membershipReconfiguration:
description: Provides actions to do membership dynamic reconfiguration.
properties:
@@ -4154,17 +4141,6 @@ spec:
Note: This field will be removed in future version.
type: string
- podUpdatePolicy:
- description: |-
- PodUpdatePolicy indicates how pods should be updated
-
-
- - `StrictInPlace` indicates that only allows in-place upgrades.
- Any attempt to modify other fields will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place upgrade of the Pod.
- If that fails, it will fall back to the ReCreate, where pod will be recreated.
- Default value is "PreferInPlace"
- type: string
replicas:
default: 1
description: |-
@@ -11843,46 +11819,75 @@ spec:
type: object
type: object
updateStrategy:
- description: |-
- Indicates the StatefulSetUpdateStrategy that will be
- employed to update Pods in the InstanceSet when a revision is made to
- Template.
- UpdateStrategy.Type will be set to appsv1.OnDeleteStatefulSetStrategyType if MemberUpdateStrategy is not nil
+ description: Provides fine-grained control over the spec update process
+ of all instances.
+ properties:
+ instanceUpdatePolicy:
+ description: |-
+ Indicates how instances should be updated.
- Note: This field will be removed in future version.
- properties:
+ - `StrictInPlace` indicates that only allows in-place update.
+ Any attempt to modify other fields that not support in-place update will be rejected.
+ - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
+ If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ Default value is "PreferInPlace".
+ enum:
+ - StrictInPlace
+ - PreferInPlace
+ type: string
rollingUpdate:
- description: RollingUpdate is used to communicate parameters when
- Type is RollingUpdateStatefulSetStrategyType.
+ description: Specifies how the rolling update should be applied.
properties:
maxUnavailable:
anyOf:
- type: integer
- type: string
description: |-
- The maximum number of pods that can be unavailable during the update.
- Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%).
+ The maximum number of instances that can be unavailable during the update.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
Absolute number is calculated from percentage by rounding up. This can not be 0.
- Defaults to 1. This field is alpha-level and is only honored by servers that enable the
- MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to
- Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it
- will be counted towards MaxUnavailable.
+ Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+ it will be counted towards MaxUnavailable.
x-kubernetes-int-or-string: true
- partition:
+ replicas:
+ anyOf:
+ - type: integer
+ - type: string
description: |-
- Partition indicates the ordinal at which the StatefulSet should be partitioned
- for updates. During a rolling update, all pods from ordinal Replicas-1 to
- Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched.
- This is helpful in being able to do a canary based deployment. The default value is 0.
- format: int32
- type: integer
+ Indicates the number of instances that should be updated during a rolling update.
+ The remaining instances will remain untouched. This is helpful in defining how many instances
+ should participate in the update process.
+ Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+ Absolute number is calculated from percentage by rounding up.
+ The default value is ComponentSpec.Replicas (i.e., update all instances).
+ x-kubernetes-int-or-string: true
+ updateConcurrency:
+ allOf:
+ - enum:
+ - Serial
+ - BestEffortParallel
+ - Parallel
+ - enum:
+ - Serial
+ - Parallel
+ - BestEffortParallel
+ default: Serial
+ description: "Specifies the concurrency level for updating
+ instances during a rolling update.\nAvailable levels:\n\n\n-
+ `Serial`: Updates instances one at a time, ensuring minimal
+ downtime by waiting for each instance to become ready\n
+ \ before updating the next.\n- `Parallel`: Updates all instances
+ simultaneously, optimizing for speed but potentially reducing
+ availability\n during the update.\n- `BestEffortParallel`:
+ Updates instances concurrently with a limit on simultaneous
+ updates to ensure a minimum\n number of operational replicas
+ for maintaining quorum.\n\t For example, in a 5-instances
+ setup, updating a maximum of 2 instances simultaneously
+ keeps\n\t at least 3 operational for quorum.\n\n\nDefaults
+ to 'Serial'."
+ type: string
type: object
- type:
- description: |-
- Type indicates the type of the StatefulSetUpdateStrategy.
- Default is RollingUpdate.
- type: string
type: object
volumeClaimTemplates:
description: |-
diff --git a/docs/developer_docs/api-reference/cluster.md b/docs/developer_docs/api-reference/cluster.md
index 97782c92516..d2406b92647 100644
--- a/docs/developer_docs/api-reference/cluster.md
+++ b/docs/developer_docs/api-reference/cluster.md
@@ -675,39 +675,32 @@ an existed ServiceAccount in this field.
-parallelPodManagementConcurrency
+updateStrategy
-
-Kubernetes api utils intstr.IntOrString
+
+UpdateStrategy
|
(Optional)
- Controls the concurrency of pods during initial scale up, when replacing pods on nodes,
-or when scaling down. It only used when PodManagementPolicy is set to Parallel .
-The default Concurrency is 100%.
+Provides fine-grained control over the spec update process of all instances.
|
-podUpdatePolicy
+parallelPodManagementConcurrency
-
-PodUpdatePolicyType
+
+Kubernetes api utils intstr.IntOrString
|
(Optional)
- PodUpdatePolicy indicates how pods should be updated
-
-StrictInPlace indicates that only allows in-place upgrades.
-Any attempt to modify other fields will be rejected.
-PreferInPlace indicates that we will first attempt an in-place upgrade of the Pod.
-If that fails, it will fall back to the ReCreate, where pod will be recreated.
-Default value is “PreferInPlace”
-
+Controls the concurrency of pods during initial scale up, when replacing pods on nodes,
+or when scaling down. It only used when PodManagementPolicy is set to Parallel .
+The default Concurrency is 100%.
|
@@ -1415,28 +1408,49 @@ This ensures the Pod’s stability and readiness to serve requests.
-updateStrategy
+instanceUpdatePolicy
-
-UpdateStrategy
+
+InstanceUpdatePolicyType
|
(Optional)
- Specifies the concurrency strategy for updating multiple instances of the Component.
-Available strategies:
+Specifies how an instance should be updated.
-Serial : Updates replicas one at a time, ensuring minimal downtime by waiting for each replica to become ready
+StrictInPlace indicates that only allows in-place update.
+Any attempt to modify other fields that not support in-place update will be rejected.
+PreferInPlace indicates that we will first attempt an in-place update of the instance.
+If that fails, it will fall back to the ReCreate, where instance will be recreated.
+Default value is “PreferInPlace”.
+
+ |
+
+
+
+updateConcurrency
+
+
+UpdateConcurrency
+
+
+ |
+
+(Optional)
+ Specifies the concurrency level for updating instances during a rolling update.
+Available levels:
+
+Serial : Updates instances one at a time, ensuring minimal downtime by waiting for each instance to become ready
before updating the next.
-Parallel : Updates all replicas simultaneously, optimizing for speed but potentially reducing availability
+Parallel : Updates all instances simultaneously, optimizing for speed but potentially reducing availability
during the update.
-BestEffortParallel : Updates replicas concurrently with a limit on simultaneous updates to ensure a minimum
+BestEffortParallel : Updates instances concurrently with a limit on simultaneous updates to ensure a minimum
number of operational replicas for maintaining quorum.
- For example, in a 5-replica component, updating a maximum of 2 replicas simultaneously keeps
+ For example, in a 5-instances setup, updating a maximum of 2 instances simultaneously keeps
at least 3 operational for quorum.
-This field is immutable and defaults to ‘Serial’.
+Defaults to ‘Serial’.
|
@@ -1927,8 +1941,8 @@ ShardsLimit
provisionStrategy
-
-UpdateStrategy
+
+UpdateConcurrency
|
@@ -1942,8 +1956,8 @@ UpdateStrategy
updateStrategy
-
-UpdateStrategy
+
+UpdateConcurrency
|
@@ -3020,23 +3034,16 @@ The default Concurrency is 100%.
-podUpdatePolicy
+updateStrategy
-
-PodUpdatePolicyType
+
+UpdateStrategy
|
(Optional)
- PodUpdatePolicy indicates how pods should be updated
-
-StrictInPlace indicates that only allows in-place upgrades.
-Any attempt to modify other fields will be rejected.
-PreferInPlace indicates that we will first attempt an in-place upgrade of the Pod.
-If that fails, it will fall back to the ReCreate, where pod will be recreated.
-Default value is “PreferInPlace”
-
+Provides fine-grained control over the spec update process of all instances.
|
@@ -5272,28 +5279,49 @@ This ensures the Pod’s stability and readiness to serve requests.
-updateStrategy
+instanceUpdatePolicy
-
-UpdateStrategy
+
+InstanceUpdatePolicyType
|
(Optional)
- Specifies the concurrency strategy for updating multiple instances of the Component.
-Available strategies:
+Specifies how an instance should be updated.
-Serial : Updates replicas one at a time, ensuring minimal downtime by waiting for each replica to become ready
+StrictInPlace indicates that only allows in-place update.
+Any attempt to modify other fields that not support in-place update will be rejected.
+PreferInPlace indicates that we will first attempt an in-place update of the instance.
+If that fails, it will fall back to the ReCreate, where instance will be recreated.
+Default value is “PreferInPlace”.
+
+ |
+
+
+
+updateConcurrency
+
+
+UpdateConcurrency
+
+
+ |
+
+(Optional)
+ Specifies the concurrency level for updating instances during a rolling update.
+Available levels:
+
+Serial : Updates instances one at a time, ensuring minimal downtime by waiting for each instance to become ready
before updating the next.
-Parallel : Updates all replicas simultaneously, optimizing for speed but potentially reducing availability
+Parallel : Updates all instances simultaneously, optimizing for speed but potentially reducing availability
during the update.
-BestEffortParallel : Updates replicas concurrently with a limit on simultaneous updates to ensure a minimum
+BestEffortParallel : Updates instances concurrently with a limit on simultaneous updates to ensure a minimum
number of operational replicas for maintaining quorum.
- For example, in a 5-replica component, updating a maximum of 2 replicas simultaneously keeps
+ For example, in a 5-instances setup, updating a maximum of 2 instances simultaneously keeps
at least 3 operational for quorum.
-This field is immutable and defaults to ‘Serial’.
+Defaults to ‘Serial’.
|
@@ -6158,39 +6186,32 @@ an existed ServiceAccount in this field.
-parallelPodManagementConcurrency
+updateStrategy
-
-Kubernetes api utils intstr.IntOrString
+
+UpdateStrategy
|
(Optional)
- Controls the concurrency of pods during initial scale up, when replacing pods on nodes,
-or when scaling down. It only used when PodManagementPolicy is set to Parallel .
-The default Concurrency is 100%.
+Provides fine-grained control over the spec update process of all instances.
|
-podUpdatePolicy
+parallelPodManagementConcurrency
-
-PodUpdatePolicyType
+
+Kubernetes api utils intstr.IntOrString
|
(Optional)
- PodUpdatePolicy indicates how pods should be updated
-
-StrictInPlace indicates that only allows in-place upgrades.
-Any attempt to modify other fields will be rejected.
-PreferInPlace indicates that we will first attempt an in-place upgrade of the Pod.
-If that fails, it will fall back to the ReCreate, where pod will be recreated.
-Default value is “PreferInPlace”
-
+Controls the concurrency of pods during initial scale up, when replacing pods on nodes,
+or when scaling down. It only used when PodManagementPolicy is set to Parallel .
+The default Concurrency is 100%.
|
@@ -7938,6 +7959,30 @@ Add new or override existing volume claim templates.
+InstanceUpdatePolicyType
+(string
alias)
+
+(Appears on:ComponentDefinitionSpec, UpdateStrategy)
+
+
+
+
+
+
+Value |
+Description |
+
+
+"PreferInPlace" |
+PreferInPlaceInstanceUpdatePolicyType indicates that we will first attempt an in-place update of the instance.
+If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ |
+
"StrictInPlace" |
+StrictInPlaceInstanceUpdatePolicyType indicates that only allows in-place update.
+Any attempt to modify other fields that not support in-place update will be rejected.
+ |
+
+
Issuer
@@ -8559,30 +8604,6 @@ Kubernetes core/v1.PersistentVolumeMode
-
PodUpdatePolicyType
-(string
alias)
-
-(Appears on:ClusterComponentSpec, ComponentSpec)
-
-
-
-
-
-
-Value |
-Description |
-
-
-"PreferInPlace" |
-PreferInPlacePodUpdatePolicyType indicates that we will first attempt an in-place upgrade of the Pod.
-If that fails, it will fall back to the ReCreate, where pod will be recreated.
- |
-
"StrictInPlace" |
-StrictInPlacePodUpdatePolicyType indicates that only allows in-place upgrades.
-Any attempt to modify other fields will be rejected.
- |
-
-
PreConditionType
(string
alias)
@@ -8971,6 +8992,87 @@ VarOption
+
RollingUpdate
+
+
+(Appears on:UpdateStrategy)
+
+
+
RollingUpdate specifies how the rolling update should be applied.
+
+
+
+
+Field |
+Description |
+
+
+
+
+
+replicas
+
+
+Kubernetes api utils intstr.IntOrString
+
+
+ |
+
+(Optional)
+ Indicates the number of instances that should be updated during a rolling update.
+The remaining instances will remain untouched. This is helpful in defining how many instances
+should participate in the update process.
+Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+Absolute number is calculated from percentage by rounding up.
+The default value is ComponentSpec.Replicas (i.e., update all instances).
+ |
+
+
+
+updateConcurrency
+
+
+UpdateConcurrency
+
+
+ |
+
+(Optional)
+ Specifies the concurrency level for updating instances during a rolling update.
+Available levels:
+
+Serial : Updates instances one at a time, ensuring minimal downtime by waiting for each instance to become ready
+before updating the next.
+Parallel : Updates all instances simultaneously, optimizing for speed but potentially reducing availability
+during the update.
+BestEffortParallel : Updates instances concurrently with a limit on simultaneous updates to ensure a minimum
+number of operational replicas for maintaining quorum.
+ For example, in a 5-instances setup, updating a maximum of 2 instances simultaneously keeps
+at least 3 operational for quorum.
+
+Defaults to ‘Serial’.
+ |
+
+
+
+maxUnavailable
+
+
+Kubernetes api utils intstr.IntOrString
+
+
+ |
+
+(Optional)
+ The maximum number of instances that can be unavailable during the update.
+Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+Absolute number is calculated from percentage by rounding up. This can not be 0.
+Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+it will be counted towards MaxUnavailable.
+ |
+
+
+
SchedulingPolicy
@@ -10488,8 +10590,8 @@ ShardsLimit
provisionStrategy
-
-UpdateStrategy
+
+UpdateConcurrency
|
@@ -10503,8 +10605,8 @@ UpdateStrategy
updateStrategy
-
-UpdateStrategy
+
+UpdateConcurrency
|
@@ -11522,15 +11624,15 @@ VarOption
-UpdateStrategy
+UpdateConcurrency
(string
alias)
-(Appears on:ComponentDefinitionSpec, ShardingDefinitionSpec)
+(Appears on:ComponentDefinitionSpec, RollingUpdate, ShardingDefinitionSpec)
-
UpdateStrategy defines the update strategy for cluster components. This strategy determines how updates are applied
+
UpdateConcurrency defines the update concurrency level for cluster components. This concurrency level determines how updates are applied
across the cluster.
-The available strategies are Serial
, BestEffortParallel
, and Parallel
.
+The available concurrency levels are
Serial
,
BestEffortParallel
, and
Parallel
.
@@ -11540,7 +11642,7 @@ The available strategies are Serial
, BestEffortParallel
"BestEffortParallel" |
-BestEffortParallelStrategy indicates that the replicas are updated in parallel, with the operator making
+ | BestEffortParallelConcurrency indicates that the replicas are updated in parallel, with the operator making
a best-effort attempt to update as many replicas as possible concurrently
while maintaining the component’s availability.
Unlike the Parallel strategy, the BestEffortParallel strategy aims to ensure that a minimum number
@@ -11551,33 +11653,25 @@ the operator may allow a maximum of 2 replicas to be simultaneously updated. Thi
The BestEffortParallel strategy strikes a balance between update speed and component availability.
|
"Parallel" |
-ParallelStrategy indicates that updates are applied simultaneously to all Pods of a Component.
+ | ParallelConcurrency indicates that updates are applied simultaneously to all Pods of a Component.
The replicas are updated in parallel, with the operator updating all replicas concurrently.
This strategy provides the fastest update time but may lead to a period of reduced availability or
capacity during the update process.
|
"Serial" |
-SerialStrategy indicates that updates are applied one at a time in a sequential manner.
+ | SerialConcurrency indicates that updates are applied one at a time in a sequential manner.
The operator waits for each replica to be updated and ready before proceeding to the next one.
This ensures that only one replica is unavailable at a time during the update process.
|
-VarOption
-(string
alias)
-
-(Appears on:ClusterVars, ComponentVars, CredentialVars, NamedVar, RoledVar, ServiceRefVars, ServiceVars, TLSVars)
-
-
-
VarOption defines whether a variable is required or optional.
-
-VarSource
+UpdateStrategy
-(Appears on:EnvVar)
+(Appears on:ClusterComponentSpec, ComponentSpec)
-
VarSource represents a source for the value of an EnvVar.
+
UpdateStrategy defines fine-grained control over the spec update process of all instances.
@@ -11589,44 +11683,105 @@ This ensures that only one replica is unavailable at a time during the update pr
-configMapKeyRef
+instanceUpdatePolicy
-
-Kubernetes core/v1.ConfigMapKeySelector
+
+InstanceUpdatePolicyType
|
(Optional)
- Selects a key of a ConfigMap.
+Indicates how instances should be updated.
+
+StrictInPlace indicates that only allows in-place update.
+Any attempt to modify other fields that not support in-place update will be rejected.
+PreferInPlace indicates that we will first attempt an in-place update of the instance.
+If that fails, it will fall back to the ReCreate, where instance will be recreated.
+Default value is “PreferInPlace”.
+
|
-secretKeyRef
+rollingUpdate
-
-Kubernetes core/v1.SecretKeySelector
+
+RollingUpdate
|
(Optional)
- Selects a key of a Secret.
+Specifies how the rolling update should be applied.
|
-
-
-hostNetworkVarRef
-
-
-HostNetworkVarSelector
-
-
- |
-
-(Optional)
- Selects a defined var of host-network resources.
+ |
+
+VarOption
+(string
alias)
+
+(Appears on:ClusterVars, ComponentVars, CredentialVars, NamedVar, RoledVar, ServiceRefVars, ServiceVars, TLSVars)
+
+
+
VarOption defines whether a variable is required or optional.
+
+VarSource
+
+
+(Appears on:EnvVar)
+
+
+
VarSource represents a source for the value of an EnvVar.
+
+
+
+
+Field |
+Description |
+
+
+
+
+
+configMapKeyRef
+
+
+Kubernetes core/v1.ConfigMapKeySelector
+
+
+ |
+
+(Optional)
+ Selects a key of a ConfigMap.
+ |
+
+
+
+secretKeyRef
+
+
+Kubernetes core/v1.SecretKeySelector
+
+
+ |
+
+(Optional)
+ Selects a key of a Secret.
+ |
+
+
+
+hostNetworkVarRef
+
+
+HostNetworkVarSelector
+
+
+ |
+
+(Optional)
+ Selects a defined var of host-network resources.
|
@@ -28953,40 +29108,16 @@ The default Concurrency is 100%.
-podUpdatePolicy
-
-
-PodUpdatePolicyType
-
-
- |
-
-(Optional)
- PodUpdatePolicy indicates how pods should be updated
-
-StrictInPlace indicates that only allows in-place upgrades.
-Any attempt to modify other fields will be rejected.
-PreferInPlace indicates that we will first attempt an in-place upgrade of the Pod.
-If that fails, it will fall back to the ReCreate, where pod will be recreated.
-Default value is “PreferInPlace”
-
- |
-
-
-
updateStrategy
-
-Kubernetes apps/v1.StatefulSetUpdateStrategy
+
+UpdateStrategy
|
- Indicates the StatefulSetUpdateStrategy that will be
-employed to update Pods in the InstanceSet when a revision is made to
-Template.
-UpdateStrategy.Type will be set to appsv1.OnDeleteStatefulSetStrategyType if MemberUpdateStrategy is not nil
-Note: This field will be removed in future version.
+(Optional)
+Provides fine-grained control over the spec update process of all instances.
|
@@ -29033,25 +29164,6 @@ MembershipReconfiguration
-memberUpdateStrategy
-
-
-MemberUpdateStrategy
-
-
- |
-
-(Optional)
- Members(Pods) update strategy.
-
-- serial: update Members one by one that guarantee minimum component unavailable time.
-- bestEffortParallel: update Members in parallel that guarantee minimum component un-writable time.
-- parallel: force parallel
-
- |
-
-
-
paused
bool
@@ -29484,40 +29596,16 @@ The default Concurrency is 100%.
|
-podUpdatePolicy
-
-
-PodUpdatePolicyType
-
-
- |
-
-(Optional)
- PodUpdatePolicy indicates how pods should be updated
-
-StrictInPlace indicates that only allows in-place upgrades.
-Any attempt to modify other fields will be rejected.
-PreferInPlace indicates that we will first attempt an in-place upgrade of the Pod.
-If that fails, it will fall back to the ReCreate, where pod will be recreated.
-Default value is “PreferInPlace”
-
- |
-
-
-
updateStrategy
-
-Kubernetes apps/v1.StatefulSetUpdateStrategy
+
+UpdateStrategy
|
- Indicates the StatefulSetUpdateStrategy that will be
-employed to update Pods in the InstanceSet when a revision is made to
-Template.
-UpdateStrategy.Type will be set to appsv1.OnDeleteStatefulSetStrategyType if MemberUpdateStrategy is not nil
-Note: This field will be removed in future version.
+(Optional)
+Provides fine-grained control over the spec update process of all instances.
|
@@ -29564,25 +29652,6 @@ MembershipReconfiguration
-memberUpdateStrategy
-
-
-MemberUpdateStrategy
-
-
- |
-
-(Optional)
- Members(Pods) update strategy.
-
-- serial: update Members one by one that guarantee minimum component unavailable time.
-- bestEffortParallel: update Members in parallel that guarantee minimum component un-writable time.
-- parallel: force parallel
-
- |
-
-
-
paused
bool
@@ -30116,6 +30185,30 @@ indicated by UpdateRevisions.
|
+InstanceUpdatePolicyType
+(string
alias)
+
+(Appears on:UpdateStrategy)
+
+
+
+
+
+
+Value |
+Description |
+
+
+"PreferInPlace" |
+PreferInPlaceInstanceUpdatePolicyType indicates that we will first attempt an in-place update of the instance.
+If that fails, it will fall back to the ReCreate, where instance will be recreated.
+ |
+
"StrictInPlace" |
+StrictInPlaceInstanceUpdatePolicyType indicates that only allows in-place update.
+Any attempt to modify other fields that not support in-place update will be rejected.
+ |
+
+
MemberStatus
@@ -30158,29 +30251,6 @@ ReplicaRole
-
MemberUpdateStrategy
-(string
alias)
-
-(Appears on:InstanceSetSpec)
-
-
-
MemberUpdateStrategy defines Cluster Component update strategy.
-
-
-
-
-Value |
-Description |
-
-
-"BestEffortParallel" |
- |
-
"Parallel" |
- |
-
"Serial" |
- |
-
-
MembershipReconfiguration
@@ -30319,30 +30389,6 @@ If the Image is not configured, the Image from the previous non-nil action will
-
PodUpdatePolicyType
-(string
alias)
-
-(Appears on:InstanceSetSpec)
-
-
-
-
-
-
-Value |
-Description |
-
-
-"PreferInPlace" |
-PreferInPlacePodUpdatePolicyType indicates that we will first attempt an in-place upgrade of the Pod.
-If that fails, it will fall back to the ReCreate, where pod will be recreated.
- |
-
"StrictInPlace" |
-StrictInPlacePodUpdatePolicyType indicates that only allows in-place upgrades.
-Any attempt to modify other fields will be rejected.
- |
-
-
Range
@@ -30581,6 +30627,87 @@ RoleUpdateMechanism
|
+RollingUpdate
+
+
+(Appears on:UpdateStrategy)
+
+
+
RollingUpdate specifies how the rolling update should be applied.
+
+
+
+
+Field |
+Description |
+
+
+
+
+
+replicas
+
+
+Kubernetes api utils intstr.IntOrString
+
+
+ |
+
+(Optional)
+ Indicates the number of instances that should be updated during a rolling update.
+The remaining instances will remain untouched. This is helpful in defining how many instances
+should participate in the update process.
+Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+Absolute number is calculated from percentage by rounding up.
+The default value is ComponentSpec.Replicas (i.e., update all instances).
+ |
+
+
+
+updateConcurrency
+
+
+UpdateConcurrency
+
+
+ |
+
+(Optional)
+ Specifies the concurrency level for updating instances during a rolling update.
+Available levels:
+
+Serial : Updates instances one at a time, ensuring minimal downtime by waiting for each instance to become ready
+before updating the next.
+Parallel : Updates all instances simultaneously, optimizing for speed but potentially reducing availability
+during the update.
+BestEffortParallel : Updates instances concurrently with a limit on simultaneous updates to ensure a minimum
+number of operational replicas for maintaining quorum.
+ For example, in a 5-instances setup, updating a maximum of 2 instances simultaneously keeps
+at least 3 operational for quorum.
+
+Defaults to ‘Serial’.
+ |
+
+
+
+maxUnavailable
+
+
+Kubernetes api utils intstr.IntOrString
+
+
+ |
+
+(Optional)
+ The maximum number of instances that can be unavailable during the update.
+Value can be an absolute number (ex: 5) or a percentage of desired instances (ex: 10%).
+Absolute number is calculated from percentage by rounding up. This can not be 0.
+Defaults to 1. The field applies to all instances. That means if there is any unavailable pod,
+it will be counted towards MaxUnavailable.
+ |
+
+
+
SchedulingPolicy
@@ -30692,6 +30819,100 @@ All topologySpreadConstraints are ANDed.
+UpdateConcurrency
+(string
alias)
+
+(Appears on:RollingUpdate)
+
+
+
UpdateConcurrency defines the update concurrency level for cluster components. This concurrency level determines how updates are applied
+across the cluster.
+The available concurrency levels are Serial
, BestEffortParallel
, and Parallel
.
+
+
+
+
+Value |
+Description |
+
+
+"BestEffortParallel" |
+BestEffortParallelConcurrency indicates that the replicas are updated in parallel, with the operator making
+a best-effort attempt to update as many replicas as possible concurrently
+while maintaining the component’s availability.
+Unlike the Parallel strategy, the BestEffortParallel strategy aims to ensure that a minimum number
+of replicas remain available during the update process to maintain the component’s quorum and functionality.
+For example, consider a component with 5 replicas. To maintain the component’s availability and quorum,
+the operator may allow a maximum of 2 replicas to be simultaneously updated. This ensures that at least
+3 replicas (a quorum) remain available and functional during the update process.
+The BestEffortParallel strategy strikes a balance between update speed and component availability.
+ |
+
"Parallel" |
+ParallelConcurrency indicates that updates are applied simultaneously to all Pods of a Component.
+The replicas are updated in parallel, with the operator updating all replicas concurrently.
+This strategy provides the fastest update time but may lead to a period of reduced availability or
+capacity during the update process.
+ |
+
"Serial" |
+SerialConcurrency indicates that updates are applied one at a time in a sequential manner.
+The operator waits for each replica to be updated and ready before proceeding to the next one.
+This ensures that only one replica is unavailable at a time during the update process.
+ |
+
+
+UpdateStrategy
+
+
+(Appears on:InstanceSetSpec)
+
+
+
UpdateStrategy defines fine-grained control over the spec update process of all instances.
+
+
+
+
+Field |
+Description |
+
+
+
+
+
+instanceUpdatePolicy
+
+
+InstanceUpdatePolicyType
+
+
+ |
+
+(Optional)
+ Indicates how instances should be updated.
+
+StrictInPlace indicates that only allows in-place update.
+Any attempt to modify other fields that not support in-place update will be rejected.
+PreferInPlace indicates that we will first attempt an in-place update of the instance.
+If that fails, it will fall back to the ReCreate, where instance will be recreated.
+Default value is “PreferInPlace”.
+
+ |
+
+
+
+rollingUpdate
+
+
+RollingUpdate
+
+
+ |
+
+(Optional)
+ Specifies how the rolling update should be applied.
+ |
+
+
+
workloads.kubeblocks.io/v1alpha1
diff --git a/pkg/controller/builder/builder_component.go b/pkg/controller/builder/builder_component.go
index 5d8ae199a05..e58b3e09760 100644
--- a/pkg/controller/builder/builder_component.go
+++ b/pkg/controller/builder/builder_component.go
@@ -86,8 +86,8 @@ func (builder *ComponentBuilder) SetParallelPodManagementConcurrency(parallelPod
return builder
}
-func (builder *ComponentBuilder) SetPodUpdatePolicy(policy *appsv1.InstanceUpdatePolicyType) *ComponentBuilder {
- builder.get().Spec.PodUpdatePolicy = policy
+func (builder *ComponentBuilder) SetUpdateStrategy(strategy *appsv1.UpdateStrategy) *ComponentBuilder {
+ builder.get().Spec.UpdateStrategy = strategy
return builder
}
diff --git a/pkg/controller/builder/builder_component_definition.go b/pkg/controller/builder/builder_component_definition.go
index d1aaa6eff5a..e873b6fe58b 100644
--- a/pkg/controller/builder/builder_component_definition.go
+++ b/pkg/controller/builder/builder_component_definition.go
@@ -205,8 +205,8 @@ func (builder *ComponentDefinitionBuilder) AddSystemAccount(accountName string,
return builder
}
-func (builder *ComponentDefinitionBuilder) SetUpdateStrategy(strategy *appsv1.UpdateConcurrency) *ComponentDefinitionBuilder {
- builder.get().Spec.UpdateStrategyConstraint = strategy
+func (builder *ComponentDefinitionBuilder) SetUpdateConcurrency(concurrency *appsv1.UpdateConcurrency) *ComponentDefinitionBuilder {
+ builder.get().Spec.UpdateConcurrency = concurrency
return builder
}
diff --git a/pkg/controller/builder/builder_instance_set.go b/pkg/controller/builder/builder_instance_set.go
index 39f9d71ffaa..3480ddde455 100644
--- a/pkg/controller/builder/builder_instance_set.go
+++ b/pkg/controller/builder/builder_instance_set.go
@@ -113,21 +113,11 @@ func (builder *InstanceSetBuilder) SetParallelPodManagementConcurrency(parallelP
return builder
}
-func (builder *InstanceSetBuilder) SetPodUpdatePolicy(policy workloads.PodUpdatePolicyType) *InstanceSetBuilder {
- builder.get().Spec.PodUpdatePolicy = policy
- return builder
-}
-
-func (builder *InstanceSetBuilder) SetUpdateStrategy(strategy apps.StatefulSetUpdateStrategy) *InstanceSetBuilder {
+func (builder *InstanceSetBuilder) SetUpdateStrategy(strategy *workloads.UpdateStrategy) *InstanceSetBuilder {
builder.get().Spec.UpdateStrategy = strategy
return builder
}
-func (builder *InstanceSetBuilder) SetUpdateStrategyType(strategyType apps.StatefulSetUpdateStrategyType) *InstanceSetBuilder {
- builder.get().Spec.UpdateStrategy.Type = strategyType
- return builder
-}
-
func (builder *InstanceSetBuilder) SetCustomHandler(handler []workloads.Action) *InstanceSetBuilder {
roleProbe := builder.get().Spec.RoleProbe
if roleProbe == nil {
@@ -160,14 +150,6 @@ func (builder *InstanceSetBuilder) SetMembershipReconfiguration(reconfiguration
return builder
}
-func (builder *InstanceSetBuilder) SetMemberUpdateStrategy(strategy *workloads.MemberUpdateStrategy) *InstanceSetBuilder {
- builder.get().Spec.MemberUpdateStrategy = strategy
- if strategy != nil {
- builder.SetUpdateStrategyType(apps.OnDeleteStatefulSetStrategyType)
- }
- return builder
-}
-
func (builder *InstanceSetBuilder) SetPaused(paused bool) *InstanceSetBuilder {
builder.get().Spec.Paused = paused
return builder
diff --git a/pkg/controller/builder/builder_instance_set_test.go b/pkg/controller/builder/builder_instance_set_test.go
index fd4a3dcabcc..b8066a348d0 100644
--- a/pkg/controller/builder/builder_instance_set_test.go
+++ b/pkg/controller/builder/builder_instance_set_test.go
@@ -45,7 +45,7 @@ var _ = Describe("instance_set builder", func() {
minReadySeconds = int32(11)
port = int32(12345)
policy = apps.OrderedReadyPodManagement
- podUpdatePolicy = workloads.PreferInPlacePodUpdatePolicyType
+ instanceUpdatePolicy = workloads.PreferInPlaceInstanceUpdatePolicyType
)
parallelPodManagementConcurrency := &intstr.IntOrString{Type: intstr.String, StrVal: "100%"}
selectors := map[string]string{selectorKey4: selectorValue4}
@@ -107,15 +107,17 @@ var _ = Describe("instance_set builder", func() {
},
},
}
- partition, maxUnavailable := int32(3), intstr.FromInt(2)
- strategy := apps.StatefulSetUpdateStrategy{
- Type: apps.RollingUpdateStatefulSetStrategyType,
- RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{
- Partition: &partition,
- MaxUnavailable: &maxUnavailable,
+ itUpdatePolicy := workloads.PreferInPlaceInstanceUpdatePolicyType
+ updateReplicas, maxUnavailable := intstr.FromInt32(3), intstr.FromInt32(2)
+ updateConcurrency := workloads.BestEffortParallelConcurrency
+ strategy := workloads.UpdateStrategy{
+ InstanceUpdatePolicy: &itUpdatePolicy,
+ RollingUpdate: &workloads.RollingUpdate{
+ Replicas: &updateReplicas,
+ MaxUnavailable: &maxUnavailable,
+ UpdateConcurrency: &updateConcurrency,
},
}
- strategyType := apps.OnDeleteStatefulSetStrategyType
delay := int32(10)
roleProbe := workloads.RoleProbe{InitialDelaySeconds: delay}
actions := []workloads.Action{
@@ -128,7 +130,6 @@ var _ = Describe("instance_set builder", func() {
Image: "foo-2",
Command: []string{"bar-2"},
}
- memberUpdateStrategy := workloads.BestEffortParallelUpdateStrategy
paused := true
credential := workloads.Credential{
Username: workloads.CredentialVar{Value: "foo"},
@@ -157,13 +158,10 @@ var _ = Describe("instance_set builder", func() {
AddVolumeClaimTemplates(vc).
SetPodManagementPolicy(policy).
SetParallelPodManagementConcurrency(parallelPodManagementConcurrency).
- SetPodUpdatePolicy(podUpdatePolicy).
- SetUpdateStrategy(strategy).
- SetUpdateStrategyType(strategyType).
+ SetUpdateStrategy(&strategy).
SetRoleProbe(&roleProbe).
SetCustomHandler(actions).
AddCustomHandler(action).
- SetMemberUpdateStrategy(&memberUpdateStrategy).
SetPaused(paused).
SetCredential(credential).
SetInstances(instances).
@@ -189,20 +187,21 @@ var _ = Describe("instance_set builder", func() {
Expect(its.Spec.VolumeClaimTemplates[1]).Should(Equal(vc))
Expect(its.Spec.PodManagementPolicy).Should(Equal(policy))
Expect(its.Spec.ParallelPodManagementConcurrency).Should(Equal(parallelPodManagementConcurrency))
- Expect(its.Spec.PodUpdatePolicy).Should(Equal(podUpdatePolicy))
- Expect(its.Spec.UpdateStrategy.Type).Should(Equal(strategyType))
+ Expect(its.Spec.UpdateStrategy).ShouldNot(BeNil())
+ Expect(its.Spec.UpdateStrategy.InstanceUpdatePolicy).ShouldNot(BeNil())
+ Expect(*its.Spec.UpdateStrategy.InstanceUpdatePolicy).Should(Equal(instanceUpdatePolicy))
Expect(its.Spec.UpdateStrategy.RollingUpdate).ShouldNot(BeNil())
- Expect(its.Spec.UpdateStrategy.RollingUpdate.Partition).ShouldNot(BeNil())
- Expect(*its.Spec.UpdateStrategy.RollingUpdate.Partition).Should(Equal(partition))
+ Expect(its.Spec.UpdateStrategy.RollingUpdate.Replicas).ShouldNot(BeNil())
+ Expect(*its.Spec.UpdateStrategy.RollingUpdate.Replicas).Should(Equal(updateReplicas))
Expect(its.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable).ShouldNot(BeNil())
- Expect(its.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable).ShouldNot(Equal(maxUnavailable))
+ Expect(*its.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable).Should(Equal(maxUnavailable))
+ Expect(its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency).ShouldNot(BeNil())
+ Expect(*its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency).Should(Equal(updateConcurrency))
Expect(its.Spec.RoleProbe).ShouldNot(BeNil())
Expect(its.Spec.RoleProbe.InitialDelaySeconds).Should(Equal(delay))
Expect(its.Spec.RoleProbe.CustomHandler).Should(HaveLen(2))
Expect(its.Spec.RoleProbe.CustomHandler[0]).Should(Equal(actions[0]))
Expect(its.Spec.RoleProbe.CustomHandler[1]).Should(Equal(action))
- Expect(its.Spec.MemberUpdateStrategy).ShouldNot(BeNil())
- Expect(*its.Spec.MemberUpdateStrategy).Should(Equal(memberUpdateStrategy))
Expect(its.Spec.Paused).Should(Equal(paused))
Expect(its.Spec.Credential).ShouldNot(BeNil())
Expect(*its.Spec.Credential).Should(Equal(credential))
diff --git a/pkg/controller/component/component.go b/pkg/controller/component/component.go
index 9678d516481..ea2a59fe451 100644
--- a/pkg/controller/component/component.go
+++ b/pkg/controller/component/component.go
@@ -77,7 +77,7 @@ func BuildComponent(cluster *appsv1.Cluster, compSpec *appsv1.ClusterComponentSp
SetResources(compSpec.Resources).
SetServiceAccountName(compSpec.ServiceAccountName).
SetParallelPodManagementConcurrency(compSpec.ParallelPodManagementConcurrency).
- SetPodUpdatePolicy(compSpec.PodUpdatePolicy).
+ SetUpdateStrategy(compSpec.UpdateStrategy).
SetVolumeClaimTemplates(compSpec.VolumeClaimTemplates).
SetVolumes(compSpec.Volumes).
SetServices(compSpec.Services).
diff --git a/pkg/controller/component/its_convertor.go b/pkg/controller/component/its_convertor.go
index 3d51af61c54..3b9bf069064 100644
--- a/pkg/controller/component/its_convertor.go
+++ b/pkg/controller/component/its_convertor.go
@@ -48,10 +48,8 @@ func BuildWorkloadFrom(synthesizeComp *SynthesizedComponent, protoITS *workloads
"roleprobe": &itsRoleProbeConvertor{},
"credential": &itsCredentialConvertor{},
"membershipreconfiguration": &itsMembershipReconfigurationConvertor{},
- "memberupdatestrategy": &itsMemberUpdateStrategyConvertor{},
"podmanagementpolicy": &itsPodManagementPolicyConvertor{},
"parallelpodmanagementconcurrency": &itsParallelPodManagementConcurrencyConvertor{},
- "podupdatepolicy": &itsPodUpdatePolicyConvertor{},
"updatestrategy": &itsUpdateStrategyConvertor{},
"instances": &itsInstancesConvertor{},
"offlineinstances": &itsOfflineInstancesConvertor{},
@@ -80,17 +78,6 @@ type itsCredentialConvertor struct{}
// itsMembershipReconfigurationConvertor is an implementation of the convertor interface, used to convert the given object into InstanceSet.Spec.MembershipReconfiguration.
type itsMembershipReconfigurationConvertor struct{}
-// itsMemberUpdateStrategyConvertor is an implementation of the convertor interface, used to convert the given object into InstanceSet.Spec.MemberUpdateStrategy.
-type itsMemberUpdateStrategyConvertor struct{}
-
-func (c *itsMemberUpdateStrategyConvertor) convert(args ...any) (any, error) {
- synthesizeComp, err := parseITSConvertorArgs(args...)
- if err != nil {
- return nil, err
- }
- return getMemberUpdateStrategy(synthesizeComp), nil
-}
-
// itsPodManagementPolicyConvertor is an implementation of the convertor interface, used to convert the given object into InstanceSet.Spec.PodManagementPolicy.
type itsPodManagementPolicyConvertor struct{}
@@ -102,11 +89,7 @@ func (c *itsPodManagementPolicyConvertor) convert(args ...any) (any, error) {
if synthesizedComp.PodManagementPolicy != nil {
return *synthesizedComp.PodManagementPolicy, nil
}
- memberUpdateStrategy := getMemberUpdateStrategy(synthesizedComp)
- if memberUpdateStrategy == nil || *memberUpdateStrategy == workloads.SerialUpdateStrategy {
- return appsv1.OrderedReadyPodManagement, nil
- }
- return appsv1.ParallelPodManagement, nil
+ return appsv1.OrderedReadyPodManagement, nil
}
// itsParallelPodManagementConcurrencyConvertor is an implementation of the convertor interface, used to convert the given object into InstanceSet.Spec.ParallelPodManagementConcurrency.
@@ -123,20 +106,6 @@ func (c *itsParallelPodManagementConcurrencyConvertor) convert(args ...any) (any
return &intstr.IntOrString{Type: intstr.String, StrVal: "100%"}, nil
}
-// itsPodUpdatePolicyConvertor is an implementation of the convertor interface, used to convert the given object into InstanceSet.Spec.PodUpdatePolicy.
-type itsPodUpdatePolicyConvertor struct{}
-
-func (c *itsPodUpdatePolicyConvertor) convert(args ...any) (any, error) {
- synthesizedComp, err := parseITSConvertorArgs(args...)
- if err != nil {
- return nil, err
- }
- if synthesizedComp.PodUpdatePolicy != nil {
- return *synthesizedComp.PodUpdatePolicy, nil
- }
- return workloads.PreferInPlacePodUpdatePolicyType, nil
-}
-
// itsUpdateStrategyConvertor is an implementation of the convertor interface, used to convert the given object into InstanceSet.Spec.Instances.
type itsUpdateStrategyConvertor struct{}
@@ -145,11 +114,20 @@ func (c *itsUpdateStrategyConvertor) convert(args ...any) (any, error) {
if err != nil {
return nil, err
}
- if getMemberUpdateStrategy(synthesizedComp) != nil {
- // appsv1.OnDeleteStatefulSetStrategyType is the default value if member update strategy is set.
- return appsv1.StatefulSetUpdateStrategy{}, nil
+ var updateStrategy *workloads.UpdateStrategy
+ if synthesizedComp.UpdateStrategy != nil {
+ updateStrategy = &workloads.UpdateStrategy{
+ InstanceUpdatePolicy: (*workloads.InstanceUpdatePolicyType)(synthesizedComp.UpdateStrategy.InstanceUpdatePolicy),
+ }
+ if synthesizedComp.UpdateStrategy.RollingUpdate != nil {
+ updateStrategy.RollingUpdate = &workloads.RollingUpdate{
+ Replicas: synthesizedComp.UpdateStrategy.RollingUpdate.Replicas,
+ MaxUnavailable: synthesizedComp.UpdateStrategy.RollingUpdate.MaxUnavailable,
+ UpdateConcurrency: (*workloads.UpdateConcurrency)(synthesizedComp.UpdateStrategy.RollingUpdate.UpdateConcurrency),
+ }
+ }
}
- return nil, nil
+ return updateStrategy, nil
}
// itsInstancesConvertor converts component instanceTemplate to ITS instanceTemplate
@@ -249,27 +227,6 @@ func parseITSConvertorArgs(args ...any) (*SynthesizedComponent, error) {
return synthesizeComp, nil
}
-func getMemberUpdateStrategy(synthesizedComp *SynthesizedComponent) *workloads.MemberUpdateStrategy {
- if synthesizedComp.UpdateStrategy == nil {
- return nil
- }
- var (
- serial = workloads.SerialUpdateStrategy
- parallelUpdate = workloads.ParallelUpdateStrategy
- bestEffortParallelUpdate = workloads.BestEffortParallelUpdateStrategy
- )
- switch *synthesizedComp.UpdateStrategy {
- case kbappsv1.SerialConcurrency:
- return &serial
- case kbappsv1.ParallelConcurrency:
- return ¶llelUpdate
- case kbappsv1.BestEffortParallelConcurrency:
- return &bestEffortParallelUpdate
- default:
- return nil
- }
-}
-
// itsServiceConvertor converts the given object into InstanceSet.Spec.Service.
func (c *itsServiceConvertor) convert(args ...any) (any, error) {
return nil, nil
diff --git a/pkg/controller/component/synthesize_component.go b/pkg/controller/component/synthesize_component.go
index 18f248dac13..3d9c0533e23 100644
--- a/pkg/controller/component/synthesize_component.go
+++ b/pkg/controller/component/synthesize_component.go
@@ -91,7 +91,6 @@ func BuildSynthesizedComponent(ctx context.Context, cli client.Reader,
ConfigTemplates: compDefObj.Spec.Configs,
ScriptTemplates: compDefObj.Spec.Scripts,
Roles: compDefObj.Spec.Roles,
- UpdateStrategy: compDefObj.Spec.UpdateStrategyConstraint,
MinReadySeconds: compDefObj.Spec.MinReadySeconds,
PolicyRules: compDefObj.Spec.PolicyRules,
LifecycleActions: compDefObj.Spec.LifecycleActions,
@@ -106,13 +105,15 @@ func BuildSynthesizedComponent(ctx context.Context, cli client.Reader,
Stop: comp.Spec.Stop,
PodManagementPolicy: compDef.Spec.PodManagementPolicy,
ParallelPodManagementConcurrency: comp.Spec.ParallelPodManagementConcurrency,
- PodUpdatePolicy: comp.Spec.PodUpdatePolicy,
}
if err = mergeUserDefinedEnv(synthesizeComp, comp); err != nil {
return nil, err
}
+ // build update strategy for workload
+ buildUpdateStrategy(synthesizeComp, comp, compDefObj)
+
// build scheduling policy for workload
buildSchedulingPolicy(synthesizeComp, comp)
@@ -155,6 +156,42 @@ func BuildSynthesizedComponent(ctx context.Context, cli client.Reader,
return synthesizeComp, nil
}
+func buildUpdateStrategy(synthesizeComp *SynthesizedComponent, comp *appsv1.Component, compDef *appsv1.ComponentDefinition) {
+ var updateStrategy *appsv1.UpdateStrategy
+ if comp.Spec.UpdateStrategy != nil {
+ updateStrategy = &appsv1.UpdateStrategy{
+ InstanceUpdatePolicy: comp.Spec.UpdateStrategy.InstanceUpdatePolicy,
+ }
+ if comp.Spec.UpdateStrategy.RollingUpdate != nil {
+ updateStrategy.RollingUpdate = &appsv1.RollingUpdate{
+ Replicas: comp.Spec.UpdateStrategy.RollingUpdate.Replicas,
+ MaxUnavailable: comp.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable,
+ UpdateConcurrency: comp.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency,
+ }
+ }
+ }
+ if compDef.Spec.InstanceUpdatePolicy != nil {
+ if updateStrategy == nil {
+ updateStrategy = &appsv1.UpdateStrategy{}
+ }
+ if updateStrategy.InstanceUpdatePolicy == nil {
+ updateStrategy.InstanceUpdatePolicy = compDef.Spec.InstanceUpdatePolicy
+ }
+ }
+ if compDef.Spec.UpdateConcurrency != nil {
+ if updateStrategy == nil {
+ updateStrategy = &appsv1.UpdateStrategy{}
+ }
+ if updateStrategy.RollingUpdate == nil {
+ updateStrategy.RollingUpdate = &appsv1.RollingUpdate{}
+ }
+ if updateStrategy.RollingUpdate.UpdateConcurrency == nil {
+ updateStrategy.RollingUpdate.UpdateConcurrency = compDef.Spec.UpdateConcurrency
+ }
+ }
+ synthesizeComp.UpdateStrategy = updateStrategy
+}
+
func buildComp2CompDefs(ctx context.Context, cli client.Reader, cluster *appsv1.Cluster) (map[string]string, error) {
if cluster == nil {
return nil, nil
diff --git a/pkg/controller/component/type.go b/pkg/controller/component/type.go
index 2fbc633c63b..cb8f8435d46 100644
--- a/pkg/controller/component/type.go
+++ b/pkg/controller/component/type.go
@@ -42,7 +42,7 @@ type SynthesizedComponent struct {
Replicas int32 `json:"replicas"`
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
PodSpec *corev1.PodSpec `json:"podSpec,omitempty"`
- SidecarVars []kbappsv1.EnvVar // vars defined by sidecars
+ SidecarVars []kbappsv1.EnvVar // vars defined by sidecars
VolumeClaimTemplates []corev1.PersistentVolumeClaimTemplate `json:"volumeClaimTemplates,omitempty"`
LogConfigs []kbappsv1.LogConfig `json:"logConfigs,omitempty"`
ConfigTemplates []kbappsv1.ComponentConfigSpec `json:"configTemplates,omitempty"`
@@ -51,22 +51,21 @@ type SynthesizedComponent struct {
ServiceAccountName string `json:"serviceAccountName,omitempty"`
ServiceReferences map[string]*kbappsv1.ServiceDescriptor `json:"serviceReferences,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
- StaticLabels map[string]string // labels defined by the component definition
- DynamicLabels map[string]string // labels defined by the cluster and component API
+ StaticLabels map[string]string // labels defined by the component definition
+ DynamicLabels map[string]string // labels defined by the cluster and component API
Annotations map[string]string `json:"annotations,omitempty"`
- StaticAnnotations map[string]string // annotations defined by the component definition
- DynamicAnnotations map[string]string // annotations defined by the cluster and component API
+ StaticAnnotations map[string]string // annotations defined by the component definition
+ DynamicAnnotations map[string]string // annotations defined by the cluster and component API
TemplateVars map[string]any `json:"templateVars,omitempty"`
EnvVars []corev1.EnvVar `json:"envVars,omitempty"`
EnvFromSources []corev1.EnvFromSource `json:"envFromSources,omitempty"`
Instances []kbappsv1.InstanceTemplate `json:"instances,omitempty"`
OfflineInstances []string `json:"offlineInstances,omitempty"`
- Roles []kbappsv1.ReplicaRole `json:"roles,omitempty"`
- UpdateStrategy *kbappsv1.UpdateConcurrency `json:"updateStrategy,omitempty"`
- PodManagementPolicy *appsv1.PodManagementPolicyType `json:"podManagementPolicy,omitempty"`
- ParallelPodManagementConcurrency *intstr.IntOrString `json:"parallelPodManagementConcurrency,omitempty"`
- PodUpdatePolicy *kbappsv1.InstanceUpdatePolicyType `json:"podUpdatePolicy,omitempty"`
- PolicyRules []rbacv1.PolicyRule `json:"policyRules,omitempty"`
+ Roles []kbappsv1.ReplicaRole `json:"roles,omitempty"`
+ UpdateStrategy *kbappsv1.UpdateStrategy `json:"updateStrategy,omitempty"`
+ PodManagementPolicy *appsv1.PodManagementPolicyType `json:"podManagementPolicy,omitempty"`
+ ParallelPodManagementConcurrency *intstr.IntOrString `json:"parallelPodManagementConcurrency,omitempty"`
+ PolicyRules []rbacv1.PolicyRule `json:"policyRules,omitempty"`
LifecycleActions *kbappsv1.ComponentLifecycleActions `json:"lifecycleActions,omitempty"`
SystemAccounts []kbappsv1.SystemAccount `json:"systemAccounts,omitempty"`
Volumes []kbappsv1.ComponentVolume `json:"volumes,omitempty"`
diff --git a/pkg/controller/factory/builder_test.go b/pkg/controller/factory/builder_test.go
index 30de73608c7..a9977a2e832 100644
--- a/pkg/controller/factory/builder_test.go
+++ b/pkg/controller/factory/builder_test.go
@@ -126,9 +126,13 @@ var _ = Describe("builder", func() {
// test role probe
Expect(its.Spec.RoleProbe).Should(BeNil())
- // test member update strategy
- Expect(its.Spec.MemberUpdateStrategy).ShouldNot(BeNil())
- Expect(*its.Spec.MemberUpdateStrategy).Should(BeEquivalentTo(workloads.BestEffortParallelUpdateStrategy))
+ // test update strategy
+ Expect(its.Spec.UpdateStrategy).ShouldNot(BeNil())
+ Expect(its.Spec.UpdateStrategy.InstanceUpdatePolicy).ShouldNot(BeNil())
+ Expect(*its.Spec.UpdateStrategy.InstanceUpdatePolicy).Should(BeEquivalentTo(workloads.PreferInPlaceInstanceUpdatePolicyType))
+ Expect(its.Spec.UpdateStrategy.RollingUpdate).ShouldNot(BeNil())
+ Expect(its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency).ShouldNot(BeNil())
+ Expect(*its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency).Should(BeEquivalentTo(workloads.BestEffortParallelConcurrency))
})
It("builds ConfigMap with template correctly", func() {
diff --git a/pkg/controller/instanceset/reconciler_update.go b/pkg/controller/instanceset/reconciler_update.go
index 7e8c453063e..a06eaf8b9fc 100644
--- a/pkg/controller/instanceset/reconciler_update.go
+++ b/pkg/controller/instanceset/reconciler_update.go
@@ -23,7 +23,6 @@ import (
"fmt"
"time"
- apps "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -93,13 +92,8 @@ func (r *updateReconciler) Reconcile(tree *kubebuilderx.ObjectTree) (kubebuilder
}
// 3. do update
- // do nothing if UpdateStrategyType is 'OnDelete'
- if its.Spec.UpdateStrategy.Type == apps.OnDeleteStatefulSetStrategyType {
- return kubebuilderx.Continue, nil
- }
-
// handle 'RollingUpdate'
- partition, maxUnavailable, err := parsePartitionNMaxUnavailable(its.Spec.UpdateStrategy.RollingUpdate, len(oldPodList))
+ partition, maxUnavailable, err := parseReplicasNMaxUnavailable(its.Spec.UpdateStrategy, len(oldPodList))
if err != nil {
return kubebuilderx.Continue, err
}
@@ -114,8 +108,7 @@ func (r *updateReconciler) Reconcile(tree *kubebuilderx.ObjectTree) (kubebuilder
// if it's a roleful InstanceSet, we use updateCount to represent Pods can be updated according to the spec.memberUpdateStrategy.
updateCount := len(oldPodList)
if len(its.Spec.Roles) > 0 {
- itsForPlan := getInstanceSetForUpdatePlan(its)
- plan := NewUpdatePlan(*itsForPlan, oldPodList, IsPodUpdated)
+ plan := NewUpdatePlan(*its, oldPodList, IsPodUpdated)
podsToBeUpdated, err := plan.Execute()
if err != nil {
return kubebuilderx.Continue, err
@@ -160,9 +153,13 @@ func (r *updateReconciler) Reconcile(tree *kubebuilderx.ObjectTree) (kubebuilder
if err != nil {
return kubebuilderx.Continue, err
}
- if its.Spec.PodUpdatePolicy == workloads.StrictInPlacePodUpdatePolicyType && updatePolicy == RecreatePolicy {
- message := fmt.Sprintf("InstanceSet %s/%s blocks on update as the PodUpdatePolicy is %s and the pod %s can not inplace update",
- its.Namespace, its.Name, workloads.StrictInPlacePodUpdatePolicyType, pod.Name)
+ instanceUpdatePolicy := workloads.PreferInPlaceInstanceUpdatePolicyType
+ if its.Spec.UpdateStrategy != nil && its.Spec.UpdateStrategy.InstanceUpdatePolicy != nil {
+ instanceUpdatePolicy = *its.Spec.UpdateStrategy.InstanceUpdatePolicy
+ }
+ if instanceUpdatePolicy == workloads.StrictInPlaceInstanceUpdatePolicyType && updatePolicy == RecreatePolicy {
+ message := fmt.Sprintf("InstanceSet %s/%s blocks on update as the InstanceUpdatePolicy is %s and the pod %s can not inplace update",
+ its.Namespace, its.Name, workloads.StrictInPlaceInstanceUpdatePolicyType, pod.Name)
if tree != nil && tree.EventRecorder != nil {
tree.EventRecorder.Eventf(its, corev1.EventTypeWarning, EventReasonStrictInPlace, message)
}
@@ -209,39 +206,33 @@ func buildBlockedCondition(its *workloads.InstanceSet, message string) *metav1.C
}
}
-func getInstanceSetForUpdatePlan(its *workloads.InstanceSet) *workloads.InstanceSet {
- if its.Spec.MemberUpdateStrategy != nil {
- return its
- }
- itsForPlan := its.DeepCopy()
- updateStrategy := workloads.SerialUpdateStrategy
- if its.Spec.PodManagementPolicy == apps.ParallelPodManagement {
- updateStrategy = workloads.ParallelUpdateStrategy
- }
- itsForPlan.Spec.MemberUpdateStrategy = &updateStrategy
- return itsForPlan
-}
-
-func parsePartitionNMaxUnavailable(rollingUpdate *apps.RollingUpdateStatefulSetStrategy, replicas int) (int, int, error) {
- partition := replicas
+func parseReplicasNMaxUnavailable(updateStrategy *workloads.UpdateStrategy, totalReplicas int) (int, int, error) {
+ replicas := totalReplicas
maxUnavailable := 1
+ if updateStrategy == nil {
+ return replicas, maxUnavailable, nil
+ }
+ rollingUpdate := updateStrategy.RollingUpdate
if rollingUpdate == nil {
- return partition, maxUnavailable, nil
+ return replicas, maxUnavailable, nil
}
- if rollingUpdate.Partition != nil {
- partition = int(*rollingUpdate.Partition)
+ var err error
+ if rollingUpdate.Replicas != nil {
+ replicas, err = intstr.GetScaledValueFromIntOrPercent(rollingUpdate.Replicas, totalReplicas, false)
+ if err != nil {
+ return replicas, maxUnavailable, err
+ }
}
if rollingUpdate.MaxUnavailable != nil {
- maxUnavailableNum, err := intstr.GetScaledValueFromIntOrPercent(intstr.ValueOrDefault(rollingUpdate.MaxUnavailable, intstr.FromInt32(1)), replicas, false)
+ maxUnavailable, err = intstr.GetScaledValueFromIntOrPercent(intstr.ValueOrDefault(rollingUpdate.MaxUnavailable, intstr.FromInt32(1)), totalReplicas, false)
if err != nil {
return 0, 0, err
}
// maxUnavailable might be zero for small percentage with round down.
// So we have to enforce it not to be less than 1.
- if maxUnavailableNum < 1 {
- maxUnavailableNum = 1
+ if maxUnavailable < 1 {
+ maxUnavailable = 1
}
- maxUnavailable = maxUnavailableNum
}
- return partition, maxUnavailable, nil
+ return replicas, maxUnavailable, nil
}
diff --git a/pkg/controller/instanceset/reconciler_update_test.go b/pkg/controller/instanceset/reconciler_update_test.go
index feb067449e7..8b888cc59c5 100644
--- a/pkg/controller/instanceset/reconciler_update_test.go
+++ b/pkg/controller/instanceset/reconciler_update_test.go
@@ -159,11 +159,11 @@ var _ = Describe("update reconciler test", func() {
Expect(err).Should(BeNil())
root, ok := partitionTree.GetRoot().(*workloads.InstanceSet)
Expect(ok).Should(BeTrue())
- partition := int32(3)
+ updateReplicas := intstr.FromInt32(3)
maxUnavailable := intstr.FromInt32(2)
- root.Spec.UpdateStrategy = appsv1.StatefulSetUpdateStrategy{
- RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
- Partition: &partition,
+ root.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ RollingUpdate: &workloads.RollingUpdate{
+ Replicas: &updateReplicas,
MaxUnavailable: &maxUnavailable,
},
}
@@ -179,9 +179,9 @@ var _ = Describe("update reconciler test", func() {
Expect(err).Should(BeNil())
root, ok = partitionTree.GetRoot().(*workloads.InstanceSet)
Expect(ok).Should(BeTrue())
- root.Spec.UpdateStrategy = appsv1.StatefulSetUpdateStrategy{
- RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{
- Partition: &partition,
+ root.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ RollingUpdate: &workloads.RollingUpdate{
+ Replicas: &updateReplicas,
MaxUnavailable: &maxUnavailable,
},
}
@@ -198,17 +198,6 @@ var _ = Describe("update reconciler test", func() {
Expect(res).Should(Equal(kubebuilderx.Continue))
expectUpdatedPods(partitionTree, []string{"bar-foo-0"})
- By("reconcile with UpdateStrategy='OnDelete'")
- onDeleteTree, err := tree.DeepCopy()
- Expect(err).Should(BeNil())
- root, ok = onDeleteTree.GetRoot().(*workloads.InstanceSet)
- Expect(ok).Should(BeTrue())
- root.Spec.UpdateStrategy.Type = appsv1.OnDeleteStatefulSetStrategyType
- res, err = reconciler.Reconcile(onDeleteTree)
- Expect(err).Should(BeNil())
- Expect(res).Should(Equal(kubebuilderx.Continue))
- expectUpdatedPods(onDeleteTree, []string{})
-
// order: bar-hello-0, bar-foo-1, bar-foo-0, bar-3, bar-2, bar-1, bar-0
// expected: bar-hello-0 being deleted
By("reconcile with PodUpdatePolicy='PreferInPlace'")
@@ -216,7 +205,10 @@ var _ = Describe("update reconciler test", func() {
Expect(err).Should(BeNil())
root, ok = preferInPlaceTree.GetRoot().(*workloads.InstanceSet)
Expect(ok).Should(BeTrue())
- root.Spec.PodUpdatePolicy = workloads.PreferInPlacePodUpdatePolicyType
+ instanceUpdatePolicy := workloads.PreferInPlaceInstanceUpdatePolicyType
+ root.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ InstanceUpdatePolicy: &instanceUpdatePolicy,
+ }
// try to add env to instanceHello to trigger the recreation
root.Spec.Instances[0].Env = []corev1.EnvVar{
{
@@ -234,7 +226,10 @@ var _ = Describe("update reconciler test", func() {
Expect(err).Should(BeNil())
root, ok = strictInPlaceTree.GetRoot().(*workloads.InstanceSet)
Expect(ok).Should(BeTrue())
- root.Spec.PodUpdatePolicy = workloads.StrictInPlacePodUpdatePolicyType
+ instanceUpdatePolicy = workloads.StrictInPlaceInstanceUpdatePolicyType
+ root.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ InstanceUpdatePolicy: &instanceUpdatePolicy,
+ }
// try to add env to instanceHello to trigger the recreation
root.Spec.Instances[0].Env = []corev1.EnvVar{
{
diff --git a/pkg/controller/instanceset/update_plan.go b/pkg/controller/instanceset/update_plan.go
index 7c05e6aa60a..343356f6644 100644
--- a/pkg/controller/instanceset/update_plan.go
+++ b/pkg/controller/instanceset/update_plan.go
@@ -97,7 +97,8 @@ func (p *realUpdatePlan) planWalkFunc(vertex graph.Vertex) error {
// This change may lead to false alarms, as when all replicas are temporarily unavailable for some reason,
// the system will update them without waiting for their roles to be elected and probed. This cloud
// potentially hide some uncertain risks.
- serialUpdate := p.its.Spec.MemberUpdateStrategy != nil && *p.its.Spec.MemberUpdateStrategy == workloads.SerialUpdateStrategy
+ updateConcurrency := getUpdateConcurrency(&p.its)
+ serialUpdate := updateConcurrency == workloads.SerialConcurrency
hasRoleProbed := len(p.its.Status.MembersStatus) > 0
if !serialUpdate || hasRoleProbed {
return ErrWait
@@ -121,20 +122,18 @@ func (p *realUpdatePlan) build() {
root := &model.ObjectVertex{}
p.dag.AddVertex(root)
- if p.its.Spec.MemberUpdateStrategy == nil {
- return
- }
+ updateConcurrency := getUpdateConcurrency(&p.its)
rolePriorityMap := ComposeRolePriorityMap(p.its.Spec.Roles)
SortPods(p.pods, rolePriorityMap, false)
// generate plan by MemberUpdateStrategy
- switch *p.its.Spec.MemberUpdateStrategy {
- case workloads.SerialUpdateStrategy:
+ switch updateConcurrency {
+ case workloads.SerialConcurrency:
p.buildSerialUpdatePlan()
- case workloads.ParallelUpdateStrategy:
+ case workloads.ParallelConcurrency:
p.buildParallelUpdatePlan()
- case workloads.BestEffortParallelUpdateStrategy:
+ case workloads.BestEffortParallelConcurrency:
p.buildBestEffortParallelUpdatePlan(rolePriorityMap)
}
}
diff --git a/pkg/controller/instanceset/update_plan_test.go b/pkg/controller/instanceset/update_plan_test.go
index a789130d9d5..8a33a0fdbe0 100644
--- a/pkg/controller/instanceset/update_plan_test.go
+++ b/pkg/controller/instanceset/update_plan_test.go
@@ -121,8 +121,12 @@ var _ = Describe("update plan test.", func() {
It("should work well in a serial plan", func() {
By("build a serial plan")
- strategy := workloads.SerialUpdateStrategy
- its.Spec.MemberUpdateStrategy = &strategy
+ updateConcurrency := workloads.SerialConcurrency
+ its.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ RollingUpdate: &workloads.RollingUpdate{
+ UpdateConcurrency: &updateConcurrency,
+ },
+ }
expectedPlan := [][]*corev1.Pod{
{pod4},
{pod2},
@@ -137,8 +141,12 @@ var _ = Describe("update plan test.", func() {
It("should work well in a serial plan when pod has no role", func() {
By("build a serial plan")
- strategy := workloads.SerialUpdateStrategy
- its.Spec.MemberUpdateStrategy = &strategy
+ updateConcurrency := workloads.SerialConcurrency
+ its.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ RollingUpdate: &workloads.RollingUpdate{
+ UpdateConcurrency: &updateConcurrency,
+ },
+ }
expectedPlan := [][]*corev1.Pod{
{pod4},
{pod2},
@@ -153,8 +161,12 @@ var _ = Describe("update plan test.", func() {
It("should work well in a parallel plan", func() {
By("build a parallel plan")
- strategy := workloads.ParallelUpdateStrategy
- its.Spec.MemberUpdateStrategy = &strategy
+ updateConcurrency := workloads.ParallelConcurrency
+ its.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ RollingUpdate: &workloads.RollingUpdate{
+ UpdateConcurrency: &updateConcurrency,
+ },
+ }
expectedPlan := [][]*corev1.Pod{
{pod0, pod1, pod2, pod3, pod4, pod5, pod6},
}
@@ -163,8 +175,12 @@ var _ = Describe("update plan test.", func() {
It("should work well in a best effort parallel", func() {
By("build a best effort parallel plan")
- strategy := workloads.BestEffortParallelUpdateStrategy
- its.Spec.MemberUpdateStrategy = &strategy
+ updateConcurrency := workloads.BestEffortParallelConcurrency
+ its.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ RollingUpdate: &workloads.RollingUpdate{
+ UpdateConcurrency: &updateConcurrency,
+ },
+ }
expectedPlan := [][]*corev1.Pod{
{pod2, pod3, pod4, pod6},
{pod1},
@@ -176,8 +192,12 @@ var _ = Describe("update plan test.", func() {
It("should work well with role-less and heterogeneous pods", func() {
By("build a serial plan with role-less and heterogeneous pods")
- strategy := workloads.SerialUpdateStrategy
- its.Spec.MemberUpdateStrategy = &strategy
+ updateConcurrency := workloads.SerialConcurrency
+ its.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ RollingUpdate: &workloads.RollingUpdate{
+ UpdateConcurrency: &updateConcurrency,
+ },
+ }
its.Spec.Roles = nil
for _, pod := range []*corev1.Pod{pod0, pod1, pod2, pod3, pod4, pod5, pod6} {
labels := pod.Labels
diff --git a/pkg/controller/instanceset/utils.go b/pkg/controller/instanceset/utils.go
index d3cd1817586..9cd881ab75e 100644
--- a/pkg/controller/instanceset/utils.go
+++ b/pkg/controller/instanceset/utils.go
@@ -266,3 +266,13 @@ func CalculateConcurrencyReplicas(concurrency *intstr.IntOrString, replicas int)
pValue = integer.IntMax(integer.IntMin(pValue, replicas), 1)
return pValue, nil
}
+
+func getUpdateConcurrency(its *workloads.InstanceSet) workloads.UpdateConcurrency {
+ updateConcurrency := workloads.SerialConcurrency
+ if its.Spec.UpdateStrategy != nil &&
+ its.Spec.UpdateStrategy.RollingUpdate != nil &&
+ its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency != nil {
+ updateConcurrency = *its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency
+ }
+ return updateConcurrency
+}
diff --git a/pkg/testutil/apps/componentdefinition_factory.go b/pkg/testutil/apps/componentdefinition_factory.go
index 1aa6b160a66..c9e24b95cd3 100644
--- a/pkg/testutil/apps/componentdefinition_factory.go
+++ b/pkg/testutil/apps/componentdefinition_factory.go
@@ -276,8 +276,8 @@ func (f *MockComponentDefinitionFactory) AddSystemAccount(accountName string, in
return f
}
-func (f *MockComponentDefinitionFactory) SetUpdateStrategy(strategy *kbappsv1.UpdateConcurrency) *MockComponentDefinitionFactory {
- f.Get().Spec.UpdateStrategyConstraint = strategy
+func (f *MockComponentDefinitionFactory) SetUpdateConcurrency(concurrency *kbappsv1.UpdateConcurrency) *MockComponentDefinitionFactory {
+ f.Get().Spec.UpdateConcurrency = concurrency
return f
}
diff --git a/pkg/testutil/apps/constant.go b/pkg/testutil/apps/constant.go
index 8e6ad00814f..ec4ad432bd8 100644
--- a/pkg/testutil/apps/constant.go
+++ b/pkg/testutil/apps/constant.go
@@ -206,7 +206,8 @@ var (
},
},
},
- UpdateStrategyConstraint: &[]appsv1.UpdateConcurrency{appsv1.BestEffortParallelConcurrency}[0],
+ UpdateConcurrency: &[]appsv1.UpdateConcurrency{appsv1.BestEffortParallelConcurrency}[0],
+ InstanceUpdatePolicy: &[]appsv1.InstanceUpdatePolicyType{appsv1.PreferInPlaceInstanceUpdatePolicyType}[0],
Roles: []appsv1.ReplicaRole{
{
Name: "leader",
diff --git a/pkg/testutil/apps/instance_set_factoy.go b/pkg/testutil/apps/instance_set_factoy.go
index e8a12b99077..8eecf14c81b 100644
--- a/pkg/testutil/apps/instance_set_factoy.go
+++ b/pkg/testutil/apps/instance_set_factoy.go
@@ -20,7 +20,6 @@ along with this program. If not, see
.
package apps
import (
- appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -60,9 +59,6 @@ func NewInstanceSetFactory(namespace, name string, clusterName string, component
},
},
},
- UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
- Type: appsv1.OnDeleteStatefulSetStrategyType,
- },
},
}, f)
return f
From 4692b7b317e30bf2f15530a425446129cde169b5 Mon Sep 17 00:00:00 2001
From: free6om
Date: Thu, 12 Dec 2024 15:02:59 +0800
Subject: [PATCH 07/11] v1alpha1 <-> v1 conversion
---
apis/apps/v1alpha1/cluster_conversion.go | 66 +++++++++++++++++--
apis/apps/v1alpha1/component_conversion.go | 30 +++++++--
.../componentdefinition_conversion.go | 8 +++
.../v1alpha1/instanceset_conversion.go | 58 ++++++++++++++++
4 files changed, 154 insertions(+), 8 deletions(-)
diff --git a/apis/apps/v1alpha1/cluster_conversion.go b/apis/apps/v1alpha1/cluster_conversion.go
index b5ef1e578fa..181f87e661d 100644
--- a/apis/apps/v1alpha1/cluster_conversion.go
+++ b/apis/apps/v1alpha1/cluster_conversion.go
@@ -20,6 +20,8 @@ along with this program. If not, see .
package v1alpha1
import (
+ "slices"
+
"github.com/jinzhu/copier"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -104,13 +106,13 @@ func (r *Cluster) changesToCluster(cluster *appsv1.Cluster) {
// - volumeClaimTemplates
// spec:
// resources: corev1.ResourceRequirements -> corev1.VolumeResourceRequirements
- // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *InstanceUpdatePolicyType
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *UpdateStrategy.InstanceUpdatePolicyType
// sharings
// - template
// volumeClaimTemplates
// spec:
// resources: corev1.ResourceRequirements -> corev1.VolumeResourceRequirements
- // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *InstanceUpdatePolicyType
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *UpdateStrategy.InstanceUpdatePolicyType
// status
// components
// - message: ComponentMessageMap -> map[string]string
@@ -122,6 +124,38 @@ func (r *Cluster) changesToCluster(cluster *appsv1.Cluster) {
} else {
cluster.Spec.TerminationPolicy = appsv1.TerminationPolicyType(r.Spec.TerminationPolicy)
}
+ for i := range r.Spec.ComponentSpecs {
+ spec := &r.Spec.ComponentSpecs[i]
+ if spec.PodUpdatePolicy == nil {
+ continue
+ }
+ index := slices.IndexFunc(cluster.Spec.ComponentSpecs, func(componentSpec appsv1.ClusterComponentSpec) bool {
+ return spec.Name == componentSpec.Name
+ })
+ if index < 0 {
+ continue
+ }
+ if cluster.Spec.ComponentSpecs[index].UpdateStrategy == nil {
+ cluster.Spec.ComponentSpecs[index].UpdateStrategy = &appsv1.UpdateStrategy{}
+ }
+ cluster.Spec.ComponentSpecs[index].UpdateStrategy.InstanceUpdatePolicy = (*appsv1.InstanceUpdatePolicyType)(spec.PodUpdatePolicy)
+ }
+ for i := range r.Spec.ShardingSpecs {
+ spec := &r.Spec.ShardingSpecs[i]
+ if spec.Template.PodUpdatePolicy == nil {
+ continue
+ }
+ index := slices.IndexFunc(cluster.Spec.Shardings, func(sharding appsv1.ClusterSharding) bool {
+ return spec.Name == sharding.Name
+ })
+ if index < 0 {
+ continue
+ }
+ if cluster.Spec.Shardings[index].Template.UpdateStrategy == nil {
+ cluster.Spec.Shardings[index].Template.UpdateStrategy = &appsv1.UpdateStrategy{}
+ }
+ cluster.Spec.Shardings[index].Template.UpdateStrategy.InstanceUpdatePolicy = (*appsv1.InstanceUpdatePolicyType)(spec.Template.PodUpdatePolicy)
+ }
}
func (r *Cluster) changesFromCluster(cluster *appsv1.Cluster) {
@@ -132,13 +166,13 @@ func (r *Cluster) changesFromCluster(cluster *appsv1.Cluster) {
// - volumeClaimTemplates
// spec:
// resources: corev1.ResourceRequirements -> corev1.VolumeResourceRequirements
- // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *InstanceUpdatePolicyType
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *UpdateStrategy.InstanceUpdatePolicyType
// sharings
// - template
// volumeClaimTemplates
// spec:
// resources: corev1.ResourceRequirements -> corev1.VolumeResourceRequirements
- // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *InstanceUpdatePolicyType
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *UpdateStrategy.InstanceUpdatePolicyType
// status
// components
// - message: ComponentMessageMap -> map[string]string
@@ -146,6 +180,30 @@ func (r *Cluster) changesFromCluster(cluster *appsv1.Cluster) {
r.Spec.ClusterDefRef = cluster.Spec.ClusterDef
}
// appsv1.TerminationPolicyType is a subset of appsv1alpha1.TerminationPolicyType, it can be converted directly.
+ for _, spec := range cluster.Spec.ComponentSpecs {
+ if spec.UpdateStrategy == nil || spec.UpdateStrategy.InstanceUpdatePolicy == nil {
+ continue
+ }
+ index := slices.IndexFunc(r.Spec.ComponentSpecs, func(componentSpec ClusterComponentSpec) bool {
+ return spec.Name == componentSpec.Name
+ })
+ if index < 0 {
+ continue
+ }
+ r.Spec.ComponentSpecs[index].PodUpdatePolicy = (*workloads.PodUpdatePolicyType)(spec.UpdateStrategy.InstanceUpdatePolicy)
+ }
+ for _, sharding := range cluster.Spec.Shardings {
+ if sharding.Template.UpdateStrategy == nil || sharding.Template.UpdateStrategy.InstanceUpdatePolicy == nil {
+ continue
+ }
+ index := slices.IndexFunc(r.Spec.ShardingSpecs, func(spec ShardingSpec) bool {
+ return spec.Name == sharding.Name
+ })
+ if index < 0 {
+ continue
+ }
+ r.Spec.ShardingSpecs[index].Template.PodUpdatePolicy = (*workloads.PodUpdatePolicyType)(sharding.Template.UpdateStrategy.InstanceUpdatePolicy)
+ }
}
type clusterConverter struct {
diff --git a/apis/apps/v1alpha1/component_conversion.go b/apis/apps/v1alpha1/component_conversion.go
index 11d5da599c5..6f1104ff51e 100644
--- a/apis/apps/v1alpha1/component_conversion.go
+++ b/apis/apps/v1alpha1/component_conversion.go
@@ -26,6 +26,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/conversion"
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
+ "github.com/apecloud/kubeblocks/apis/workloads/v1alpha1"
)
// ConvertTo converts this Component to the Hub version (v1).
@@ -76,8 +77,7 @@ func (r *Component) ConvertFrom(srcRaw conversion.Hub) error {
func (r *Component) incrementConvertTo(dstRaw metav1.Object) (incrementChange, error) {
// changed
- comp := dstRaw.(*appsv1.Component)
- comp.Status.Message = r.Status.Message
+ r.changesToComponent(dstRaw.(*appsv1.Component))
// deleted
return &componentConverter{
@@ -97,12 +97,34 @@ func (r *Component) incrementConvertFrom(srcRaw metav1.Object, ic incrementChang
r.Spec.InstanceUpdateStrategy = c.InstanceUpdateStrategy
// changed
- comp := srcRaw.(*appsv1.Component)
- r.Status.Message = comp.Status.Message
+ r.changesFromComponent(srcRaw.(*appsv1.Component))
return nil
}
+func (r *Component) changesToComponent(comp *appsv1.Component) {
+ // changed:
+ // spec
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *UpdateStrategy.InstanceUpdatePolicyType
+ comp.Status.Message = r.Status.Message
+ if r.Spec.PodUpdatePolicy != nil {
+ if comp.Spec.UpdateStrategy == nil {
+ comp.Spec.UpdateStrategy = &appsv1.UpdateStrategy{}
+ }
+ comp.Spec.UpdateStrategy.InstanceUpdatePolicy = (*appsv1.InstanceUpdatePolicyType)(r.Spec.PodUpdatePolicy)
+ }
+}
+
+func (r *Component) changesFromComponent(comp *appsv1.Component) {
+ // changed:
+ // spec
+ // podUpdatePolicy: *workloads.InstanceUpdatePolicyType -> *UpdateStrategy.InstanceUpdatePolicyType
+ if comp.Spec.UpdateStrategy != nil && comp.Spec.UpdateStrategy.InstanceUpdatePolicy != nil {
+ r.Spec.PodUpdatePolicy = (*v1alpha1.PodUpdatePolicyType)(comp.Spec.UpdateStrategy.InstanceUpdatePolicy)
+ }
+ r.Status.Message = comp.Status.Message
+}
+
type componentConverter struct {
EnabledLogs []string `json:"enabledLogs,omitempty"`
Affinity *Affinity `json:"affinity,omitempty"`
diff --git a/apis/apps/v1alpha1/componentdefinition_conversion.go b/apis/apps/v1alpha1/componentdefinition_conversion.go
index bc16131e525..2bfe97e124f 100644
--- a/apis/apps/v1alpha1/componentdefinition_conversion.go
+++ b/apis/apps/v1alpha1/componentdefinition_conversion.go
@@ -115,6 +115,7 @@ func (r *ComponentDefinition) changesToComponentDefinition(cmpd *appsv1.Componen
// - ValueFrom
// componentVarRef:
// instanceNames -> podNames
+ // updateStrategy -> updateConcurrency
// lifecycleActions
for _, v := range r.Spec.Vars {
@@ -125,6 +126,9 @@ func (r *ComponentDefinition) changesToComponentDefinition(cmpd *appsv1.Componen
return err
}
}
+ if r.Spec.UpdateStrategy != nil {
+ cmpd.Spec.UpdateConcurrency = (*appsv1.UpdateConcurrency)(r.Spec.UpdateStrategy)
+ }
r.toV1LifecycleActions(cmpd)
return nil
}
@@ -136,6 +140,7 @@ func (r *ComponentDefinition) changesFromComponentDefinition(cmpd *appsv1.Compon
// - ValueFrom
// componentVarRef:
// instanceNames -> podNames
+ // updateStrategy -> updateConcurrency
// lifecycleActions
for _, v := range cmpd.Spec.Vars {
@@ -146,6 +151,9 @@ func (r *ComponentDefinition) changesFromComponentDefinition(cmpd *appsv1.Compon
return err
}
}
+ if cmpd.Spec.UpdateConcurrency != nil {
+ r.Spec.UpdateStrategy = (*UpdateStrategy)(cmpd.Spec.UpdateConcurrency)
+ }
r.fromV1LifecycleActions(cmpd)
return nil
}
diff --git a/apis/workloads/v1alpha1/instanceset_conversion.go b/apis/workloads/v1alpha1/instanceset_conversion.go
index 7da2721cf7e..75b86909124 100644
--- a/apis/workloads/v1alpha1/instanceset_conversion.go
+++ b/apis/workloads/v1alpha1/instanceset_conversion.go
@@ -21,6 +21,9 @@ package v1alpha1
import (
"github.com/jinzhu/copier"
+ appsv1 "k8s.io/api/apps/v1"
+ "k8s.io/apimachinery/pkg/util/intstr"
+ "k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/conversion"
workloadsv1 "github.com/apecloud/kubeblocks/apis/workloads/v1"
@@ -37,6 +40,7 @@ func (r *InstanceSet) ConvertTo(dstRaw conversion.Hub) error {
if err := copier.Copy(&dst.Spec, &r.Spec); err != nil {
return err
}
+ r.changesToInstanceSet(dst)
// status
if err := copier.Copy(&dst.Status, &r.Status); err != nil {
@@ -65,3 +69,57 @@ func (r *InstanceSet) ConvertFrom(srcRaw conversion.Hub) error {
return nil
}
+
+func (r *InstanceSet) changesToInstanceSet(its *workloadsv1.InstanceSet) {
+ // changed:
+ // spec
+ // podUpdatePolicy -> updateStrategy.instanceUpdatePolicy
+ // memberUpdateStrategy -> updateStrategy.rollingUpdate.updateConcurrency
+ // updateStrategy.rollingUpdate.partition -> updateStrategy.rollingUpdate.replicas
+ if its.Spec.UpdateStrategy == nil {
+ its.Spec.UpdateStrategy = &workloadsv1.UpdateStrategy{}
+ }
+ its.Spec.UpdateStrategy.InstanceUpdatePolicy = (*workloadsv1.InstanceUpdatePolicyType)(&r.Spec.PodUpdatePolicy)
+ if r.Spec.MemberUpdateStrategy != nil {
+ if its.Spec.UpdateStrategy.RollingUpdate == nil {
+ its.Spec.UpdateStrategy.RollingUpdate = &workloadsv1.RollingUpdate{}
+ }
+ its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency = (*workloadsv1.UpdateConcurrency)(r.Spec.MemberUpdateStrategy)
+ }
+ if r.Spec.UpdateStrategy.RollingUpdate != nil {
+ if r.Spec.UpdateStrategy.RollingUpdate.Partition != nil {
+ if its.Spec.UpdateStrategy.RollingUpdate == nil {
+ its.Spec.UpdateStrategy.RollingUpdate = &workloadsv1.RollingUpdate{}
+ }
+ replicas := intstr.FromInt32(*r.Spec.UpdateStrategy.RollingUpdate.Partition)
+ its.Spec.UpdateStrategy.RollingUpdate.Replicas = &replicas
+ }
+ }
+}
+
+func (r *InstanceSet) changesFromInstanceSet(its *workloadsv1.InstanceSet) {
+ // changed:
+ // spec
+ // podUpdatePolicy -> updateStrategy.instanceUpdatePolicy
+ // memberUpdateStrategy -> updateStrategy.rollingUpdate.updateConcurrency
+ // updateStrategy.rollingUpdate.partition -> updateStrategy.rollingUpdate.replicas
+ if its.Spec.UpdateStrategy == nil {
+ return
+ }
+ if its.Spec.UpdateStrategy.InstanceUpdatePolicy != nil {
+ r.Spec.PodUpdatePolicy = PodUpdatePolicyType(*its.Spec.UpdateStrategy.InstanceUpdatePolicy)
+ }
+ if its.Spec.UpdateStrategy.RollingUpdate == nil {
+ return
+ }
+ if its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency != nil {
+ r.Spec.MemberUpdateStrategy = (*MemberUpdateStrategy)(its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency)
+ }
+ if its.Spec.UpdateStrategy.RollingUpdate.Replicas != nil {
+ if r.Spec.UpdateStrategy.RollingUpdate == nil {
+ r.Spec.UpdateStrategy.RollingUpdate = &appsv1.RollingUpdateStatefulSetStrategy{}
+ }
+ partition, _ := intstr.GetScaledValueFromIntOrPercent(its.Spec.UpdateStrategy.RollingUpdate.Replicas, int(*its.Spec.Replicas), false)
+ r.Spec.UpdateStrategy.RollingUpdate.Partition = pointer.Int32(int32(partition))
+ }
+}
From c47b10287681488b406e6fb2838c64026f96be47 Mon Sep 17 00:00:00 2001
From: free6om
Date: Thu, 12 Dec 2024 15:43:14 +0800
Subject: [PATCH 08/11] fix staticcheck error
---
apis/workloads/v1alpha1/instanceset_conversion.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/apis/workloads/v1alpha1/instanceset_conversion.go b/apis/workloads/v1alpha1/instanceset_conversion.go
index 75b86909124..e1187ddf5d4 100644
--- a/apis/workloads/v1alpha1/instanceset_conversion.go
+++ b/apis/workloads/v1alpha1/instanceset_conversion.go
@@ -61,6 +61,7 @@ func (r *InstanceSet) ConvertFrom(srcRaw conversion.Hub) error {
if err := copier.Copy(&r.Spec, &src.Spec); err != nil {
return err
}
+ r.changesFromInstanceSet(src)
// status
if err := copier.Copy(&r.Status, &src.Status); err != nil {
From 7ffb8078fd8160e8b8dac7b85897b75fdec5b6e3 Mon Sep 17 00:00:00 2001
From: free6om
Date: Mon, 23 Dec 2024 10:32:16 +0800
Subject: [PATCH 09/11] remove InstanceUpdatePolicy from cmpd
---
apis/apps/v1/componentdefinition_types.go | 12 ------------
apis/apps/v1/zz_generated.deepcopy.go | 5 -----
.../apps.kubeblocks.io_componentdefinitions.yaml | 14 --------------
.../apps.kubeblocks.io_componentdefinitions.yaml | 14 --------------
pkg/controller/component/synthesize_component.go | 8 --------
pkg/testutil/apps/constant.go | 1 -
6 files changed, 54 deletions(-)
diff --git a/apis/apps/v1/componentdefinition_types.go b/apis/apps/v1/componentdefinition_types.go
index e7f59c0e4b5..5cd57edcab2 100644
--- a/apis/apps/v1/componentdefinition_types.go
+++ b/apis/apps/v1/componentdefinition_types.go
@@ -444,18 +444,6 @@ type ComponentDefinitionSpec struct {
// +optional
MinReadySeconds int32 `json:"minReadySeconds,omitempty"`
- // Specifies how an instance should be updated.
- //
- // - `StrictInPlace` indicates that only allows in-place update.
- // Any attempt to modify other fields that not support in-place update will be rejected.
- // - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
- // If that fails, it will fall back to the ReCreate, where instance will be recreated.
- // Default value is "PreferInPlace".
- //
- // +kubebuilder:validation:Enum={StrictInPlace,PreferInPlace}
- // +optional
- InstanceUpdatePolicy *InstanceUpdatePolicyType `json:"instanceUpdatePolicy,omitempty"`
-
// Specifies the concurrency level for updating instances during a rolling update.
// Available levels:
//
diff --git a/apis/apps/v1/zz_generated.deepcopy.go b/apis/apps/v1/zz_generated.deepcopy.go
index bf14b491b57..2e35adeb186 100644
--- a/apis/apps/v1/zz_generated.deepcopy.go
+++ b/apis/apps/v1/zz_generated.deepcopy.go
@@ -1191,11 +1191,6 @@ func (in *ComponentDefinitionSpec) DeepCopyInto(out *ComponentDefinitionSpec) {
*out = make([]ReplicaRole, len(*in))
copy(*out, *in)
}
- if in.InstanceUpdatePolicy != nil {
- in, out := &in.InstanceUpdatePolicy, &out.InstanceUpdatePolicy
- *out = new(InstanceUpdatePolicyType)
- **out = **in
- }
if in.UpdateConcurrency != nil {
in, out := &in.UpdateConcurrency, &out.UpdateConcurrency
*out = new(UpdateConcurrency)
diff --git a/config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml b/config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml
index 5a9c213212e..27599fc79f9 100644
--- a/config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml
+++ b/config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml
@@ -4449,20 +4449,6 @@ spec:
type: object
type: array
type: object
- instanceUpdatePolicy:
- description: |-
- Specifies how an instance should be updated.
-
-
- - `StrictInPlace` indicates that only allows in-place update.
- Any attempt to modify other fields that not support in-place update will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
- If that fails, it will fall back to the ReCreate, where instance will be recreated.
- Default value is "PreferInPlace".
- enum:
- - StrictInPlace
- - PreferInPlace
- type: string
labels:
additionalProperties:
type: string
diff --git a/deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml b/deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml
index 5a9c213212e..27599fc79f9 100644
--- a/deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml
+++ b/deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml
@@ -4449,20 +4449,6 @@ spec:
type: object
type: array
type: object
- instanceUpdatePolicy:
- description: |-
- Specifies how an instance should be updated.
-
-
- - `StrictInPlace` indicates that only allows in-place update.
- Any attempt to modify other fields that not support in-place update will be rejected.
- - `PreferInPlace` indicates that we will first attempt an in-place update of the instance.
- If that fails, it will fall back to the ReCreate, where instance will be recreated.
- Default value is "PreferInPlace".
- enum:
- - StrictInPlace
- - PreferInPlace
- type: string
labels:
additionalProperties:
type: string
diff --git a/pkg/controller/component/synthesize_component.go b/pkg/controller/component/synthesize_component.go
index 3d9c0533e23..95b562b1e0e 100644
--- a/pkg/controller/component/synthesize_component.go
+++ b/pkg/controller/component/synthesize_component.go
@@ -170,14 +170,6 @@ func buildUpdateStrategy(synthesizeComp *SynthesizedComponent, comp *appsv1.Comp
}
}
}
- if compDef.Spec.InstanceUpdatePolicy != nil {
- if updateStrategy == nil {
- updateStrategy = &appsv1.UpdateStrategy{}
- }
- if updateStrategy.InstanceUpdatePolicy == nil {
- updateStrategy.InstanceUpdatePolicy = compDef.Spec.InstanceUpdatePolicy
- }
- }
if compDef.Spec.UpdateConcurrency != nil {
if updateStrategy == nil {
updateStrategy = &appsv1.UpdateStrategy{}
diff --git a/pkg/testutil/apps/constant.go b/pkg/testutil/apps/constant.go
index ec4ad432bd8..2db15cd5093 100644
--- a/pkg/testutil/apps/constant.go
+++ b/pkg/testutil/apps/constant.go
@@ -207,7 +207,6 @@ var (
},
},
UpdateConcurrency: &[]appsv1.UpdateConcurrency{appsv1.BestEffortParallelConcurrency}[0],
- InstanceUpdatePolicy: &[]appsv1.InstanceUpdatePolicyType{appsv1.PreferInPlaceInstanceUpdatePolicyType}[0],
Roles: []appsv1.ReplicaRole{
{
Name: "leader",
From 48d9c8512b6aaafd884f37853eb8e739836b8ea1 Mon Sep 17 00:00:00 2001
From: free6om
Date: Mon, 23 Dec 2024 11:07:14 +0800
Subject: [PATCH 10/11] support OnDelete update strategy
---
apis/apps/v1/types.go | 23 ++++
apis/workloads/v1/instanceset_types.go | 23 ++++
.../bases/apps.kubeblocks.io_clusters.yaml | 16 +++
.../bases/apps.kubeblocks.io_components.yaml | 8 ++
.../workloads.kubeblocks.io_instancesets.yaml | 8 ++
.../crds/apps.kubeblocks.io_clusters.yaml | 16 +++
.../crds/apps.kubeblocks.io_components.yaml | 8 ++
.../workloads.kubeblocks.io_instancesets.yaml | 8 ++
docs/developer_docs/api-reference/cluster.md | 128 ++++++++++++------
pkg/controller/component/its_convertor.go | 1 +
.../component/synthesize_component.go | 1 +
.../instanceset/reconciler_update.go | 5 +
.../instanceset/reconciler_update_test.go | 13 ++
pkg/testutil/apps/constant.go | 2 +-
pkg/testutil/apps/instance_set_factoy.go | 3 +
15 files changed, 219 insertions(+), 44 deletions(-)
diff --git a/apis/apps/v1/types.go b/apis/apps/v1/types.go
index 6369e87b4bb..b70c1e13d02 100644
--- a/apis/apps/v1/types.go
+++ b/apis/apps/v1/types.go
@@ -665,6 +665,12 @@ type InstanceTemplate struct {
// UpdateStrategy defines fine-grained control over the spec update process of all instances.
type UpdateStrategy struct {
+ // Indicates the type of the UpdateStrategy.
+ // Default is RollingUpdate.
+ //
+ // +optional
+ Type UpdateStrategyType `json:"type,omitempty"`
+
// Indicates how instances should be updated.
//
// - `StrictInPlace` indicates that only allows in-place update.
@@ -683,6 +689,23 @@ type UpdateStrategy struct {
RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"`
}
+// UpdateStrategyType is a string enumeration type that enumerates
+// all possible update strategies for the KubeBlocks controllers.
+//
+// +enum
+// +kubebuilder:validation:Enum={RollingUpdate,OnDelete}
+type UpdateStrategyType string
+
+const (
+ // RollingUpdateStrategyType indicates that update will be
+ // applied to all Instances with respect to the InstanceSet
+ // ordering constraints.
+ RollingUpdateStrategyType UpdateStrategyType = "RollingUpdate"
+ // OnDeleteStrategyType indicates that ordered rolling restarts are disabled. Instances are recreated
+ // when they are manually deleted.
+ OnDeleteStrategyType UpdateStrategyType = "OnDelete"
+)
+
// RollingUpdate specifies how the rolling update should be applied.
type RollingUpdate struct {
// Indicates the number of instances that should be updated during a rolling update.
diff --git a/apis/workloads/v1/instanceset_types.go b/apis/workloads/v1/instanceset_types.go
index e88baa08c69..5837bfbd76a 100644
--- a/apis/workloads/v1/instanceset_types.go
+++ b/apis/workloads/v1/instanceset_types.go
@@ -429,6 +429,12 @@ type SchedulingPolicy struct {
// UpdateStrategy defines fine-grained control over the spec update process of all instances.
type UpdateStrategy struct {
+ // Indicates the type of the UpdateStrategy.
+ // Default is RollingUpdate.
+ //
+ // +optional
+ Type UpdateStrategyType `json:"type,omitempty"`
+
// Indicates how instances should be updated.
//
// - `StrictInPlace` indicates that only allows in-place update.
@@ -447,6 +453,23 @@ type UpdateStrategy struct {
RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"`
}
+// UpdateStrategyType is a string enumeration type that enumerates
+// all possible update strategies for the KubeBlocks controllers.
+//
+// +enum
+// +kubebuilder:validation:Enum={RollingUpdate,OnDelete}
+type UpdateStrategyType string
+
+const (
+ // RollingUpdateStrategyType indicates that update will be
+ // applied to all Instances with respect to the InstanceSet
+ // ordering constraints.
+ RollingUpdateStrategyType UpdateStrategyType = "RollingUpdate"
+ // OnDeleteStrategyType indicates that ordered rolling restarts are disabled. Instances are recreated
+ // when they are manually deleted.
+ OnDeleteStrategyType UpdateStrategyType = "OnDelete"
+)
+
// RollingUpdate specifies how the rolling update should be applied.
type RollingUpdate struct {
// Indicates the number of instances that should be updated during a rolling update.
diff --git a/config/crd/bases/apps.kubeblocks.io_clusters.yaml b/config/crd/bases/apps.kubeblocks.io_clusters.yaml
index a8f51511f11..3d6ba2c3009 100644
--- a/config/crd/bases/apps.kubeblocks.io_clusters.yaml
+++ b/config/crd/bases/apps.kubeblocks.io_clusters.yaml
@@ -5410,6 +5410,14 @@ spec:
to 'Serial'."
type: string
type: object
+ type:
+ description: |-
+ Indicates the type of the UpdateStrategy.
+ Default is RollingUpdate.
+ enum:
+ - RollingUpdate
+ - OnDelete
+ type: string
type: object
volumeClaimTemplates:
description: |-
@@ -14172,6 +14180,14 @@ spec:
to 'Serial'."
type: string
type: object
+ type:
+ description: |-
+ Indicates the type of the UpdateStrategy.
+ Default is RollingUpdate.
+ enum:
+ - RollingUpdate
+ - OnDelete
+ type: string
type: object
volumeClaimTemplates:
description: |-
diff --git a/config/crd/bases/apps.kubeblocks.io_components.yaml b/config/crd/bases/apps.kubeblocks.io_components.yaml
index ca5f89dbec8..ed49feac30a 100644
--- a/config/crd/bases/apps.kubeblocks.io_components.yaml
+++ b/config/crd/bases/apps.kubeblocks.io_components.yaml
@@ -5671,6 +5671,14 @@ spec:
to 'Serial'."
type: string
type: object
+ type:
+ description: |-
+ Indicates the type of the UpdateStrategy.
+ Default is RollingUpdate.
+ enum:
+ - RollingUpdate
+ - OnDelete
+ type: string
type: object
volumeClaimTemplates:
description: |-
diff --git a/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml b/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml
index b76985e1411..b14b0785072 100644
--- a/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml
+++ b/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml
@@ -11809,6 +11809,14 @@ spec:
to 'Serial'."
type: string
type: object
+ type:
+ description: |-
+ Indicates the type of the UpdateStrategy.
+ Default is RollingUpdate.
+ enum:
+ - RollingUpdate
+ - OnDelete
+ type: string
type: object
volumeClaimTemplates:
description: |-
diff --git a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml
index a8f51511f11..3d6ba2c3009 100644
--- a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml
+++ b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml
@@ -5410,6 +5410,14 @@ spec:
to 'Serial'."
type: string
type: object
+ type:
+ description: |-
+ Indicates the type of the UpdateStrategy.
+ Default is RollingUpdate.
+ enum:
+ - RollingUpdate
+ - OnDelete
+ type: string
type: object
volumeClaimTemplates:
description: |-
@@ -14172,6 +14180,14 @@ spec:
to 'Serial'."
type: string
type: object
+ type:
+ description: |-
+ Indicates the type of the UpdateStrategy.
+ Default is RollingUpdate.
+ enum:
+ - RollingUpdate
+ - OnDelete
+ type: string
type: object
volumeClaimTemplates:
description: |-
diff --git a/deploy/helm/crds/apps.kubeblocks.io_components.yaml b/deploy/helm/crds/apps.kubeblocks.io_components.yaml
index ca5f89dbec8..ed49feac30a 100644
--- a/deploy/helm/crds/apps.kubeblocks.io_components.yaml
+++ b/deploy/helm/crds/apps.kubeblocks.io_components.yaml
@@ -5671,6 +5671,14 @@ spec:
to 'Serial'."
type: string
type: object
+ type:
+ description: |-
+ Indicates the type of the UpdateStrategy.
+ Default is RollingUpdate.
+ enum:
+ - RollingUpdate
+ - OnDelete
+ type: string
type: object
volumeClaimTemplates:
description: |-
diff --git a/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml b/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml
index b76985e1411..b14b0785072 100644
--- a/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml
+++ b/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml
@@ -11809,6 +11809,14 @@ spec:
to 'Serial'."
type: string
type: object
+ type:
+ description: |-
+ Indicates the type of the UpdateStrategy.
+ Default is RollingUpdate.
+ enum:
+ - RollingUpdate
+ - OnDelete
+ type: string
type: object
volumeClaimTemplates:
description: |-
diff --git a/docs/developer_docs/api-reference/cluster.md b/docs/developer_docs/api-reference/cluster.md
index 619185fe75a..b52a1ae58be 100644
--- a/docs/developer_docs/api-reference/cluster.md
+++ b/docs/developer_docs/api-reference/cluster.md
@@ -1408,27 +1408,6 @@ This ensures the Pod’s stability and readiness to serve requests.
-instanceUpdatePolicy
-
-
-InstanceUpdatePolicyType
-
-
- |
-
-(Optional)
- Specifies how an instance should be updated.
-
-StrictInPlace indicates that only allows in-place update.
-Any attempt to modify other fields that not support in-place update will be rejected.
-PreferInPlace indicates that we will first attempt an in-place update of the instance.
-If that fails, it will fall back to the ReCreate, where instance will be recreated.
-Default value is “PreferInPlace”.
-
- |
-
-
-
updateConcurrency
@@ -5259,27 +5238,6 @@ This ensures the Pod’s stability and readiness to serve requests.
|
-instanceUpdatePolicy
-
-
-InstanceUpdatePolicyType
-
-
- |
-
-(Optional)
- Specifies how an instance should be updated.
-
-StrictInPlace indicates that only allows in-place update.
-Any attempt to modify other fields that not support in-place update will be rejected.
-PreferInPlace indicates that we will first attempt an in-place update of the instance.
-If that fails, it will fall back to the ReCreate, where instance will be recreated.
-Default value is “PreferInPlace”.
-
- |
-
-
-
updateConcurrency
@@ -7939,7 +7897,7 @@ Add new or override existing volume claim templates.
InstanceUpdatePolicyType
(string alias)
-(Appears on:ComponentDefinitionSpec, UpdateStrategy)
+(Appears on:UpdateStrategy)
@@ -11625,6 +11583,21 @@ This ensures that only one replica is unavailable at a time during the update pr
+type
+
+
+UpdateStrategyType
+
+
+ |
+
+(Optional)
+ Indicates the type of the UpdateStrategy.
+Default is RollingUpdate.
+ |
+
+
+
instanceUpdatePolicy
@@ -11660,6 +11633,33 @@ RollingUpdate
|
+UpdateStrategyType
+(string alias)
+
+(Appears on:UpdateStrategy)
+
+
+ UpdateStrategyType is a string enumeration type that enumerates
+all possible update strategies for the KubeBlocks controllers.
+
+
+
+
+Value |
+Description |
+
+
+"OnDelete" |
+OnDeleteStrategyType indicates that ordered rolling restarts are disabled. Instances are recreated
+when they are manually deleted.
+ |
+ "RollingUpdate" |
+RollingUpdateStrategyType indicates that update will be
+applied to all Instances with respect to the InstanceSet
+ordering constraints.
+ |
+
+
VarOption
(string alias)
@@ -30676,6 +30676,21 @@ This ensures that only one replica is unavailable at a time during the update pr
+type
+
+
+UpdateStrategyType
+
+
+ |
+
+(Optional)
+ Indicates the type of the UpdateStrategy.
+Default is RollingUpdate.
+ |
+
+
+
instanceUpdatePolicy
@@ -30711,6 +30726,33 @@ RollingUpdate
|
+UpdateStrategyType
+(string alias)
+
+(Appears on:UpdateStrategy)
+
+
+ UpdateStrategyType is a string enumeration type that enumerates
+all possible update strategies for the KubeBlocks controllers.
+
+
+
+
+Value |
+Description |
+
+
+"OnDelete" |
+OnDeleteStrategyType indicates that ordered rolling restarts are disabled. Instances are recreated
+when they are manually deleted.
+ |
+ "RollingUpdate" |
+RollingUpdateStrategyType indicates that update will be
+applied to all Instances with respect to the InstanceSet
+ordering constraints.
+ |
+
+
workloads.kubeblocks.io/v1alpha1
diff --git a/pkg/controller/component/its_convertor.go b/pkg/controller/component/its_convertor.go
index 3b9bf069064..bca212171b2 100644
--- a/pkg/controller/component/its_convertor.go
+++ b/pkg/controller/component/its_convertor.go
@@ -117,6 +117,7 @@ func (c *itsUpdateStrategyConvertor) convert(args ...any) (any, error) {
var updateStrategy *workloads.UpdateStrategy
if synthesizedComp.UpdateStrategy != nil {
updateStrategy = &workloads.UpdateStrategy{
+ Type: workloads.UpdateStrategyType(synthesizedComp.UpdateStrategy.Type),
InstanceUpdatePolicy: (*workloads.InstanceUpdatePolicyType)(synthesizedComp.UpdateStrategy.InstanceUpdatePolicy),
}
if synthesizedComp.UpdateStrategy.RollingUpdate != nil {
diff --git a/pkg/controller/component/synthesize_component.go b/pkg/controller/component/synthesize_component.go
index 95b562b1e0e..638f3935db7 100644
--- a/pkg/controller/component/synthesize_component.go
+++ b/pkg/controller/component/synthesize_component.go
@@ -160,6 +160,7 @@ func buildUpdateStrategy(synthesizeComp *SynthesizedComponent, comp *appsv1.Comp
var updateStrategy *appsv1.UpdateStrategy
if comp.Spec.UpdateStrategy != nil {
updateStrategy = &appsv1.UpdateStrategy{
+ Type: comp.Spec.UpdateStrategy.Type,
InstanceUpdatePolicy: comp.Spec.UpdateStrategy.InstanceUpdatePolicy,
}
if comp.Spec.UpdateStrategy.RollingUpdate != nil {
diff --git a/pkg/controller/instanceset/reconciler_update.go b/pkg/controller/instanceset/reconciler_update.go
index a06eaf8b9fc..bee0ca50cbe 100644
--- a/pkg/controller/instanceset/reconciler_update.go
+++ b/pkg/controller/instanceset/reconciler_update.go
@@ -92,6 +92,11 @@ func (r *updateReconciler) Reconcile(tree *kubebuilderx.ObjectTree) (kubebuilder
}
// 3. do update
+ // do nothing if UpdateStrategyType is 'OnDelete'
+ if its.Spec.UpdateStrategy != nil && its.Spec.UpdateStrategy.Type == workloads.OnDeleteStrategyType {
+ return kubebuilderx.Continue, nil
+ }
+
// handle 'RollingUpdate'
partition, maxUnavailable, err := parseReplicasNMaxUnavailable(its.Spec.UpdateStrategy, len(oldPodList))
if err != nil {
diff --git a/pkg/controller/instanceset/reconciler_update_test.go b/pkg/controller/instanceset/reconciler_update_test.go
index 8b888cc59c5..42d7fff5098 100644
--- a/pkg/controller/instanceset/reconciler_update_test.go
+++ b/pkg/controller/instanceset/reconciler_update_test.go
@@ -198,6 +198,19 @@ var _ = Describe("update reconciler test", func() {
Expect(res).Should(Equal(kubebuilderx.Continue))
expectUpdatedPods(partitionTree, []string{"bar-foo-0"})
+ By("reconcile with UpdateStrategy='OnDelete'")
+ onDeleteTree, err := tree.DeepCopy()
+ Expect(err).Should(BeNil())
+ root, ok = onDeleteTree.GetRoot().(*workloads.InstanceSet)
+ Expect(ok).Should(BeTrue())
+ root.Spec.UpdateStrategy = &workloads.UpdateStrategy{
+ Type: workloads.OnDeleteStrategyType,
+ }
+ res, err = reconciler.Reconcile(onDeleteTree)
+ Expect(err).Should(BeNil())
+ Expect(res).Should(Equal(kubebuilderx.Continue))
+ expectUpdatedPods(onDeleteTree, []string{})
+
// order: bar-hello-0, bar-foo-1, bar-foo-0, bar-3, bar-2, bar-1, bar-0
// expected: bar-hello-0 being deleted
By("reconcile with PodUpdatePolicy='PreferInPlace'")
diff --git a/pkg/testutil/apps/constant.go b/pkg/testutil/apps/constant.go
index 2db15cd5093..7d1b5714d08 100644
--- a/pkg/testutil/apps/constant.go
+++ b/pkg/testutil/apps/constant.go
@@ -206,7 +206,7 @@ var (
},
},
},
- UpdateConcurrency: &[]appsv1.UpdateConcurrency{appsv1.BestEffortParallelConcurrency}[0],
+ UpdateConcurrency: &[]appsv1.UpdateConcurrency{appsv1.BestEffortParallelConcurrency}[0],
Roles: []appsv1.ReplicaRole{
{
Name: "leader",
diff --git a/pkg/testutil/apps/instance_set_factoy.go b/pkg/testutil/apps/instance_set_factoy.go
index 8eecf14c81b..b8fb66baef2 100644
--- a/pkg/testutil/apps/instance_set_factoy.go
+++ b/pkg/testutil/apps/instance_set_factoy.go
@@ -59,6 +59,9 @@ func NewInstanceSetFactory(namespace, name string, clusterName string, component
},
},
},
+ UpdateStrategy: &workloads.UpdateStrategy{
+ Type: workloads.OnDeleteStrategyType,
+ },
},
}, f)
return f
From bcb16358678c0a272f959446dbd7fb3702b35cea Mon Sep 17 00:00:00 2001
From: free6om
Date: Mon, 23 Dec 2024 11:20:13 +0800
Subject: [PATCH 11/11] fix broken ut
---
pkg/controller/factory/builder_test.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pkg/controller/factory/builder_test.go b/pkg/controller/factory/builder_test.go
index 1d5b21000d9..e122431e82d 100644
--- a/pkg/controller/factory/builder_test.go
+++ b/pkg/controller/factory/builder_test.go
@@ -125,8 +125,8 @@ var _ = Describe("builder", func() {
// test update strategy
Expect(its.Spec.UpdateStrategy).ShouldNot(BeNil())
- Expect(its.Spec.UpdateStrategy.InstanceUpdatePolicy).ShouldNot(BeNil())
- Expect(*its.Spec.UpdateStrategy.InstanceUpdatePolicy).Should(BeEquivalentTo(workloads.PreferInPlaceInstanceUpdatePolicyType))
+ Expect(its.Spec.UpdateStrategy.Type).Should(BeEmpty())
+ Expect(its.Spec.UpdateStrategy.InstanceUpdatePolicy).Should(BeNil())
Expect(its.Spec.UpdateStrategy.RollingUpdate).ShouldNot(BeNil())
Expect(its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency).ShouldNot(BeNil())
Expect(*its.Spec.UpdateStrategy.RollingUpdate.UpdateConcurrency).Should(BeEquivalentTo(workloads.BestEffortParallelConcurrency))
|