From 34af05f4d557e7fe6bc2c87399c3d99dd15c226d Mon Sep 17 00:00:00 2001 From: yandongxiao Date: Tue, 12 Nov 2024 15:07:26 +0800 Subject: [PATCH] [Enhancement] Support Update Strategy for FE/BE/CN component Signed-off-by: yandongxiao --- .../starrocks.com_starrocksclusters.yaml | 117 ++++++++++++++++++ .../starrocks.com_starrockswarehouses.yaml | 39 ++++++ deploy/starrocks.com_starrocksclusters.yaml | 48 +++++++ deploy/starrocks.com_starrockswarehouses.yaml | 16 +++ .../starrocks/templates/starrockscluster.yaml | 15 +++ .../charts/starrocks/values.yaml | 19 +++ helm-charts/charts/kube-starrocks/values.yaml | 19 +++ pkg/apis/starrocks/v1/component_type.go | 44 ++++++- pkg/apis/starrocks/v1/component_type_test.go | 69 +++++++++++ pkg/apis/starrocks/v1/load_type.go | 3 + .../starrocks/v1/starrockscluster_types.go | 7 ++ .../starrocks/v1/zz_generated.deepcopy.go | 6 + pkg/k8sutils/templates/statefulset/spec.go | 9 +- .../templates/statefulset/spec_test.go | 49 ++++++++ pkg/subcontrollers/be/be_controller.go | 3 + pkg/subcontrollers/cn/cn_controller.go | 4 + pkg/subcontrollers/fe/fe_controller.go | 7 +- 17 files changed, 463 insertions(+), 11 deletions(-) create mode 100644 pkg/apis/starrocks/v1/component_type_test.go diff --git a/config/crd/bases/starrocks.com_starrocksclusters.yaml b/config/crd/bases/starrocks.com_starrocksclusters.yaml index a8247b56..15894e68 100644 --- a/config/crd/bases/starrocks.com_starrocksclusters.yaml +++ b/config/crd/bases/starrocks.com_starrocksclusters.yaml @@ -4362,6 +4362,45 @@ spec: - whenUnsatisfiable type: object type: array + updateStrategy: + description: |- + updateStrategy indicates the StatefulSetUpdateStrategy that will be + employed to update Pods in the StatefulSet when a revision is made to + Template. StarRocksCluster use StatefulSet to deploy FE/BE/CN components. + see https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#rolling-updates for more details. + properties: + rollingUpdate: + description: RollingUpdate is used to communicate parameters + when Type is RollingUpdateStatefulSetStrategyType. + 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%). + 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. + x-kubernetes-int-or-string: true + partition: + 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 + type: object + type: + description: |- + Type indicates the type of the StatefulSetUpdateStrategy. + Default is RollingUpdate. + type: string + type: object type: object starRocksCnSpec: description: StarRocksCnSpec define cn configuration for start cn @@ -9283,6 +9322,45 @@ spec: - whenUnsatisfiable type: object type: array + updateStrategy: + description: |- + updateStrategy indicates the StatefulSetUpdateStrategy that will be + employed to update Pods in the StatefulSet when a revision is made to + Template. StarRocksCluster use StatefulSet to deploy FE/BE/CN components. + see https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#rolling-updates for more details. + properties: + rollingUpdate: + description: RollingUpdate is used to communicate parameters + when Type is RollingUpdateStatefulSetStrategyType. + 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%). + 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. + x-kubernetes-int-or-string: true + partition: + 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 + type: object + type: + description: |- + Type indicates the type of the StatefulSetUpdateStrategy. + Default is RollingUpdate. + type: string + type: object type: object starRocksFeProxySpec: description: StarRocksLoadSpec define a proxy for fe. @@ -15074,6 +15152,45 @@ spec: - whenUnsatisfiable type: object type: array + updateStrategy: + description: |- + updateStrategy indicates the StatefulSetUpdateStrategy that will be + employed to update Pods in the StatefulSet when a revision is made to + Template. StarRocksCluster use StatefulSet to deploy FE/BE/CN components. + see https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#rolling-updates for more details. + properties: + rollingUpdate: + description: RollingUpdate is used to communicate parameters + when Type is RollingUpdateStatefulSetStrategyType. + 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%). + 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. + x-kubernetes-int-or-string: true + partition: + 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 + type: object + type: + description: |- + Type indicates the type of the StatefulSetUpdateStrategy. + Default is RollingUpdate. + type: string + type: object type: object type: object status: diff --git a/config/crd/bases/starrocks.com_starrockswarehouses.yaml b/config/crd/bases/starrocks.com_starrockswarehouses.yaml index f779fe4b..e9b5d301 100644 --- a/config/crd/bases/starrocks.com_starrockswarehouses.yaml +++ b/config/crd/bases/starrocks.com_starrockswarehouses.yaml @@ -4973,6 +4973,45 @@ spec: - whenUnsatisfiable type: object type: array + updateStrategy: + description: |- + updateStrategy indicates the StatefulSetUpdateStrategy that will be + employed to update Pods in the StatefulSet when a revision is made to + Template. StarRocksCluster use StatefulSet to deploy FE/BE/CN components. + see https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#rolling-updates for more details. + properties: + rollingUpdate: + description: RollingUpdate is used to communicate parameters + when Type is RollingUpdateStatefulSetStrategyType. + 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%). + 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. + x-kubernetes-int-or-string: true + partition: + 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 + type: object + type: + description: |- + Type indicates the type of the StatefulSetUpdateStrategy. + Default is RollingUpdate. + type: string + type: object type: object required: - starRocksCluster diff --git a/deploy/starrocks.com_starrocksclusters.yaml b/deploy/starrocks.com_starrocksclusters.yaml index df1a45af..d9f43e4d 100644 --- a/deploy/starrocks.com_starrocksclusters.yaml +++ b/deploy/starrocks.com_starrocksclusters.yaml @@ -2052,6 +2052,22 @@ spec: - whenUnsatisfiable type: object type: array + updateStrategy: + properties: + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object + type: + type: string + type: object type: object starRocksCnSpec: properties: @@ -4389,6 +4405,22 @@ spec: - whenUnsatisfiable type: object type: array + updateStrategy: + properties: + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object + type: + type: string + type: object type: object starRocksFeProxySpec: properties: @@ -7072,6 +7104,22 @@ spec: - whenUnsatisfiable type: object type: array + updateStrategy: + properties: + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object + type: + type: string + type: object type: object type: object status: diff --git a/deploy/starrocks.com_starrockswarehouses.yaml b/deploy/starrocks.com_starrockswarehouses.yaml index 1e0cb216..0e3e776e 100644 --- a/deploy/starrocks.com_starrockswarehouses.yaml +++ b/deploy/starrocks.com_starrockswarehouses.yaml @@ -2374,6 +2374,22 @@ spec: - whenUnsatisfiable type: object type: array + updateStrategy: + properties: + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object + type: + type: string + type: object type: object required: - starRocksCluster diff --git a/helm-charts/charts/kube-starrocks/charts/starrocks/templates/starrockscluster.yaml b/helm-charts/charts/kube-starrocks/charts/starrocks/templates/starrockscluster.yaml index efffa20d..2a7dcb90 100644 --- a/helm-charts/charts/kube-starrocks/charts/starrocks/templates/starrockscluster.yaml +++ b/helm-charts/charts/kube-starrocks/charts/starrocks/templates/starrockscluster.yaml @@ -24,6 +24,11 @@ spec: {{- end }} replicas: {{ .Values.starrocksFESpec.replicas }} imagePullPolicy: {{ .Values.starrocksFESpec.imagePullPolicy }} + {{- if .Values.starrocksFESpec.maxUnavailablePods }} + updateStrategy: + rollingUpdate: + maxUnavailable: "{{ .Values.starrocksFESpec.maxUnavailablePods }}" + {{- end }} {{- /* support both resources and resource for backward compatibility */}} @@ -252,6 +257,11 @@ spec: {{- end }} replicas: {{ .Values.starrocksBeSpec.replicas }} imagePullPolicy: {{ .Values.starrocksBeSpec.imagePullPolicy }} + {{- if .Values.starrocksBeSpec.maxUnavailablePods }} + updateStrategy: + rollingUpdate: + maxUnavailable: "{{ .Values.starrocksBeSpec.maxUnavailablePods }}" + {{-end }} {{- /* support both resources and resource for backward compatibility */}} @@ -512,6 +522,11 @@ spec: replicas: {{ .Values.starrocksCnSpec.replicas }} {{- end }} imagePullPolicy: {{ .Values.starrocksCnSpec.imagePullPolicy }} + {{- if .Values.starrocksCnSpec.maxUnavailablePods }} + updateStrategy: + rollingUpdate: + maxUnavailable: "{{ .Values.starrocksCnSpec.maxUnavailablePods }}" + {{-end }} {{- if or .Values.starrocksCnSpec.serviceAccount .Values.starrocksCluster.componentValues.serviceAccount }} serviceAccount: {{ include "starrockscluster.cn.serviceAccount" . }} {{- end }} diff --git a/helm-charts/charts/kube-starrocks/charts/starrocks/values.yaml b/helm-charts/charts/kube-starrocks/charts/starrocks/values.yaml index 483b4664..03320245 100644 --- a/helm-charts/charts/kube-starrocks/charts/starrocks/values.yaml +++ b/helm-charts/charts/kube-starrocks/charts/starrocks/values.yaml @@ -382,6 +382,13 @@ starrocksFESpec: # volumeMounts: # - mountPath: /opt/starrocks/fe/meta # name: fe-meta # append -meta to the end of the name of the starrocksFESpec.storageSpec.name + # Max unavailable pods for the fe component when doing rolling update. + # This field cannot be 0. The default setting is 1. + # Note: Because Operator uses statefulset to manage this component, the maxUnavailable field is in Alpha stage, and it is honored + # only by API servers that are running with the MaxUnavailableStatefulSet feature gate enabled. + # See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#maximum-unavailable-pods for more details. + maxUnavailablePods: + # spec for compute node, compute node provide compute function. starrocksCnSpec: @@ -683,6 +690,12 @@ starrocksCnSpec: # volumeMounts: # - mountPath: /opt/starrocks/cn/storage # name: cn-data # append -data to the end of the name of the starrocksCnSpec.storageSpec.name + # Max unavailable pods for the fe component when doing rolling update. + # This field cannot be 0. The default setting is 1. + # Note: Because Operator uses statefulset to manage this component, the maxUnavailable field is in Alpha stage, and it is honored + # only by API servers that are running with the MaxUnavailableStatefulSet feature gate enabled. + # See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#maximum-unavailable-pods for more details. + maxUnavailablePods: # spec for component be, provide storage and compute function. starrocksBeSpec: @@ -946,6 +959,12 @@ starrocksBeSpec: # volumeMounts: # - mountPath: /opt/starrocks/be/storage # name: be-data # append -data to the end of the name of the starrocksBeSpec.storageSpec.name + # Max unavailable pods for the fe component when doing rolling update. + # This field cannot be 0. The default setting is 1. + # Note: Because Operator uses statefulset to manage this component, the maxUnavailable field is in Alpha stage, and it is honored + # only by API servers that are running with the MaxUnavailableStatefulSet feature gate enabled. + # See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#maximum-unavailable-pods for more details. + maxUnavailablePods: # create secrets if necessary. secrets: [] diff --git a/helm-charts/charts/kube-starrocks/values.yaml b/helm-charts/charts/kube-starrocks/values.yaml index 86146cea..2906a4bf 100644 --- a/helm-charts/charts/kube-starrocks/values.yaml +++ b/helm-charts/charts/kube-starrocks/values.yaml @@ -490,6 +490,13 @@ starrocks: # volumeMounts: # - mountPath: /opt/starrocks/fe/meta # name: fe-meta # append -meta to the end of the name of the starrocksFESpec.storageSpec.name + # Max unavailable pods for the fe component when doing rolling update. + # This field cannot be 0. The default setting is 1. + # Note: Because Operator uses statefulset to manage this component, the maxUnavailable field is in Alpha stage, and it is honored + # only by API servers that are running with the MaxUnavailableStatefulSet feature gate enabled. + # See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#maximum-unavailable-pods for more details. + maxUnavailablePods: + # spec for compute node, compute node provide compute function. starrocksCnSpec: @@ -791,6 +798,12 @@ starrocks: # volumeMounts: # - mountPath: /opt/starrocks/cn/storage # name: cn-data # append -data to the end of the name of the starrocksCnSpec.storageSpec.name + # Max unavailable pods for the fe component when doing rolling update. + # This field cannot be 0. The default setting is 1. + # Note: Because Operator uses statefulset to manage this component, the maxUnavailable field is in Alpha stage, and it is honored + # only by API servers that are running with the MaxUnavailableStatefulSet feature gate enabled. + # See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#maximum-unavailable-pods for more details. + maxUnavailablePods: # spec for component be, provide storage and compute function. starrocksBeSpec: @@ -1054,6 +1067,12 @@ starrocks: # volumeMounts: # - mountPath: /opt/starrocks/be/storage # name: be-data # append -data to the end of the name of the starrocksBeSpec.storageSpec.name + # Max unavailable pods for the fe component when doing rolling update. + # This field cannot be 0. The default setting is 1. + # Note: Because Operator uses statefulset to manage this component, the maxUnavailable field is in Alpha stage, and it is honored + # only by API servers that are running with the MaxUnavailableStatefulSet feature gate enabled. + # See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#maximum-unavailable-pods for more details. + maxUnavailablePods: # create secrets if necessary. secrets: [] diff --git a/pkg/apis/starrocks/v1/component_type.go b/pkg/apis/starrocks/v1/component_type.go index 72092bcb..876f6daf 100644 --- a/pkg/apis/starrocks/v1/component_type.go +++ b/pkg/apis/starrocks/v1/component_type.go @@ -16,7 +16,13 @@ package v1 -import corev1 "k8s.io/api/core/v1" +import ( + "errors" + "strings" + + appv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" +) type StarRocksComponentSpec struct { StarRocksLoadSpec `json:",inline"` @@ -85,6 +91,13 @@ type StarRocksComponentSpec struct { // More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell // +optional Args []string `json:"args,omitempty"` + + // updateStrategy indicates the StatefulSetUpdateStrategy that will be + // employed to update Pods in the StatefulSet when a revision is made to + // Template. StarRocksCluster use StatefulSet to deploy FE/BE/CN components. + // see https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#rolling-updates for more details. + // +optional + UpdateStrategy *appv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"` } // StarRocksComponentStatus represents the status of a starrocks component. @@ -190,3 +203,32 @@ func (spec *StarRocksComponentSpec) GetCommand() []string { func (spec *StarRocksComponentSpec) GetArgs() []string { return spec.Args } + +func (spec *StarRocksComponentSpec) GetUpdateStrategy() *appv1.StatefulSetUpdateStrategy { + if spec.UpdateStrategy == nil { + const defaultRollingUpdateStartPod int32 = 0 + return &appv1.StatefulSetUpdateStrategy{ + Type: appv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appv1.RollingUpdateStatefulSetStrategy{ + Partition: func(v int32) *int32 { return &v }(defaultRollingUpdateStartPod), + }, + } + } + return spec.UpdateStrategy +} + +func ValidUpdateStrategy(updateStrategy *appv1.StatefulSetUpdateStrategy) error { + if updateStrategy != nil { + if (updateStrategy.Type == "" || updateStrategy.Type == appv1.RollingUpdateStatefulSetStrategyType) && + updateStrategy.RollingUpdate != nil { + rollingUpdate := updateStrategy.RollingUpdate + if rollingUpdate.MaxUnavailable != nil { + s := rollingUpdate.MaxUnavailable.String() + if strings.HasPrefix(s, "0") { + return errors.New("maxUnavailable field should > 0") + } + } + } + } + return nil +} diff --git a/pkg/apis/starrocks/v1/component_type_test.go b/pkg/apis/starrocks/v1/component_type_test.go new file mode 100644 index 00000000..ec9a3be7 --- /dev/null +++ b/pkg/apis/starrocks/v1/component_type_test.go @@ -0,0 +1,69 @@ +package v1 + +import ( + "testing" + + appv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +func TestValidUpdateStrategy(t *testing.T) { + type args struct { + updateStrategy *appv1.StatefulSetUpdateStrategy + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Validating update strategy with valid max unavailable", + args: args{ + updateStrategy: &appv1.StatefulSetUpdateStrategy{ + RollingUpdate: &appv1.RollingUpdateStatefulSetStrategy{ + MaxUnavailable: func() *intstr.IntOrString { + i := intstr.FromInt(1) + return &i + }(), + }, + }, + }, + wantErr: false, + }, + { + name: "Validating update strategy with max unavailable 0", + args: args{ + updateStrategy: &appv1.StatefulSetUpdateStrategy{ + RollingUpdate: &appv1.RollingUpdateStatefulSetStrategy{ + MaxUnavailable: func() *intstr.IntOrString { + i := intstr.FromInt(0) + return &i + }(), + }, + }, + }, + wantErr: true, + }, + { + name: "Validating update strategy with max unavailable 0%", + args: args{ + updateStrategy: &appv1.StatefulSetUpdateStrategy{ + RollingUpdate: &appv1.RollingUpdateStatefulSetStrategy{ + MaxUnavailable: func() *intstr.IntOrString { + i := intstr.FromString("0%") + return &i + }(), + }, + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidUpdateStrategy(tt.args.updateStrategy); (err != nil) != tt.wantErr { + t.Errorf("ValidUpdateStrategy() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/pkg/apis/starrocks/v1/load_type.go b/pkg/apis/starrocks/v1/load_type.go index 07f06a22..f4c326c8 100644 --- a/pkg/apis/starrocks/v1/load_type.go +++ b/pkg/apis/starrocks/v1/load_type.go @@ -1,6 +1,7 @@ package v1 import ( + appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" ) @@ -17,7 +18,9 @@ type loadInterface interface { GetStartupProbeFailureSeconds() *int32 GetLivenessProbeFailureSeconds() *int32 GetReadinessProbeFailureSeconds() *int32 + GetLifecycle() *corev1.Lifecycle GetService() *StarRocksService + GetUpdateStrategy() *appv1.StatefulSetUpdateStrategy GetStorageVolumes() []StorageVolume GetServiceAccount() string diff --git a/pkg/apis/starrocks/v1/starrockscluster_types.go b/pkg/apis/starrocks/v1/starrockscluster_types.go index cb5fe1a7..7646cc37 100644 --- a/pkg/apis/starrocks/v1/starrockscluster_types.go +++ b/pkg/apis/starrocks/v1/starrockscluster_types.go @@ -19,6 +19,7 @@ package v1 import ( "errors" + appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -229,6 +230,12 @@ func (spec *StarRocksFeProxySpec) GetArgs() []string { return nil } +// GetUpdateStrategy +// fe proxy is deployed by deployment, and it does not have field UpdateStrategy +func (spec *StarRocksFeProxySpec) GetUpdateStrategy() *appv1.StatefulSetUpdateStrategy { + return nil +} + // Phase is defined under status, e.g. // 1. StarRocksClusterStatus.Phase represents the phase of starrocks cluster. // 2. StarRocksWarehouseStatus.Phase represents the phase of starrocks warehouse. diff --git a/pkg/apis/starrocks/v1/zz_generated.deepcopy.go b/pkg/apis/starrocks/v1/zz_generated.deepcopy.go index 97e55f56..a6a888c6 100644 --- a/pkg/apis/starrocks/v1/zz_generated.deepcopy.go +++ b/pkg/apis/starrocks/v1/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1 import ( + appsv1 "k8s.io/api/apps/v1" "k8s.io/api/autoscaling/v2beta2" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" @@ -426,6 +427,11 @@ func (in *StarRocksComponentSpec) DeepCopyInto(out *StarRocksComponentSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.UpdateStrategy != nil { + in, out := &in.UpdateStrategy, &out.UpdateStrategy + *out = new(appsv1.StatefulSetUpdateStrategy) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StarRocksComponentSpec. diff --git a/pkg/k8sutils/templates/statefulset/spec.go b/pkg/k8sutils/templates/statefulset/spec.go index 632f873f..f9f44e5c 100644 --- a/pkg/k8sutils/templates/statefulset/spec.go +++ b/pkg/k8sutils/templates/statefulset/spec.go @@ -23,7 +23,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "github.com/StarRocks/starrocks-kubernetes-operator/pkg/apis/starrocks/v1" - rutils "github.com/StarRocks/starrocks-kubernetes-operator/pkg/common/resource_utils" "github.com/StarRocks/starrocks-kubernetes-operator/pkg/k8sutils/load" srobject "github.com/StarRocks/starrocks-kubernetes-operator/pkg/k8sutils/templates/object" "github.com/StarRocks/starrocks-kubernetes-operator/pkg/k8sutils/templates/pod" @@ -64,7 +63,6 @@ func PVCList(volumes []v1.StorageVolume) []corev1.PersistentVolumeClaim { // MakeStatefulset make statefulset func MakeStatefulset(object srobject.StarRocksObject, spec v1.SpecInterface, podTemplateSpec *corev1.PodTemplateSpec) appv1.StatefulSet { - const defaultRollingUpdateStartPod int32 = 0 // TODO: statefulset only allow update 'replicas', 'template', 'updateStrategy' or := metav1.NewControllerRef(object, object.GroupVersionKind()) st := appv1.StatefulSet{ @@ -80,12 +78,7 @@ func MakeStatefulset(object srobject.StarRocksObject, spec v1.SpecInterface, pod Selector: &metav1.LabelSelector{ MatchLabels: load.Selector(object.AliasName, spec), }, - UpdateStrategy: appv1.StatefulSetUpdateStrategy{ - Type: appv1.RollingUpdateStatefulSetStrategyType, - RollingUpdate: &appv1.RollingUpdateStatefulSetStrategy{ - Partition: rutils.GetInt32Pointer(defaultRollingUpdateStartPod), - }, - }, + UpdateStrategy: *spec.GetUpdateStrategy(), Template: *podTemplateSpec, ServiceName: service.SearchServiceName(object.AliasName, spec), VolumeClaimTemplates: PVCList(spec.GetStorageVolumes()), diff --git a/pkg/k8sutils/templates/statefulset/spec_test.go b/pkg/k8sutils/templates/statefulset/spec_test.go index 6828ce26..c98cd453 100644 --- a/pkg/k8sutils/templates/statefulset/spec_test.go +++ b/pkg/k8sutils/templates/statefulset/spec_test.go @@ -22,6 +22,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" v1 "github.com/StarRocks/starrocks-kubernetes-operator/pkg/apis/starrocks/v1" "github.com/StarRocks/starrocks-kubernetes-operator/pkg/common/resource_utils" @@ -168,6 +169,54 @@ func TestMakeStatefulset(t *testing.T) { }, }, }, + { + name: "test Statefulset with updateStrategy", + args: args{ + cluster: cluster, + spec: &v1.StarRocksFeSpec{ + StarRocksComponentSpec: v1.StarRocksComponentSpec{ + StarRocksLoadSpec: v1.StarRocksLoadSpec{ + Replicas: &replicas, + }, + UpdateStrategy: &appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + MaxUnavailable: func() *intstr.IntOrString { i := intstr.FromInt(3); return &i }(), + }, + }, + }, + }, + }, + want: appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-fe", + Namespace: "namespace", + Labels: map[string]string{ + "app.starrocks.ownerreference/name": "test", + "app.kubernetes.io/component": "fe", + }, + Annotations: map[string]string{}, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &replicas, + Template: corev1.PodTemplateSpec{}, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/component": "fe", + "app.starrocks.ownerreference/name": "test-fe", + }, + }, + ServiceName: "test-fe-search", + PodManagementPolicy: appsv1.ParallelPodManagement, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + MaxUnavailable: func() *intstr.IntOrString { i := intstr.FromInt(3); return &i }(), + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/subcontrollers/be/be_controller.go b/pkg/subcontrollers/be/be_controller.go index 78fe7d48..a4f9cd6e 100644 --- a/pkg/subcontrollers/be/be_controller.go +++ b/pkg/subcontrollers/be/be_controller.go @@ -251,5 +251,8 @@ func (be *BeController) validating(beSpec *srapi.StarRocksBeSpec) error { return err } } + if err := srapi.ValidUpdateStrategy(beSpec.UpdateStrategy); err != nil { + return err + } return nil } diff --git a/pkg/subcontrollers/cn/cn_controller.go b/pkg/subcontrollers/cn/cn_controller.go index d9ccd045..6a49f99e 100644 --- a/pkg/subcontrollers/cn/cn_controller.go +++ b/pkg/subcontrollers/cn/cn_controller.go @@ -477,6 +477,10 @@ func (cc *CnController) validating(cnSpec *srapi.StarRocksCnSpec) error { } } + if err := srapi.ValidUpdateStrategy(cnSpec.UpdateStrategy); err != nil { + return err + } + return nil } diff --git a/pkg/subcontrollers/fe/fe_controller.go b/pkg/subcontrollers/fe/fe_controller.go index 6ff0e7a4..4b19823e 100644 --- a/pkg/subcontrollers/fe/fe_controller.go +++ b/pkg/subcontrollers/fe/fe_controller.go @@ -76,7 +76,7 @@ func (fc *FeController) SyncCluster(ctx context.Context, src *srapi.StarRocksClu }() feSpec := src.Spec.StarRocksFeSpec - if err = fc.validating(feSpec); err != nil { + if err = fc.Validating(feSpec); err != nil { return err } @@ -207,12 +207,15 @@ func (fc *FeController) ClearResources(ctx context.Context, src *srapi.StarRocks return nil } -func (fc *FeController) validating(feSpec *srapi.StarRocksFeSpec) error { +func (fc *FeController) Validating(feSpec *srapi.StarRocksFeSpec) error { for i := range feSpec.StorageVolumes { if err := feSpec.StorageVolumes[i].Validate(); err != nil { return err } } + if err := srapi.ValidUpdateStrategy(feSpec.UpdateStrategy); err != nil { + return err + } return nil }