diff --git a/Changelog.md b/Changelog.md index 76dd97361..253cd07b1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -11,6 +11,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). provisioners wich don't support fsGroup in security context (fixes #615) * Add `appSecretLabels`, `appSecretAnnotations`, `backupSecretLabels`, `backupSecretAnnotations` to provide custom labels and annotations to created app and backup secrets + * Add ability to provision LoadBalancers for master/replica services + * Support specifying additional annotations for master/replica services ### Changed * Allow setting pod security context when deploying with Helm * Use [distroless](https://github.com/GoogleContainerTools/distroless) as base image for orchestrator container diff --git a/config/crd/bases/mysql.presslabs.org_mysqlclusters.yaml b/config/crd/bases/mysql.presslabs.org_mysqlclusters.yaml index 2bbc3af3a..8c82057f1 100644 --- a/config/crd/bases/mysql.presslabs.org_mysqlclusters.yaml +++ b/config/crd/bases/mysql.presslabs.org_mysqlclusters.yaml @@ -51,6 +51,20 @@ spec: description: 'MysqlClusterSpec defines the desired state of MysqlCluster nolint: maligned' properties: + MasterServiceSpec: + description: Master service extra specification + properties: + annotations: + additionalProperties: + type: string + description: Annotations allow to specify annotations for MysqlCluster's + services + type: object + loadBalancer: + description: LoadBalancer configures whether a service is a LoadBalancer + or not. + type: boolean + type: object backupCompressCommand: description: BackupCompressCommand is a command to use for compressing the backup. @@ -6161,6 +6175,20 @@ spec: in case of a failover the cluster will be writable for at least a few seconds. type: boolean + replicaServiceSpec: + description: Healthy replica service extra specification + properties: + annotations: + additionalProperties: + type: string + description: Annotations allow to specify annotations for MysqlCluster's + services + type: object + loadBalancer: + description: LoadBalancer configures whether a service is a LoadBalancer + or not. + type: boolean + type: object replicas: description: The number of pods. This updates replicas filed Defaults to 0 diff --git a/deploy/charts/mysql-operator/crds/mysql.presslabs.org_mysqlclusters.yaml b/deploy/charts/mysql-operator/crds/mysql.presslabs.org_mysqlclusters.yaml index 76b8852e9..b14b74d50 100644 --- a/deploy/charts/mysql-operator/crds/mysql.presslabs.org_mysqlclusters.yaml +++ b/deploy/charts/mysql-operator/crds/mysql.presslabs.org_mysqlclusters.yaml @@ -46,6 +46,18 @@ spec: spec: description: 'MysqlClusterSpec defines the desired state of MysqlCluster nolint: maligned' properties: + MasterServiceSpec: + description: Master service extra specification + properties: + annotations: + additionalProperties: + type: string + description: Annotations allow to specify annotations for MysqlCluster's services + type: object + loadBalancer: + description: LoadBalancer configures whether a service is a LoadBalancer or not. + type: boolean + type: object backupCompressCommand: description: BackupCompressCommand is a command to use for compressing the backup. items: @@ -3759,6 +3771,18 @@ spec: readOnly: description: Makes the cluster READ ONLY. This has not a strong guarantee, in case of a failover the cluster will be writable for at least a few seconds. type: boolean + replicaServiceSpec: + description: Healthy replica service extra specification + properties: + annotations: + additionalProperties: + type: string + description: Annotations allow to specify annotations for MysqlCluster's services + type: object + loadBalancer: + description: LoadBalancer configures whether a service is a LoadBalancer or not. + type: boolean + type: object replicas: description: The number of pods. This updates replicas filed Defaults to 0 format: int32 diff --git a/pkg/apis/mysql/v1alpha1/mysqlcluster_types.go b/pkg/apis/mysql/v1alpha1/mysqlcluster_types.go index ebe19c8f9..c12c5b511 100644 --- a/pkg/apis/mysql/v1alpha1/mysqlcluster_types.go +++ b/pkg/apis/mysql/v1alpha1/mysqlcluster_types.go @@ -107,6 +107,14 @@ type MysqlClusterSpec struct { // +optional VolumeSpec VolumeSpec `json:"volumeSpec,omitempty"` + // Master service extra specification + // +optional + MasterServiceSpec ServiceSpec `json:"MasterServiceSpec,omitempty"` + + // Healthy replica service extra specification + // +optional + ReplicaServiceSpec ServiceSpec `json:"replicaServiceSpec,omitempty"` + // TmpfsSize if specified, mounts a tmpfs of this size into /tmp // DEPRECATED: use instead PodSpec.Volumes and PodSpec.VolumeMounts // +optional @@ -241,6 +249,17 @@ type VolumeSpec struct { PersistentVolumeClaim *core.PersistentVolumeClaimSpec `json:"persistentVolumeClaim,omitempty"` } +// ServiceSpec s the desired spec for addition configuration of MysqlCluster services +type ServiceSpec struct { + // LoadBalancer configures whether a service is a LoadBalancer or not. + // +optional + LoadBalancer bool `json:"loadBalancer,omitempty"` + + // Annotations allow to specify annotations for MysqlCluster's services + // +optional + Annotations map[string]string `json:"annotations,omitempty"` +} + // QueryLimits represents the pt-kill parameters, more info can be found // here: https://www.percona.com/doc/percona-toolkit/LATEST/pt-kill.html type QueryLimits struct { diff --git a/pkg/apis/mysql/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/mysql/v1alpha1/zz_generated.deepcopy.go index 3a053a939..a11c06486 100644 --- a/pkg/apis/mysql/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/mysql/v1alpha1/zz_generated.deepcopy.go @@ -267,6 +267,8 @@ func (in *MysqlClusterSpec) DeepCopyInto(out *MysqlClusterSpec) { } in.PodSpec.DeepCopyInto(&out.PodSpec) in.VolumeSpec.DeepCopyInto(&out.VolumeSpec) + in.MasterServiceSpec.DeepCopyInto(&out.MasterServiceSpec) + in.ReplicaServiceSpec.DeepCopyInto(&out.ReplicaServiceSpec) if in.TmpfsSize != nil { in, out := &in.TmpfsSize, &out.TmpfsSize x := (*in).DeepCopy() @@ -831,6 +833,28 @@ func (in *QueryLimits) DeepCopy() *QueryLimits { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) { + *out = *in + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceSpec. +func (in *ServiceSpec) DeepCopy() *ServiceSpec { + if in == nil { + return nil + } + out := new(ServiceSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VolumeSpec) DeepCopyInto(out *VolumeSpec) { *out = *in diff --git a/pkg/controller/mysqlcluster/internal/syncer/healthy_replicas_service.go b/pkg/controller/mysqlcluster/internal/syncer/healthy_replicas_service.go index 5d15931b3..0ee8ba64f 100644 --- a/pkg/controller/mysqlcluster/internal/syncer/healthy_replicas_service.go +++ b/pkg/controller/mysqlcluster/internal/syncer/healthy_replicas_service.go @@ -17,6 +17,7 @@ limitations under the License. package mysqlcluster import ( + "github.com/imdario/mergo" "github.com/presslabs/controller-util/syncer" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -36,6 +37,16 @@ func NewHealthyReplicasSVCSyncer(c client.Client, scheme *runtime.Scheme, cluste } return syncer.NewObjectSyncer("HealthyReplicasSVC", cluster.Unwrap(), service, c, func() error { + // set service type + if cluster.Spec.ReplicaServiceSpec.LoadBalancer { + service.Spec.Type = core.ServiceTypeLoadBalancer + } + + // merge annotations + if err := mergo.Merge(&service.ObjectMeta.Annotations, cluster.Spec.ReplicaServiceSpec.Annotations); err != nil { + return err + } + // set service labels service.Labels = cluster.GetLabels() service.Labels["mysql.presslabs.org/service-type"] = "ready-replicas" diff --git a/pkg/controller/mysqlcluster/internal/syncer/master_service.go b/pkg/controller/mysqlcluster/internal/syncer/master_service.go index e7374cb1b..156e83904 100644 --- a/pkg/controller/mysqlcluster/internal/syncer/master_service.go +++ b/pkg/controller/mysqlcluster/internal/syncer/master_service.go @@ -17,6 +17,7 @@ limitations under the License. package mysqlcluster import ( + "github.com/imdario/mergo" "github.com/presslabs/controller-util/syncer" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -36,6 +37,16 @@ func NewMasterSVCSyncer(c client.Client, scheme *runtime.Scheme, cluster *mysqlc } return syncer.NewObjectSyncer("MasterSVC", cluster.Unwrap(), service, c, func() error { + // set service type + if cluster.Spec.MasterServiceSpec.LoadBalancer { + service.Spec.Type = core.ServiceTypeLoadBalancer + } + + // merge annotations + if err := mergo.Merge(&service.ObjectMeta.Annotations, cluster.Spec.MasterServiceSpec.Annotations); err != nil { + return err + } + // set service labels service.Labels = cluster.GetLabels() service.Labels["mysql.presslabs.org/service-type"] = "master" diff --git a/pkg/internal/mysqlcluster/mysqlcluster_test.go b/pkg/internal/mysqlcluster/mysqlcluster_test.go index a472f8640..21654130a 100644 --- a/pkg/internal/mysqlcluster/mysqlcluster_test.go +++ b/pkg/internal/mysqlcluster/mysqlcluster_test.go @@ -75,6 +75,9 @@ var _ = Describe("Test MySQL cluster wrapper", func() { Expect(cluster.Spec.MysqlConf).To(HaveKey(Equal("innodb-buffer-pool-size"))) Expect(cluster.Spec.MysqlConf).To(HaveKey(Equal("innodb-log-file-size"))) Expect(cluster.Spec.MysqlConf).NotTo(HaveKey(Equal("max-binlog-size"))) + + Expect(cluster.Spec.MasterServiceSpec.LoadBalancer).To(Equal(false)) + Expect(cluster.Spec.ReplicaServiceSpec.LoadBalancer).To(Equal(false)) }) It("should use init MySQL container", func() {