From d298ebd7a2ecdc586ac59c9c7f545cf8cf34f592 Mon Sep 17 00:00:00 2001 From: Phoeniix Zhao Date: Sat, 23 Dec 2023 22:43:51 +0800 Subject: [PATCH] feat: support pvc for xline Signed-off-by: Phoeniix Zhao --- api/v1alpha1/xlinecluster_types.go | 8 ++++ api/v1alpha1/zz_generated.deepcopy.go | 46 +++++++++++++++++++ ...e.kvstore.datenlord.com_xlineclusters.yaml | 46 +++++++++++++++++++ internal/transformer/xlinecluster_resource.go | 20 +++++--- internal/util/kubeutil.go | 19 ++++++++ 5 files changed, 132 insertions(+), 7 deletions(-) diff --git a/api/v1alpha1/xlinecluster_types.go b/api/v1alpha1/xlinecluster_types.go index 8e9b73fa..19e39cf2 100644 --- a/api/v1alpha1/xlinecluster_types.go +++ b/api/v1alpha1/xlinecluster_types.go @@ -68,6 +68,14 @@ type XlineClusterSpec struct { // The auth secret keys AuthSecrets *XlineAuthSecret `json:"authSecret,omitempty"` + + // K8s storage-class-name of the Xline storage + // Defaults to Kubernetes default storage class. + // +optional + StorageClassName *string `json:"storageClassName"` + + // Defines the specification of resource cpu, mem, storage. + corev1.ResourceRequirements `json:",inline"` } type XlineAuthSecret struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 6a7cc92b..e4249fdd 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -41,6 +41,41 @@ func (in *NamespacedName) DeepCopy() *NamespacedName { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *XlineAuthSecret) DeepCopyInto(out *XlineAuthSecret) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.MountPath != nil { + in, out := &in.MountPath, &out.MountPath + *out = new(string) + **out = **in + } + if in.PubKey != nil { + in, out := &in.PubKey, &out.PubKey + *out = new(string) + **out = **in + } + if in.PriKey != nil { + in, out := &in.PriKey, &out.PriKey + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XlineAuthSecret. +func (in *XlineAuthSecret) DeepCopy() *XlineAuthSecret { + if in == nil { + return nil + } + out := new(XlineAuthSecret) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *XlineCluster) DeepCopyInto(out *XlineCluster) { *out = *in @@ -128,6 +163,17 @@ func (in *XlineClusterSpec) DeepCopyInto(out *XlineClusterSpec) { *out = new(string) **out = **in } + if in.AuthSecrets != nil { + in, out := &in.AuthSecrets, &out.AuthSecrets + *out = new(XlineAuthSecret) + (*in).DeepCopyInto(*out) + } + if in.StorageClassName != nil { + in, out := &in.StorageClassName, &out.StorageClassName + *out = new(string) + **out = **in + } + in.ResourceRequirements.DeepCopyInto(&out.ResourceRequirements) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new XlineClusterSpec. diff --git a/config/crd/bases/xline.kvstore.datenlord.com_xlineclusters.yaml b/config/crd/bases/xline.kvstore.datenlord.com_xlineclusters.yaml index 62c71f44..673888c0 100644 --- a/config/crd/bases/xline.kvstore.datenlord.com_xlineclusters.yaml +++ b/config/crd/bases/xline.kvstore.datenlord.com_xlineclusters.yaml @@ -52,17 +52,63 @@ spec: - priKey - pubKey type: object + claims: + description: "Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. \n This is an alpha field and requires + enabling the DynamicResourceAllocation feature gate. \n This field + is immutable. It can only be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims + of the Pod where this field is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map image: description: Xline cluster image type: string imagePullPolicy: description: ImagePullPolicy of Xline cluster Pods type: string + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object replicas: description: The replicas of xline nodes format: int32 minimum: 3 type: integer + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute resources + required. If Requests is omitted for a container, it defaults to + Limits if that is explicitly specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + storageClassName: + description: K8s storage-class-name of the Xline storage Defaults + to Kubernetes default storage class. + type: string version: description: Xline cluster image version type: string diff --git a/internal/transformer/xlinecluster_resource.go b/internal/transformer/xlinecluster_resource.go index e07674f9..240bf7c5 100644 --- a/internal/transformer/xlinecluster_resource.go +++ b/internal/transformer/xlinecluster_resource.go @@ -5,6 +5,7 @@ import ( "strings" xapi "github.com/xline-kv/xline-operator/api/v1alpha1" + "github.com/xline-kv/xline-operator/internal/util" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -108,14 +109,18 @@ func MakeStatefulSet(cr *xapi.XlineCluster, scheme *runtime.Scheme) *appv1.State svcName := GetServiceKey(cr.ObjKey()).Name volumes := GetAuthSecretVolume(cr.Spec.AuthSecrets) - volumeMount := GetAuthSecretVolumeMount(cr.Spec.AuthSecrets) - + volumeMounts := GetAuthSecretVolumeMount(cr.Spec.AuthSecrets) + volumeMounts = append(volumeMounts, corev1.VolumeMount{Name: "xline-storage", MountPath: "/usr/local/xline/data-dir"}) envs := []corev1.EnvVar{ {Name: "MEMBERS", Value: GetMemberTopology(stsRef, svcName, int(cr.Spec.Replicas))}, } envs = append(envs, GetAuthSecretEnvVars(cr.Spec.AuthSecrets)...) + pvcTemplates := []corev1.PersistentVolumeClaim{ + util.NewReadWriteOncePVC("xline-storage", cr.Spec.StorageClassName, cr.Spec.Requests.Storage()), + } + // pod template: main container mainContainer := corev1.Container{ Name: "xline", @@ -125,7 +130,7 @@ func MakeStatefulSet(cr *xapi.XlineCluster, scheme *runtime.Scheme) *appv1.State {Name: "xline-port", ContainerPort: 2379}, }, Env: envs, - VolumeMounts: volumeMount, + VolumeMounts: volumeMounts, } // pod template @@ -149,10 +154,11 @@ func MakeStatefulSet(cr *xapi.XlineCluster, scheme *runtime.Scheme) *appv1.State Labels: stsLabels, }, Spec: appv1.StatefulSetSpec{ - Replicas: &cr.Spec.Replicas, - ServiceName: svcName, - Selector: &metav1.LabelSelector{MatchLabels: stsLabels}, - Template: podTemplate, + Replicas: &cr.Spec.Replicas, + ServiceName: svcName, + Selector: &metav1.LabelSelector{MatchLabels: stsLabels}, + VolumeClaimTemplates: pvcTemplates, + Template: podTemplate, }, } diff --git a/internal/util/kubeutil.go b/internal/util/kubeutil.go index fc4a04f1..58d87cce 100644 --- a/internal/util/kubeutil.go +++ b/internal/util/kubeutil.go @@ -5,6 +5,9 @@ import ( "encoding/json" "fmt" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -34,3 +37,19 @@ func Md5HashOr(obj any, fallback string) string { } return hash } + +func NewReadWriteOncePVC(name string, storageClassName *string, storageRequest *resource.Quantity) corev1.PersistentVolumeClaim { + pvc := corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce}, + StorageClassName: storageClassName, + }, + } + if storageRequest != nil { + pvc.Spec.Resources.Requests = corev1.ResourceList{corev1.ResourceStorage: *storageRequest} + } + return pvc +}