diff --git a/apis/v1alpha1/defaulting.go b/apis/v1alpha1/defaulting.go index be01992..9e41119 100644 --- a/apis/v1alpha1/defaulting.go +++ b/apis/v1alpha1/defaulting.go @@ -15,9 +15,11 @@ package v1alpha1 import ( + "reflect" "strings" "dario.cat/mergo" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/util/intstr" @@ -34,7 +36,7 @@ func (in *GreptimeDBCluster) SetDefaults() error { in.Spec.Version = getVersionFromImage(in.GetBaseMainContainer().GetImage()) // Merge the default settings into the GreptimeDBClusterSpec. - if err := mergo.Merge(&in.Spec, in.defaultSpec()); err != nil { + if err := mergo.Merge(&in.Spec, in.defaultSpec(), mergo.WithTransformers(intOrStringTransformer{})); err != nil { return err } @@ -171,6 +173,7 @@ func (in *GreptimeDBCluster) defaultFrontend() *FrontendSpec { Service: &ServiceSpec{ Type: corev1.ServiceTypeClusterIP, }, + RollingUpdate: defaultRollingUpdateForDeployment(), } } @@ -188,6 +191,7 @@ func (in *GreptimeDBCluster) defaultMeta() *MetaSpec { RPCPort: DefaultMetaRPCPort, HTTPPort: DefaultHTTPPort, EnableRegionFailover: &enableRegionFailover, + RollingUpdate: defaultRollingUpdateForDeployment(), } } @@ -198,9 +202,10 @@ func (in *GreptimeDBCluster) defaultDatanode() *DatanodeSpec { Replicas: pointer.Int32(DefaultReplicas), Logging: &LoggingSpec{}, }, - RPCPort: DefaultRPCPort, - HTTPPort: DefaultHTTPPort, - Storage: defaultDatanodeStorage(), + RPCPort: DefaultRPCPort, + HTTPPort: DefaultHTTPPort, + Storage: defaultDatanodeStorage(), + RollingUpdate: defaultRollingUpdateForStatefulSet(), } } @@ -312,7 +317,7 @@ func (in *GreptimeDBStandalone) SetDefaults() error { in.Spec.Version = getVersionFromImage(in.GetBaseMainContainer().GetImage()) - if err := mergo.Merge(&in.Spec, in.defaultSpec()); err != nil { + if err := mergo.Merge(&in.Spec, in.defaultSpec(), mergo.WithTransformers(intOrStringTransformer{})); err != nil { return err } @@ -344,6 +349,7 @@ func (in *GreptimeDBStandalone) defaultSpec() *GreptimeDBStandaloneSpec { OnlyLogToStdout: pointer.Bool(false), }, DatanodeStorage: defaultDatanodeStorage(), + RollingUpdate: defaultRollingUpdateForStatefulSet(), } return defaultSpec @@ -427,3 +433,58 @@ func defaultReadinessProbe() *corev1.Probe { FailureThreshold: 10, } } + +// Same as the default rolling update strategy of Deployment. +func defaultRollingUpdateForDeployment() *appsv1.RollingUpdateDeployment { + return &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"}, + MaxSurge: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"}, + } +} + +// Same as the default rolling update strategy of StatefulSet. +func defaultRollingUpdateForStatefulSet() *appsv1.RollingUpdateStatefulSetStrategy { + return &appsv1.RollingUpdateStatefulSetStrategy{ + Partition: pointer.Int32(0), + MaxUnavailable: &intstr.IntOrString{ + Type: intstr.Int, + IntVal: 1, + }, + } +} + +// This transformer handles merging of intstr.IntOrString values. +// The `Type` field in IntOrString is an int starting from 0, which means it would be considered "empty" during merging and get overwritten. +// We want to preserve the original Type of the destination value while only merging the actual int/string content. +type intOrStringTransformer struct{} + +func (t intOrStringTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error { + if typ != reflect.TypeOf(&intstr.IntOrString{}) { + return nil + } + + return func(dst, src reflect.Value) error { + if dst.IsNil() || src.IsNil() { + return nil + } + + dstVal, srcVal := dst.Interface().(*intstr.IntOrString), src.Interface().(*intstr.IntOrString) + + // Don't override the type of dst. + if dstVal.Type == intstr.Int { + if dstVal.IntVal == 0 { + dstVal.IntVal = srcVal.IntVal + } + dstVal.StrVal = "" + } + + if dstVal.Type == intstr.String { + if dstVal.StrVal == "" { + dstVal.StrVal = srcVal.StrVal + } + dstVal.IntVal = 0 + } + + return nil + } +} diff --git a/apis/v1alpha1/defaulting_test.go b/apis/v1alpha1/defaulting_test.go index cf9d97f..f12d494 100644 --- a/apis/v1alpha1/defaulting_test.go +++ b/apis/v1alpha1/defaulting_test.go @@ -20,7 +20,9 @@ import ( "reflect" "testing" + "dario.cat/mergo" "github.com/sergi/go-diff/diffmatchpatch" + "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/yaml" ) @@ -211,3 +213,47 @@ func TestStandaloneSetDefaults(t *testing.T) { } } } + +func TestIntOrStringTransformer(t *testing.T) { + type foo struct { + Val *intstr.IntOrString + } + type testStruct struct { + Src foo + Dst foo + Expect foo + } + + tests := []testStruct{ + { + Src: foo{Val: &intstr.IntOrString{Type: intstr.String, StrVal: "1"}}, + Dst: foo{Val: &intstr.IntOrString{Type: intstr.Int, IntVal: 10}}, + Expect: foo{Val: &intstr.IntOrString{Type: intstr.Int, IntVal: 10}}, + }, + { + Src: foo{Val: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"}}, + Dst: foo{Val: &intstr.IntOrString{Type: intstr.String, StrVal: "75%"}}, + Expect: foo{Val: &intstr.IntOrString{Type: intstr.String, StrVal: "75%"}}, + }, + { + Src: foo{Val: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"}}, + Dst: foo{}, + Expect: foo{Val: &intstr.IntOrString{Type: intstr.String, StrVal: "25%"}}, + }, + { + Src: foo{Val: &intstr.IntOrString{Type: intstr.Int, IntVal: 10}}, + Dst: foo{}, + Expect: foo{Val: &intstr.IntOrString{Type: intstr.Int, IntVal: 10}}, + }, + } + + for i, tt := range tests { + if err := mergo.Merge(&tt.Dst, &tt.Src, mergo.WithTransformers(intOrStringTransformer{})); err != nil { + t.Errorf("test [%d] failed: %v", i, err) + } + + if !reflect.DeepEqual(tt.Dst, tt.Expect) { + t.Errorf("test [%d] failed: expected '%v', got '%v'", i, tt.Expect, tt.Dst) + } + } +} diff --git a/apis/v1alpha1/greptimedbcluster_types.go b/apis/v1alpha1/greptimedbcluster_types.go index 9ef7666..8850211 100644 --- a/apis/v1alpha1/greptimedbcluster_types.go +++ b/apis/v1alpha1/greptimedbcluster_types.go @@ -15,6 +15,7 @@ package v1alpha1 import ( + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -70,6 +71,10 @@ type MetaSpec struct { // StoreKeyPrefix is the prefix of the key in the etcd. We can use it to isolate the data of different clusters. // +optional StoreKeyPrefix string `json:"storeKeyPrefix,omitempty"` + + // RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategyt. + // +optional + RollingUpdate *appsv1.RollingUpdateDeployment `json:"rollingUpdate,omitempty"` } func (in *MetaSpec) GetConfig() string { @@ -143,6 +148,10 @@ type FrontendSpec struct { // TLS is the TLS configuration of the frontend. // +optional TLS *TLSSpec `json:"tls,omitempty"` + + // RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategyt. + // +optional + RollingUpdate *appsv1.RollingUpdateDeployment `json:"rollingUpdate,omitempty"` } func (in *FrontendSpec) GetTLS() *TLSSpec { @@ -192,6 +201,10 @@ type DatanodeSpec struct { // Storage is the default file storage of the datanode. For example, WAL, cache, index etc. // +optional Storage *DatanodeStorageSpec `json:"storage,omitempty"` + + // RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategy. + // +optional + RollingUpdate *appsv1.RollingUpdateStatefulSetStrategy `json:"rollingUpdate,omitempty"` } func (in *DatanodeSpec) GetConfig() string { @@ -231,6 +244,10 @@ type FlownodeSpec struct { // +kubebuilder:validation:Maximum=65535 // +optional RPCPort int32 `json:"rpcPort,omitempty"` + + // RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategy. + // +optional + RollingUpdate *appsv1.RollingUpdateStatefulSetStrategy `json:"rollingUpdate,omitempty"` } func (in *FlownodeSpec) GetConfig() string { diff --git a/apis/v1alpha1/greptimedbstandalone_types.go b/apis/v1alpha1/greptimedbstandalone_types.go index 81b1686..4b61035 100644 --- a/apis/v1alpha1/greptimedbstandalone_types.go +++ b/apis/v1alpha1/greptimedbstandalone_types.go @@ -15,6 +15,7 @@ package v1alpha1 import ( + appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -87,6 +88,10 @@ type GreptimeDBStandaloneSpec struct { // Logging defines the logging configuration for the component. // +optional Logging *LoggingSpec `json:"logging,omitempty"` + + // RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategy. + // +optional + RollingUpdate *appsv1.RollingUpdateStatefulSetStrategy `json:"rollingUpdate,omitempty"` } // GreptimeDBStandaloneStatus defines the observed state of GreptimeDBStandalone diff --git a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/merge/test00/expect.yaml b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/merge/test00/expect.yaml index a2075c9..e575d99 100644 --- a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/merge/test00/expect.yaml +++ b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/merge/test00/expect.yaml @@ -59,6 +59,9 @@ spec: logsDir: /data/greptimedb/logs onlyLogToStdout: false persistentWithData: false + rollingUpdate: + maxUnavailable: 1 + maxSurge: 2 template: main: image: greptime/greptimedb:test @@ -100,6 +103,9 @@ spec: logsDir: /data/greptimedb/logs onlyLogToStdout: false persistentWithData: false + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% template: main: image: greptime/greptimedb:latest @@ -145,6 +151,9 @@ spec: logsDir: /data/greptimedb/logs onlyLogToStdout: false persistentWithData: false + rollingUpdate: + maxUnavailable: 25% + partition: 1 template: main: image: greptime/greptimedb:latest diff --git a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/merge/test00/input.yaml b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/merge/test00/input.yaml index 2de7752..bd3d423 100644 --- a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/merge/test00/input.yaml +++ b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/merge/test00/input.yaml @@ -20,6 +20,9 @@ spec: template: main: image: greptime/greptimedb:test + rollingUpdate: + maxUnavailable: 1 + maxSurge: 2 meta: etcdEndpoints: - etcd.etcd-cluster.svc.cluster.local:2379 @@ -37,4 +40,7 @@ spec: replicas: 3 logging: level: debug + rollingUpdate: + partition: 1 + maxUnavailable: 25% httpPort: 5000 diff --git a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test00/expect.yaml b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test00/expect.yaml index c7b9d03..803d408 100644 --- a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test00/expect.yaml +++ b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test00/expect.yaml @@ -48,6 +48,9 @@ spec: type: ClusterIP logging: {} template: {} + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% meta: etcdEndpoints: - etcd.etcd-cluster.svc.cluster.local:2379 @@ -57,6 +60,9 @@ spec: replicas: 1 logging: {} template: {} + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% datanode: httpPort: 4000 rpcPort: 4001 @@ -70,3 +76,6 @@ spec: storageSize: 10Gi logging: {} template: {} + rollingUpdate: + maxUnavailable: 1 + partition: 0 diff --git a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test01/expect.yaml b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test01/expect.yaml index 8c64033..87b1340 100644 --- a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test01/expect.yaml +++ b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test01/expect.yaml @@ -60,6 +60,9 @@ spec: args: - --metasrv-addrs - meta.default:3002 + rollingUpdate: + maxUnavailable: 25% + maxSurge: 25% meta: enableRegionFailover: false etcdEndpoints: @@ -74,6 +77,9 @@ spec: args: - --store-addr - etcd.default:2379 + rollingUpdate: + maxUnavailable: 25% + maxSurge: 25% datanode: httpPort: 4000 rpcPort: 4001 @@ -89,3 +95,6 @@ spec: template: main: image: greptime/greptimedb:latest + rollingUpdate: + maxUnavailable: 1 + partition: 0 diff --git a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test02/expect.yaml b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test02/expect.yaml index c9a5c1b..be3f1ca 100644 --- a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test02/expect.yaml +++ b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test02/expect.yaml @@ -59,6 +59,9 @@ spec: type: ClusterIP logging: {} template: {} + rollingUpdate: + maxUnavailable: 25% + maxSurge: 25% meta: etcdEndpoints: - etcd.etcd-cluster.svc.cluster.local:2379 @@ -69,6 +72,9 @@ spec: rpcPort: 3002 replicas: 1 template: {} + rollingUpdate: + maxUnavailable: 25% + maxSurge: 25% datanode: httpPort: 4000 rpcPort: 4001 @@ -82,3 +88,6 @@ spec: storageRetainPolicy: Retain storageSize: 10Gi template: {} + rollingUpdate: + maxUnavailable: 1 + partition: 0 diff --git a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test03/expect.yaml b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test03/expect.yaml index a901178..1660311 100644 --- a/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test03/expect.yaml +++ b/apis/v1alpha1/testdata/defaulting/greptimedbcluster/setdefaults/test03/expect.yaml @@ -59,6 +59,9 @@ spec: type: ClusterIP logging: {} template: {} + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% meta: etcdEndpoints: - etcd.etcd-cluster.svc.cluster.local:2379 @@ -69,6 +72,9 @@ spec: replicas: 1 logging: {} template: {} + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% datanode: httpPort: 4000 rpcPort: 4001 @@ -82,6 +88,9 @@ spec: storageSize: 10Gi logging: {} template: {} + rollingUpdate: + maxUnavailable: 1 + partition: 0 monitoring: enabled: true logsCollection: {} @@ -127,6 +136,9 @@ spec: service: type: ClusterIP version: latest + rollingUpdate: + maxUnavailable: 1 + partition: 0 vector: image: timberio/vector:nightly-alpine resources: diff --git a/apis/v1alpha1/testdata/defaulting/greptimedbstandalone/test00/expect.yaml b/apis/v1alpha1/testdata/defaulting/greptimedbstandalone/test00/expect.yaml index cab06ce..3416ae0 100644 --- a/apis/v1alpha1/testdata/defaulting/greptimedbstandalone/test00/expect.yaml +++ b/apis/v1alpha1/testdata/defaulting/greptimedbstandalone/test00/expect.yaml @@ -45,3 +45,6 @@ spec: mountPath: /data/greptimedb storageRetainPolicy: Retain storageSize: 10Gi + rollingUpdate: + maxUnavailable: 1 + partition: 0 diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go index 60fea66..a374937 100644 --- a/apis/v1alpha1/zz_generated.deepcopy.go +++ b/apis/v1alpha1/zz_generated.deepcopy.go @@ -19,6 +19,7 @@ package v1alpha1 import ( + appsv1 "k8s.io/api/apps/v1" "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -99,6 +100,11 @@ func (in *DatanodeSpec) DeepCopyInto(out *DatanodeSpec) { *out = new(DatanodeStorageSpec) (*in).DeepCopyInto(*out) } + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(appsv1.RollingUpdateStatefulSetStrategy) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatanodeSpec. @@ -170,6 +176,11 @@ func (in *FileStorage) DeepCopy() *FileStorage { func (in *FlownodeSpec) DeepCopyInto(out *FlownodeSpec) { *out = *in in.ComponentSpec.DeepCopyInto(&out.ComponentSpec) + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(appsv1.RollingUpdateStatefulSetStrategy) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlownodeSpec. @@ -211,6 +222,11 @@ func (in *FrontendSpec) DeepCopyInto(out *FrontendSpec) { *out = new(TLSSpec) **out = **in } + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(appsv1.RollingUpdateDeployment) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FrontendSpec. @@ -521,6 +537,11 @@ func (in *GreptimeDBStandaloneSpec) DeepCopyInto(out *GreptimeDBStandaloneSpec) *out = new(LoggingSpec) (*in).DeepCopyInto(*out) } + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(appsv1.RollingUpdateStatefulSetStrategy) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GreptimeDBStandaloneSpec. @@ -744,6 +765,11 @@ func (in *MetaSpec) DeepCopyInto(out *MetaSpec) { *out = new(bool) **out = **in } + if in.RollingUpdate != nil { + in, out := &in.RollingUpdate, &out.RollingUpdate + *out = new(appsv1.RollingUpdateDeployment) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetaSpec. diff --git a/config/crd/resources/greptime.io_greptimedbclusters.yaml b/config/crd/resources/greptime.io_greptimedbclusters.yaml index c2ad24b..4c0bc28 100644 --- a/config/crd/resources/greptime.io_greptimedbclusters.yaml +++ b/config/crd/resources/greptime.io_greptimedbclusters.yaml @@ -3066,6 +3066,17 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 @@ -6105,6 +6116,17 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 @@ -9137,6 +9159,19 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object rpcPort: format: int32 maximum: 65535 @@ -12237,6 +12272,19 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object rpcPort: format: int32 maximum: 65535 @@ -18361,6 +18409,17 @@ spec: required: - enabled type: object + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 diff --git a/config/crd/resources/greptime.io_greptimedbstandalones.yaml b/config/crd/resources/greptime.io_greptimedbstandalones.yaml index 6468eaf..39fdc73 100644 --- a/config/crd/resources/greptime.io_greptimedbstandalones.yaml +++ b/config/crd/resources/greptime.io_greptimedbstandalones.yaml @@ -3173,6 +3173,17 @@ spec: required: - enabled type: object + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 diff --git a/controllers/greptimedbcluster/deployers/datanode.go b/controllers/greptimedbcluster/deployers/datanode.go index 9684ad0..4a023d9 100644 --- a/controllers/greptimedbcluster/deployers/datanode.go +++ b/controllers/greptimedbcluster/deployers/datanode.go @@ -388,6 +388,10 @@ func (b *datanodeBuilder) BuildStatefulSet() deployer.Builder { }, Template: b.generatePodTemplateSpec(), VolumeClaimTemplates: b.generatePVCs(), + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: b.Cluster.Spec.Datanode.RollingUpdate, + }, }, } diff --git a/controllers/greptimedbcluster/deployers/flownode.go b/controllers/greptimedbcluster/deployers/flownode.go index b192998..cd890ab 100644 --- a/controllers/greptimedbcluster/deployers/flownode.go +++ b/controllers/greptimedbcluster/deployers/flownode.go @@ -193,6 +193,10 @@ func (b *flownodeBuilder) BuildStatefulSet() deployer.Builder { }, }, Template: b.generatePodTemplateSpec(), + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: b.Cluster.Spec.Flownode.RollingUpdate, + }, }, } diff --git a/controllers/greptimedbcluster/deployers/frontend.go b/controllers/greptimedbcluster/deployers/frontend.go index f3a8d21..e1a6d87 100644 --- a/controllers/greptimedbcluster/deployers/frontend.go +++ b/controllers/greptimedbcluster/deployers/frontend.go @@ -170,6 +170,10 @@ func (b *frontendBuilder) BuildDeployment() deployer.Builder { }, }, Template: *b.generatePodTemplateSpec(), + Strategy: appsv1.DeploymentStrategy{ + Type: appsv1.RollingUpdateDeploymentStrategyType, + RollingUpdate: b.Cluster.Spec.Frontend.RollingUpdate, + }, }, } diff --git a/controllers/greptimedbcluster/deployers/meta.go b/controllers/greptimedbcluster/deployers/meta.go index c8f1ead..fb88f7f 100644 --- a/controllers/greptimedbcluster/deployers/meta.go +++ b/controllers/greptimedbcluster/deployers/meta.go @@ -247,6 +247,10 @@ func (b *metaBuilder) BuildDeployment() deployer.Builder { }, }, Template: *b.generatePodTemplateSpec(), + Strategy: appsv1.DeploymentStrategy{ + Type: appsv1.RollingUpdateDeploymentStrategyType, + RollingUpdate: b.Cluster.Spec.Meta.RollingUpdate, + }, }, } diff --git a/controllers/greptimedbstandalone/deployer.go b/controllers/greptimedbstandalone/deployer.go index b8283f0..8857d60 100644 --- a/controllers/greptimedbstandalone/deployer.go +++ b/controllers/greptimedbstandalone/deployer.go @@ -253,6 +253,10 @@ func (b *standaloneBuilder) BuildStatefulSet() deployer.Builder { }, Template: b.generatePodTemplateSpec(), VolumeClaimTemplates: b.generatePVCs(), + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: b.standalone.Spec.RollingUpdate, + }, }, } diff --git a/docs/api-references/docs.md b/docs/api-references/docs.md index 28ddc5c..8fdb0d8 100644 --- a/docs/api-references/docs.md +++ b/docs/api-references/docs.md @@ -114,6 +114,7 @@ _Appears in:_ | `rpcPort` _integer_ | RPCPort is the gRPC port of the datanode. | | Maximum: 65535
Minimum: 0
| | `httpPort` _integer_ | HTTPPort is the HTTP port of the datanode. | | Maximum: 65535
Minimum: 0
| | `storage` _[DatanodeStorageSpec](#datanodestoragespec)_ | Storage is the default file storage of the datanode. For example, WAL, cache, index etc. | | | +| `rollingUpdate` _[RollingUpdateStatefulSetStrategy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#rollingupdatestatefulsetstrategy-v1-apps)_ | RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategy. | | | #### DatanodeStatus @@ -193,6 +194,7 @@ _Appears in:_ | `template` _[PodTemplateSpec](#podtemplatespec)_ | Template defines the pod template for the component, if not specified, the pod template will use the default value. | | | | `logging` _[LoggingSpec](#loggingspec)_ | Logging defines the logging configuration for the component. | | | | `rpcPort` _integer_ | The gRPC port of the flownode. | | Maximum: 65535
Minimum: 0
| +| `rollingUpdate` _[RollingUpdateStatefulSetStrategy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#rollingupdatestatefulsetstrategy-v1-apps)_ | RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategy. | | | #### FlownodeStatus @@ -235,6 +237,7 @@ _Appears in:_ | `postgreSQLPort` _integer_ | PostgreSQLPort is the PostgreSQL port of the frontend. | | Maximum: 65535
Minimum: 0
| | `service` _[ServiceSpec](#servicespec)_ | Service is the service configuration of the frontend. | | | | `tls` _[TLSSpec](#tlsspec)_ | TLS is the TLS configuration of the frontend. | | | +| `rollingUpdate` _[RollingUpdateDeployment](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#rollingupdatedeployment-v1-apps)_ | RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategyt. | | | #### FrontendStatus @@ -410,6 +413,7 @@ _Appears in:_ | `wal` _[WALProviderSpec](#walproviderspec)_ | WALProvider is the WAL provider for the greptimedb cluster. | | | | `config` _string_ | The content of the configuration file of the component in TOML format. | | | | `logging` _[LoggingSpec](#loggingspec)_ | Logging defines the logging configuration for the component. | | | +| `rollingUpdate` _[RollingUpdateStatefulSetStrategy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#rollingupdatestatefulsetstrategy-v1-apps)_ | RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategy. | | | @@ -595,6 +599,7 @@ _Appears in:_ | `enableCheckEtcdService` _boolean_ | EnableCheckEtcdService indicates whether to check etcd cluster health when starting meta. | | | | `enableRegionFailover` _boolean_ | EnableRegionFailover indicates whether to enable region failover. | | | | `storeKeyPrefix` _string_ | StoreKeyPrefix is the prefix of the key in the etcd. We can use it to isolate the data of different clusters. | | | +| `rollingUpdate` _[RollingUpdateDeployment](https://kubernetes.io/docs/reference/generated/kubernetes-api/v/#rollingupdatedeployment-v1-apps)_ | RollingUpdate is the rolling update configuration. We always use `RollingUpdate` strategyt. | | | #### MetaStatus diff --git a/manifests/bundle.yaml b/manifests/bundle.yaml index c5ab69c..a1a8742 100644 --- a/manifests/bundle.yaml +++ b/manifests/bundle.yaml @@ -3072,6 +3072,17 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 @@ -6111,6 +6122,17 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 @@ -9143,6 +9165,19 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object rpcPort: format: int32 maximum: 65535 @@ -12243,6 +12278,19 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object rpcPort: format: int32 maximum: 65535 @@ -18367,6 +18415,17 @@ spec: required: - enabled type: object + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 @@ -21875,6 +21934,17 @@ spec: required: - enabled type: object + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 diff --git a/manifests/crds.yaml b/manifests/crds.yaml index 7f3ae18..76a6573 100644 --- a/manifests/crds.yaml +++ b/manifests/crds.yaml @@ -3065,6 +3065,17 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 @@ -6104,6 +6115,17 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 @@ -9136,6 +9158,19 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object rpcPort: format: int32 maximum: 65535 @@ -12236,6 +12271,19 @@ spec: format: int32 minimum: 0 type: integer + rollingUpdate: + properties: + maxSurge: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object rpcPort: format: int32 maximum: 65535 @@ -18360,6 +18408,17 @@ spec: required: - enabled type: object + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535 @@ -21868,6 +21927,17 @@ spec: required: - enabled type: object + rollingUpdate: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + partition: + format: int32 + type: integer + type: object rpcPort: format: int32 maximum: 65535