From 147d7069f1c9f032859936dc0567c9f161adae73 Mon Sep 17 00:00:00 2001 From: yangw Date: Mon, 11 Nov 2024 15:06:00 +0800 Subject: [PATCH] feat: add master/replica service to redis replication (#1124) * refactor Signed-off-by: drivebyer * feat: add master/replica service to redis replication Signed-off-by: drivebyer * fix docs Signed-off-by: drivebyer * fix docs Signed-off-by: drivebyer --------- Signed-off-by: drivebyer --- api/common_types.go | 14 +++ .../en/docs/Configuration/Redis/_index.md | 91 +++++++++----- .../docs/Configuration/RedisCluster/_index.md | 113 ++++++++++++------ .../Configuration/RedisReplication/_index.md | 92 +++++++++----- pkg/k8sutils/redis-cluster.go | 27 ++--- pkg/k8sutils/redis-replication.go | 43 ++++--- pkg/k8sutils/redis-sentinel.go | 22 ++-- pkg/k8sutils/redis-standalone.go | 21 ++-- pkg/util/map.go | 13 ++ .../setup/redis-replication/ready-svc.yaml | 65 ++++++++++ 10 files changed, 351 insertions(+), 150 deletions(-) create mode 100644 pkg/util/map.go diff --git a/api/common_types.go b/api/common_types.go index c0212cf31..378bda1bc 100644 --- a/api/common_types.go +++ b/api/common_types.go @@ -19,6 +19,20 @@ type KubernetesConfig struct { MinReadySeconds *int32 `json:"minReadySeconds,omitempty"` } +func (in *KubernetesConfig) GetServiceType() string { + if in.Service == nil { + return "ClusterIP" + } + return in.Service.ServiceType +} + +func (in *KubernetesConfig) GetServiceAnnotations() map[string]string { + if in.Service == nil { + return nil + } + return in.Service.ServiceAnnotations +} + // ServiceConfig define the type of service to be created and its annotations // +k8s:deepcopy-gen=true type ServiceConfig struct { diff --git a/docs/content/en/docs/Configuration/Redis/_index.md b/docs/content/en/docs/Configuration/Redis/_index.md index 460f7e007..a6748d514 100644 --- a/docs/content/en/docs/Configuration/Redis/_index.md +++ b/docs/content/en/docs/Configuration/Redis/_index.md @@ -7,36 +7,67 @@ description: > Configurations and parameters for Redis standalone --- -Redis standalone configuration can be customized by [values.yaml](https://github.com/OT-CONTAINER-KIT/helm-charts/blob/main/charts/redis/values.yaml). The recommended way of managing the setup is using `helm` but if the setup is not maintained by it, `YAML` CRD parameters can be modified in the manifest. +Redis standalone configuration can be customized by [values.yaml](https://github.com/OT-CONTAINER-KIT/redis-operator/blob/master/charts/redis/values.yaml). The recommended way of managing the setup is using `helm` but if the setup is not maintained by it, `YAML` CRD parameters can be modified in the manifest. ## Helm Configuration Parameters -| **Name** | **Value** | **Description** | -|-----------------------------------|--------------------------------|-----------------------------------------------------------------------------------------------| -| `imagePullSecrets` | [] | List of image pull secrets, in case redis image is getting pull from private registry | -| `redisStandalone.secretName` | redis-secret | Name of the existing secret in Kubernetes | -| `redisStandalone.secretKey` | password | Name of the existing secret key in Kubernetes | -| `redisStandalone.image` | quay.io/opstree/redis | Name of the redis image | -| `redisStandalone.tag` | v7.0.15 | Tag of the redis image | -| `redisStandalone.imagePullPolicy` | IfNotPresent | Image Pull Policy of the redis image | -| `redisStandalone.resources` | {} | Request and limits for redis statefulset | -| `externalService.enabled` | false | If redis service needs to be exposed using LoadBalancer or NodePort | -| `externalService.annotations` | {} | Kubernetes service related annotations | -| `externalService.serviceType` | NodePort | Kubernetes service type for exposing service, values - ClusterIP, NodePort, and LoadBalancer | -| `externalService.port` | 6379 | Port number on which redis external service should be exposed | -| `serviceMonitor.enabled` | false | Servicemonitor to monitor redis with Prometheus | -| `serviceMonitor.interval` | 30s | Interval at which metrics should be scraped. | -| `serviceMonitor.scrapeTimeout` | 10s | Timeout after which the scrape is ended | -| `serviceMonitor.namespace` | monitoring | Namespace in which Prometheus operator is running | -| `redisExporter.enabled` | true | Redis exporter should be deployed or not | -| `redisExporter.image` | quay.io/opstree/redis-exporter | Name of the redis exporter image | -| `redisExporter.tag` | v1.44.0 | Tag of the redis exporter image | -| `redisExporter.imagePullPolicy` | IfNotPresent | Image Pull Policy of the redis exporter image | -| `redisExporter.env` | [] | Extra environment variables which needs to be added in redis exporter | -| `nodeSelector` | {} | NodeSelector for redis statefulset | -| `priorityClassName` | "" | Priority class name for the redis statefulset | -| `storageSpec` | {} | Storage configuration for redis setup | -| `securityContext` | {} | Security Context for redis pods for changing system or kernel level parameters | -| `affinity` | {} | Affinity for node and pod for redis statefulset | -| `tolerations` | [] | Tolerations for redis statefulset | -| `sidecars` | [] | Sidecar containers to run alongside Redis pods | +| Key | Type | Default | Description | +|-----------------------------------------------------------------|--------|--------------------------------------------------------------------------|-------------| +| TLS.ca | string | `"ca.key"` | | +| TLS.cert | string | `"tls.crt"` | | +| TLS.key | string | `"tls.key"` | | +| TLS.secret.secretName | string | `""` | | +| acl.secret.secretName | string | `""` | | +| affinity | object | `{}` | | +| env | list | `[]` | | +| externalConfig.data | string | `"tcp-keepalive 400\nslowlog-max-len 158\nstream-node-max-bytes 2048\n"` | | +| externalConfig.enabled | bool | `false` | | +| externalService.enabled | bool | `false` | | +| externalService.port | int | `6379` | | +| externalService.serviceType | string | `"NodePort"` | | +| initContainer.args | list | `[]` | | +| initContainer.command | list | `[]` | | +| initContainer.enabled | bool | `false` | | +| initContainer.env | list | `[]` | | +| initContainer.image | string | `""` | | +| initContainer.imagePullPolicy | string | `"IfNotPresent"` | | +| initContainer.resources | object | `{}` | | +| labels | object | `{}` | | +| nodeSelector | object | `{}` | | +| podSecurityContext.fsGroup | int | `1000` | | +| podSecurityContext.runAsUser | int | `1000` | | +| priorityClassName | string | `""` | | +| redisExporter.enabled | bool | `false` | | +| redisExporter.env | list | `[]` | | +| redisExporter.image | string | `"quay.io/opstree/redis-exporter"` | | +| redisExporter.imagePullPolicy | string | `"IfNotPresent"` | | +| redisExporter.resources | object | `{}` | | +| redisExporter.tag | string | `"v1.44.0"` | | +| redisStandalone.ignoreAnnotations | list | `[]` | | +| redisStandalone.image | string | `"quay.io/opstree/redis"` | | +| redisStandalone.imagePullPolicy | string | `"IfNotPresent"` | | +| redisStandalone.imagePullSecrets | list | `[]` | | +| redisStandalone.minReadySeconds | int | `0` | | +| redisStandalone.name | string | `""` | | +| redisStandalone.redisSecret.secretKey | string | `""` | | +| redisStandalone.redisSecret.secretName | string | `""` | | +| redisStandalone.resources | object | `{}` | | +| redisStandalone.serviceType | string | `"ClusterIP"` | | +| redisStandalone.tag | string | `"v7.0.15"` | | +| securityContext | object | `{}` | | +| serviceAccountName | string | `""` | | +| serviceMonitor.enabled | bool | `false` | | +| serviceMonitor.interval | string | `"30s"` | | +| serviceMonitor.namespace | string | `"monitoring"` | | +| serviceMonitor.scrapeTimeout | string | `"10s"` | | +| sidecars.env | list | `[]` | | +| sidecars.image | string | `""` | | +| sidecars.imagePullPolicy | string | `"IfNotPresent"` | | +| sidecars.name | string | `""` | | +| sidecars.resources.limits.cpu | string | `"100m"` | | +| sidecars.resources.limits.memory | string | `"128Mi"` | | +| sidecars.resources.requests.cpu | string | `"50m"` | | +| sidecars.resources.requests.memory | string | `"64Mi"` | | +| storageSpec.volumeClaimTemplate.spec.accessModes[0] | string | `"ReadWriteOnce"` | | +| storageSpec.volumeClaimTemplate.spec.resources.requests.storage | string | `"1Gi"` | | +| tolerations | list | `[]` | | \ No newline at end of file diff --git a/docs/content/en/docs/Configuration/RedisCluster/_index.md b/docs/content/en/docs/Configuration/RedisCluster/_index.md index a4a85b1ec..86bbc73a7 100644 --- a/docs/content/en/docs/Configuration/RedisCluster/_index.md +++ b/docs/content/en/docs/Configuration/RedisCluster/_index.md @@ -7,40 +7,85 @@ description: > Configurations and parameters for Redis cluster --- -Redis cluster can be customized by [values.yaml](https://github.com/OT-CONTAINER-KIT/helm-charts/blob/main/charts/redis-cluster/values.yaml). The recommended way of managing the setup is using `helm` but if the setup is not maintained by it, `YAML` CRD parameters can be modified in the manifest. +Redis cluster can be customized by [values.yaml](https://github.com/OT-CONTAINER-KIT/redis-operator/blob/master/charts/redis-cluster/values.yaml). The recommended way of managing the setup is using `helm` but if the setup is not maintained by it, `YAML` CRD parameters can be modified in the manifest. ## Helm Configuration Parameters -| **Name** | **Default Value** | **Description** | -|------------------------------------|--------------------------------|----------------------------------------------------------------------------------------------| -| `imagePullSecrets` | [] | List of image pull secrets, in case redis image is getting pull from private registry | -| `redisCluster.clusterSize` | 3 | Size of the redis cluster leader and follower nodes | -| `redisCluster.clusterVersion` | v7 | Major version of Redis setup, values can be v6 or v7 | -| `redisCluster.persistenceEnabled` | true | Persistence should be enabled or not in the Redis cluster setup | -| `redisCluster.secretName` | redis-secret | Name of the existing secret in Kubernetes | -| `redisCluster.secretKey` | password | Name of the existing secret key in Kubernetes | -| `redisCluster.image` | quay.io/opstree/redis | Name of the redis image | -| `redisCluster.tag` | v7.0.15 | Tag of the redis image | -| `redisCluster.imagePullPolicy` | IfNotPresent | Image Pull Policy of the redis image | -| `redisCluster.leaderServiceType` | ClusterIP | Kubernetes service type for Redis Leader | -| `redisCluster.followerServiceType` | ClusterIP | Kubernetes service type for Redis Follower | -| `externalService.enabled` | false | If redis service needs to be exposed using LoadBalancer or NodePort | -| `externalService.annotations` | {} | Kubernetes service related annotations | -| `externalService.serviceType` | NodePort | Kubernetes service type for exposing service, values - ClusterIP, NodePort, and LoadBalancer | -| `externalService.port` | 6379 | Port number on which redis external service should be exposed | -| `serviceMonitor.enabled` | false | Servicemonitor to monitor redis with Prometheus | -| `serviceMonitor.interval` | 30s | Interval at which metrics should be scraped. | -| `serviceMonitor.scrapeTimeout` | 10s | Timeout after which the scrape is ended | -| `serviceMonitor.namespace` | monitoring | Namespace in which Prometheus operator is running | -| `redisExporter.enabled` | true | Redis exporter should be deployed or not | -| `redisExporter.image` | quay.io/opstree/redis-exporter | Name of the redis exporter image | -| `redisExporter.tag` | v1.44.0 | Tag of the redis exporter image | -| `redisExporter.imagePullPolicy` | IfNotPresent | Image Pull Policy of the redis exporter image | -| `redisExporter.env` | [] | Extra environment variables which needs to be added in redis exporter | -| `sidecars` | [] | Sidecar container to run alongside Redis pods | -| `nodeSelector` | {} | NodeSelector for redis statefulset | -| `priorityClassName` | "" | Priority class name for the redis statefulset | -| `storageSpec` | {} | Storage configuration for redis setup | -| `securityContext` | {} | Security Context for redis pods for changing system or kernel level parameters | -| `affinity` | {} | Affinity for node and pods for redis statefulset | -| `tolerations` | [] | Tolerations for redis statefulset management | +| Key | Type | Default | Description | +|-------------------------------------------------------------------------|--------|--------------------------------------------------------------------------|-------------| +| TLS.ca | string | `"ca.key"` | | +| TLS.cert | string | `"tls.crt"` | | +| TLS.key | string | `"tls.key"` | | +| TLS.secret.secretName | string | `""` | | +| acl.secret.secretName | string | `""` | | +| env | list | `[]` | | +| externalConfig.data | string | `"tcp-keepalive 400\nslowlog-max-len 158\nstream-node-max-bytes 2048\n"` | | +| externalConfig.enabled | bool | `false` | | +| externalService.enabled | bool | `false` | | +| externalService.port | int | `6379` | | +| externalService.serviceType | string | `"LoadBalancer"` | | +| initContainer.args | list | `[]` | | +| initContainer.command | list | `[]` | | +| initContainer.enabled | bool | `false` | | +| initContainer.env | list | `[]` | | +| initContainer.image | string | `""` | | +| initContainer.imagePullPolicy | string | `"IfNotPresent"` | | +| initContainer.resources | object | `{}` | | +| labels | object | `{}` | | +| podSecurityContext.fsGroup | int | `1000` | | +| podSecurityContext.runAsUser | int | `1000` | | +| priorityClassName | string | `""` | | +| redisCluster.clusterSize | int | `3` | | +| redisCluster.clusterVersion | string | `"v7"` | | +| redisCluster.follower.affinity | string | `nil` | | +| redisCluster.follower.nodeSelector | string | `nil` | | +| redisCluster.follower.pdb.enabled | bool | `false` | | +| redisCluster.follower.pdb.maxUnavailable | int | `1` | | +| redisCluster.follower.pdb.minAvailable | int | `1` | | +| redisCluster.follower.replicas | int | `3` | | +| redisCluster.follower.securityContext | object | `{}` | | +| redisCluster.follower.serviceType | string | `"ClusterIP"` | | +| redisCluster.follower.tolerations | list | `[]` | | +| redisCluster.image | string | `"quay.io/opstree/redis"` | | +| redisCluster.imagePullPolicy | string | `"IfNotPresent"` | | +| redisCluster.imagePullSecrets | object | `{}` | | +| redisCluster.leader.affinity | object | `{}` | | +| redisCluster.leader.nodeSelector | string | `nil` | | +| redisCluster.leader.pdb.enabled | bool | `false` | | +| redisCluster.leader.pdb.maxUnavailable | int | `1` | | +| redisCluster.leader.pdb.minAvailable | int | `1` | | +| redisCluster.leader.replicas | int | `3` | | +| redisCluster.leader.securityContext | object | `{}` | | +| redisCluster.leader.serviceType | string | `"ClusterIP"` | | +| redisCluster.leader.tolerations | list | `[]` | | +| redisCluster.minReadySeconds | int | `0` | | +| redisCluster.name | string | `""` | | +| redisCluster.persistenceEnabled | bool | `true` | | +| redisCluster.redisSecret.secretKey | string | `""` | | +| redisCluster.redisSecret.secretName | string | `""` | | +| redisCluster.resources | object | `{}` | | +| redisCluster.tag | string | `"v7.0.15"` | | +| redisExporter.enabled | bool | `false` | | +| redisExporter.env | list | `[]` | | +| redisExporter.image | string | `"quay.io/opstree/redis-exporter"` | | +| redisExporter.imagePullPolicy | string | `"IfNotPresent"` | | +| redisExporter.resources | object | `{}` | | +| redisExporter.tag | string | `"v1.44.0"` | | +| serviceAccountName | string | `""` | | +| serviceMonitor.enabled | bool | `false` | | +| serviceMonitor.interval | string | `"30s"` | | +| serviceMonitor.namespace | string | `"monitoring"` | | +| serviceMonitor.scrapeTimeout | string | `"10s"` | | +| sidecars.env | object | `{}` | | +| sidecars.image | string | `""` | | +| sidecars.imagePullPolicy | string | `"IfNotPresent"` | | +| sidecars.name | string | `""` | | +| sidecars.resources.limits.cpu | string | `"100m"` | | +| sidecars.resources.limits.memory | string | `"128Mi"` | | +| sidecars.resources.requests.cpu | string | `"50m"` | | +| sidecars.resources.requests.memory | string | `"64Mi"` | | +| storageSpec.nodeConfVolume | bool | `true` | | +| storageSpec.nodeConfVolumeClaimTemplate.spec.accessModes[0] | string | `"ReadWriteOnce"` | | +| storageSpec.nodeConfVolumeClaimTemplate.spec.resources.requests.storage | string | `"1Gi"` | | +| storageSpec.volumeClaimTemplate.spec.accessModes[0] | string | `"ReadWriteOnce"` | | +| storageSpec.volumeClaimTemplate.spec.resources.requests.storage | string | `"1Gi"` | | \ No newline at end of file diff --git a/docs/content/en/docs/Configuration/RedisReplication/_index.md b/docs/content/en/docs/Configuration/RedisReplication/_index.md index a51fc3da1..d9e8ab1a0 100644 --- a/docs/content/en/docs/Configuration/RedisReplication/_index.md +++ b/docs/content/en/docs/Configuration/RedisReplication/_index.md @@ -7,36 +7,68 @@ description: > Configurations and parameters for Redis replication --- -Redis replication configuration can be customized by [values.yaml](https://github.com/OT-CONTAINER-KIT/helm-charts/blob/main/charts/redis-replication/values.yaml). The recommended way of managing the setup is using `helm` but if the setup is not maintained by it, `YAML` CRD parameters can be modified in the manifest. +Redis replication configuration can be customized by [values.yaml](https://github.com/OT-CONTAINER-KIT/redis-operator/blob/master/charts/redis-replication/values.yaml). The recommended way of managing the setup is using `helm` but if the setup is not maintained by it, `YAML` CRD parameters can be modified in the manifest. ## Helm Configuration Parameters -| **Name** | **Value** | **Description** | -|-----------------------------------|--------------------------------|-----------------------------------------------------------------------------------------------| -| `imagePullSecrets` | [] | List of image pull secrets, in case redis image is getting pull from private registry | -| `redisReplication.secretName` | redis-secret | Name of the existing secret in Kubernetes | -| `redisReplication.secretKey` | password | Name of the existing secret key in Kubernetes | -| `redisReplication.image` | quay.io/opstree/redis | Name of the redis image | -| `redisReplication.tag` | v7.0.15 | Tag of the redis image | -| `redisReplication.imagePullPolicy` | IfNotPresent | Image Pull Policy of the redis image | -| `redisReplication.resources` | {} | Request and limits for redis statefulset | -| `externalService.enabled` | false | If redis service needs to be exposed using LoadBalancer or NodePort | -| `externalService.annotations` | {} | Kubernetes service related annotations | -| `externalService.serviceType` | NodePort | Kubernetes service type for exposing service, values - ClusterIP, NodePort, and LoadBalancer | -| `externalService.port` | 6379 | Port number on which redis external service should be exposed | -| `serviceMonitor.enabled` | false | Servicemonitor to monitor redis with Prometheus | -| `serviceMonitor.interval` | 30s | Interval at which metrics should be scraped. | -| `serviceMonitor.scrapeTimeout` | 10s | Timeout after which the scrape is ended | -| `serviceMonitor.namespace` | monitoring | Namespace in which Prometheus operator is running | -| `redisExporter.enabled` | true | Redis exporter should be deployed or not | -| `redisExporter.image` | quay.io/opstree/redis-exporter | Name of the redis exporter image | -| `redisExporter.tag` | v1.44.0 | Tag of the redis exporter image | -| `redisExporter.imagePullPolicy` | IfNotPresent | Image Pull Policy of the redis exporter image | -| `redisExporter.env` | [] | Extra environment variables which needs to be added in redis exporter | -| `nodeSelector` | {} | NodeSelector for redis statefulset | -| `priorityClassName` | "" | Priority class name for the redis statefulset | -| `storageSpec` | {} | Storage configuration for redis setup | -| `securityContext` | {} | Security Context for redis pods for changing system or kernel level parameters | -| `affinity` | {} | Affinity for node and pod for redis statefulset | -| `tolerations` | [] | Tolerations for redis statefulset | -| `sidecars` | [] | Sidecar containers to run alongside Redis pods | +| Key | Type | Default | Description | +|-----------------------------------------------------------------|--------|--------------------------------------------------------------------------|-------------| +| TLS.ca | string | `"ca.key"` | | +| TLS.cert | string | `"tls.crt"` | | +| TLS.key | string | `"tls.key"` | | +| TLS.secret.secretName | string | `""` | | +| acl.secret.secretName | string | `""` | | +| affinity | object | `{}` | | +| env | list | `[]` | | +| externalConfig.data | string | `"tcp-keepalive 400\nslowlog-max-len 158\nstream-node-max-bytes 2048\n"` | | +| externalConfig.enabled | bool | `false` | | +| externalService.enabled | bool | `false` | | +| externalService.port | int | `6379` | | +| externalService.serviceType | string | `"NodePort"` | | +| initContainer.args | list | `[]` | | +| initContainer.command | list | `[]` | | +| initContainer.enabled | bool | `false` | | +| initContainer.env | list | `[]` | | +| initContainer.image | string | `""` | | +| initContainer.imagePullPolicy | string | `"IfNotPresent"` | | +| initContainer.resources | object | `{}` | | +| labels | object | `{}` | | +| nodeSelector | object | `{}` | | +| podSecurityContext.fsGroup | int | `1000` | | +| podSecurityContext.runAsUser | int | `1000` | | +| priorityClassName | string | `""` | | +| redisExporter.enabled | bool | `false` | | +| redisExporter.env | list | `[]` | | +| redisExporter.image | string | `"quay.io/opstree/redis-exporter"` | | +| redisExporter.imagePullPolicy | string | `"IfNotPresent"` | | +| redisExporter.resources | object | `{}` | | +| redisExporter.tag | string | `"v1.44.0"` | | +| redisReplication.clusterSize | int | `3` | | +| redisReplication.ignoreAnnotations | list | `[]` | | +| redisReplication.image | string | `"quay.io/opstree/redis"` | | +| redisReplication.imagePullPolicy | string | `"IfNotPresent"` | | +| redisReplication.imagePullSecrets | list | `[]` | | +| redisReplication.minReadySeconds | int | `0` | | +| redisReplication.name | string | `""` | | +| redisReplication.redisSecret.secretKey | string | `""` | | +| redisReplication.redisSecret.secretName | string | `""` | | +| redisReplication.resources | object | `{}` | | +| redisReplication.serviceType | string | `"ClusterIP"` | | +| redisReplication.tag | string | `"v7.0.15"` | | +| securityContext | object | `{}` | | +| serviceAccountName | string | `""` | | +| serviceMonitor.enabled | bool | `false` | | +| serviceMonitor.interval | string | `"30s"` | | +| serviceMonitor.namespace | string | `"monitoring"` | | +| serviceMonitor.scrapeTimeout | string | `"10s"` | | +| sidecars.env | list | `[]` | | +| sidecars.image | string | `""` | | +| sidecars.imagePullPolicy | string | `"IfNotPresent"` | | +| sidecars.name | string | `""` | | +| sidecars.resources.limits.cpu | string | `"100m"` | | +| sidecars.resources.limits.memory | string | `"128Mi"` | | +| sidecars.resources.requests.cpu | string | `"50m"` | | +| sidecars.resources.requests.memory | string | `"64Mi"` | | +| storageSpec.volumeClaimTemplate.spec.accessModes[0] | string | `"ReadWriteOnce"` | | +| storageSpec.volumeClaimTemplate.spec.resources.requests.storage | string | `"1Gi"` | | +| tolerations | list | `[]` | | \ No newline at end of file diff --git a/pkg/k8sutils/redis-cluster.go b/pkg/k8sutils/redis-cluster.go index 9cc63ecd3..7fe9515dd 100644 --- a/pkg/k8sutils/redis-cluster.go +++ b/pkg/k8sutils/redis-cluster.go @@ -119,7 +119,7 @@ func generateRedisClusterContainerParams(cl kubernetes.Interface, logger logr.Lo if cr.Spec.EnvVars != nil { containerProp.EnvVars = cr.Spec.EnvVars } - if cr.Spec.KubernetesConfig.Service != nil && cr.Spec.KubernetesConfig.Service.ServiceType == "NodePort" { + if cr.Spec.KubernetesConfig.GetServiceType() == "NodePort" { envVars := util.Coalesce(containerProp.EnvVars, &[]corev1.EnvVar{}) *envVars = append(*envVars, corev1.EnvVar{ Name: "NODEPORT", @@ -306,13 +306,9 @@ func (service RedisClusterService) CreateRedisClusterService(cr *redisv1beta2.Re epp = disableMetrics } annotations := generateServiceAnots(cr.ObjectMeta, nil, epp) - additionalServiceAnnotations := map[string]string{} - if cr.Spec.KubernetesConfig.Service != nil { - additionalServiceAnnotations = cr.Spec.KubernetesConfig.Service.ServiceAnnotations - } objectMetaInfo := generateObjectMetaInformation(serviceName, cr.Namespace, labels, annotations) headlessObjectMetaInfo := generateObjectMetaInformation(serviceName+"-headless", cr.Namespace, labels, annotations) - additionalObjectMetaInfo := generateObjectMetaInformation(serviceName+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, additionalServiceAnnotations, epp)) + additionalObjectMetaInfo := generateObjectMetaInformation(serviceName+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp)) err := CreateOrUpdateService(cr.Namespace, headlessObjectMetaInfo, redisClusterAsOwner(cr), disableMetrics, true, "ClusterIP", *cr.Spec.Port, cl) if err != nil { logger.Error(err, "Cannot create headless service for Redis", "Setup.Type", service.RedisServiceRole) @@ -323,17 +319,14 @@ func (service RedisClusterService) CreateRedisClusterService(cr *redisv1beta2.Re logger.Error(err, "Cannot create service for Redis", "Setup.Type", service.RedisServiceRole) return err } - additionalServiceType := "ClusterIP" - if cr.Spec.KubernetesConfig.Service != nil { - additionalServiceType = cr.Spec.KubernetesConfig.Service.ServiceType - if additionalServiceType == "NodePort" { - // If NodePort is enabled, we need to create a service for every redis pod. - // Then use --cluster-announce-ip --cluster-announce-port --cluster-announce-bus-port to make cluster. - err = service.createOrUpdateClusterNodePortService(cr, cl) - if err != nil { - logger.Error(err, "Cannot create nodeport service for Redis", "Setup.Type", service.RedisServiceRole) - return err - } + additionalServiceType := cr.Spec.KubernetesConfig.GetServiceType() + if additionalServiceType == "NodePort" { + // If NodePort is enabled, we need to create a service for every redis pod. + // Then use --cluster-announce-ip --cluster-announce-port --cluster-announce-bus-port to make cluster. + err = service.createOrUpdateClusterNodePortService(cr, cl) + if err != nil { + logger.Error(err, "Cannot create nodeport service for Redis", "Setup.Type", service.RedisServiceRole) + return err } } err = CreateOrUpdateService(cr.Namespace, additionalObjectMetaInfo, redisClusterAsOwner(cr), disableMetrics, false, additionalServiceType, *cr.Spec.Port, cl) diff --git a/pkg/k8sutils/redis-replication.go b/pkg/k8sutils/redis-replication.go index 66c066492..d1287e4f6 100644 --- a/pkg/k8sutils/redis-replication.go +++ b/pkg/k8sutils/redis-replication.go @@ -15,42 +15,49 @@ import ( func CreateReplicationService(cr *redisv1beta2.RedisReplication, cl kubernetes.Interface) error { logger := serviceLogger(cr.Namespace, cr.ObjectMeta.Name) labels := getRedisLabels(cr.ObjectMeta.Name, replication, "replication", cr.ObjectMeta.Labels) - var epp exporterPortProvider + + epp := disableMetrics if cr.Spec.RedisExporter != nil { epp = func() (port int, enable bool) { defaultP := ptr.To(redisExporterPort) return *util.Coalesce(cr.Spec.RedisExporter.Port, defaultP), cr.Spec.RedisExporter.Enabled } - } else { - epp = disableMetrics } + annotations := generateServiceAnots(cr.ObjectMeta, nil, epp) - additionalServiceAnnotations := map[string]string{} - if cr.Spec.KubernetesConfig.Service != nil { - additionalServiceAnnotations = cr.Spec.KubernetesConfig.Service.ServiceAnnotations - } objectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name, cr.Namespace, labels, annotations) headlessObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-headless", cr.Namespace, labels, annotations) - additionalObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, additionalServiceAnnotations, epp)) - err := CreateOrUpdateService(cr.Namespace, headlessObjectMetaInfo, redisReplicationAsOwner(cr), disableMetrics, true, "ClusterIP", redisPort, cl) - if err != nil { + additionalObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp)) + masterLabels := util.MergeMap( + labels, map[string]string{RedisRoleLabelKey: RedisRoleLabelMaster}, + ) + replicaLabels := util.MergeMap( + labels, map[string]string{RedisRoleLabelKey: RedisRoleLabelSlave}, + ) + masterObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-master", cr.Namespace, masterLabels, annotations) + replicaObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-replica", cr.Namespace, replicaLabels, annotations) + + if err := CreateOrUpdateService(cr.Namespace, headlessObjectMetaInfo, redisReplicationAsOwner(cr), disableMetrics, true, "ClusterIP", redisPort, cl); err != nil { logger.Error(err, "Cannot create replication headless service for Redis") return err } - err = CreateOrUpdateService(cr.Namespace, objectMetaInfo, redisReplicationAsOwner(cr), epp, false, "ClusterIP", redisPort, cl) - if err != nil { + if err := CreateOrUpdateService(cr.Namespace, objectMetaInfo, redisReplicationAsOwner(cr), epp, false, "ClusterIP", redisPort, cl); err != nil { logger.Error(err, "Cannot create replication service for Redis") return err } - additionalServiceType := "ClusterIP" - if cr.Spec.KubernetesConfig.Service != nil { - additionalServiceType = cr.Spec.KubernetesConfig.Service.ServiceType - } - err = CreateOrUpdateService(cr.Namespace, additionalObjectMetaInfo, redisReplicationAsOwner(cr), disableMetrics, false, additionalServiceType, redisPort, cl) - if err != nil { + if err := CreateOrUpdateService(cr.Namespace, additionalObjectMetaInfo, redisReplicationAsOwner(cr), disableMetrics, false, cr.Spec.KubernetesConfig.GetServiceType(), redisPort, cl); err != nil { logger.Error(err, "Cannot create additional service for Redis Replication") return err } + if err := CreateOrUpdateService(cr.Namespace, masterObjectMetaInfo, redisReplicationAsOwner(cr), disableMetrics, false, "ClusterIP", redisPort, cl); err != nil { + logger.Error(err, "Cannot create master service for Redis") + return err + } + if err := CreateOrUpdateService(cr.Namespace, replicaObjectMetaInfo, redisReplicationAsOwner(cr), disableMetrics, false, "ClusterIP", redisPort, cl); err != nil { + logger.Error(err, "Cannot create replica service for Redis") + return err + } + return nil } diff --git a/pkg/k8sutils/redis-sentinel.go b/pkg/k8sutils/redis-sentinel.go index 873b05e1c..3d2f4ba6b 100644 --- a/pkg/k8sutils/redis-sentinel.go +++ b/pkg/k8sutils/redis-sentinel.go @@ -220,14 +220,9 @@ func (service RedisSentinelService) CreateRedisSentinelService(cr *redisv1beta2. epp = disableMetrics } annotations := generateServiceAnots(cr.ObjectMeta, nil, epp) - additionalServiceAnnotations := map[string]string{} - if cr.Spec.KubernetesConfig.Service != nil { - additionalServiceAnnotations = cr.Spec.KubernetesConfig.Service.ServiceAnnotations - } - objectMetaInfo := generateObjectMetaInformation(serviceName, cr.Namespace, labels, annotations) headlessObjectMetaInfo := generateObjectMetaInformation(serviceName+"-headless", cr.Namespace, labels, annotations) - additionalObjectMetaInfo := generateObjectMetaInformation(serviceName+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, additionalServiceAnnotations, epp)) + additionalObjectMetaInfo := generateObjectMetaInformation(serviceName+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp)) err := CreateOrUpdateService(cr.Namespace, headlessObjectMetaInfo, redisSentinelAsOwner(cr), disableMetrics, true, "ClusterIP", sentinelPort, cl) if err != nil { @@ -240,11 +235,16 @@ func (service RedisSentinelService) CreateRedisSentinelService(cr *redisv1beta2. return err } - additionalServiceType := "ClusterIP" - if cr.Spec.KubernetesConfig.Service != nil { - additionalServiceType = cr.Spec.KubernetesConfig.Service.ServiceType - } - err = CreateOrUpdateService(cr.Namespace, additionalObjectMetaInfo, redisSentinelAsOwner(cr), disableMetrics, false, additionalServiceType, sentinelPort, cl) + err = CreateOrUpdateService( + cr.Namespace, + additionalObjectMetaInfo, + redisSentinelAsOwner(cr), + disableMetrics, + false, + cr.Spec.KubernetesConfig.GetServiceType(), + sentinelPort, + cl, + ) if err != nil { logger.Error(err, "Cannot create additional service for Redis", "Setup.Type", service.RedisServiceRole) return err diff --git a/pkg/k8sutils/redis-standalone.go b/pkg/k8sutils/redis-standalone.go index 4fed7d135..05a911760 100644 --- a/pkg/k8sutils/redis-standalone.go +++ b/pkg/k8sutils/redis-standalone.go @@ -21,13 +21,9 @@ func CreateStandaloneService(cr *redisv1beta2.Redis, cl kubernetes.Interface) er epp = disableMetrics } annotations := generateServiceAnots(cr.ObjectMeta, nil, epp) - additionalServiceAnnotations := map[string]string{} - if cr.Spec.KubernetesConfig.Service != nil { - additionalServiceAnnotations = cr.Spec.KubernetesConfig.Service.ServiceAnnotations - } objectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name, cr.Namespace, labels, annotations) headlessObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-headless", cr.Namespace, labels, annotations) - additionalObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, additionalServiceAnnotations, epp)) + additionalObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp)) err := CreateOrUpdateService(cr.Namespace, headlessObjectMetaInfo, redisAsOwner(cr), disableMetrics, true, "ClusterIP", redisPort, cl) if err != nil { logger.Error(err, "Cannot create standalone headless service for Redis") @@ -38,11 +34,16 @@ func CreateStandaloneService(cr *redisv1beta2.Redis, cl kubernetes.Interface) er logger.Error(err, "Cannot create standalone service for Redis") return err } - additionalServiceType := "ClusterIP" - if cr.Spec.KubernetesConfig.Service != nil { - additionalServiceType = cr.Spec.KubernetesConfig.Service.ServiceType - } - err = CreateOrUpdateService(cr.Namespace, additionalObjectMetaInfo, redisAsOwner(cr), disableMetrics, false, additionalServiceType, redisPort, cl) + err = CreateOrUpdateService( + cr.Namespace, + additionalObjectMetaInfo, + redisAsOwner(cr), + disableMetrics, + false, + cr.Spec.KubernetesConfig.GetServiceType(), + redisPort, + cl, + ) if err != nil { logger.Error(err, "Cannot create additional service for Redis") return err diff --git a/pkg/util/map.go b/pkg/util/map.go new file mode 100644 index 000000000..0add4b4af --- /dev/null +++ b/pkg/util/map.go @@ -0,0 +1,13 @@ +package util + +// MergeMap merges all the label maps received as argument into a single new label map. +func MergeMap(all ...map[string]string) map[string]string { + res := map[string]string{} + + for _, labels := range all { + for k, v := range labels { + res[k] = v + } + } + return res +} diff --git a/tests/e2e-chainsaw/v1beta2/setup/redis-replication/ready-svc.yaml b/tests/e2e-chainsaw/v1beta2/setup/redis-replication/ready-svc.yaml index 3e2e7ccbb..3bb1ba962 100644 --- a/tests/e2e-chainsaw/v1beta2/setup/redis-replication/ready-svc.yaml +++ b/tests/e2e-chainsaw/v1beta2/setup/redis-replication/ready-svc.yaml @@ -89,3 +89,68 @@ spec: redis_setup_type: replication role: replication type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/port: "9121" + prometheus.io/scrape: "true" + redis.opstreelabs.in: "true" + redis.opstreelabs.instance: redis-replication + labels: + app: redis-replication + redis-role: master + redis_setup_type: replication + role: replication + name: redis-replication-master + ownerReferences: + - apiVersion: redis.redis.opstreelabs.in/v1beta2 + controller: true + kind: RedisReplication + name: redis-replication +spec: + ports: + - name: redis-client + port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: redis-replication + redis-role: master + redis_setup_type: replication + role: replication + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + annotations: + prometheus.io/port: "9121" + prometheus.io/scrape: "true" + redis.opstreelabs.in: "true" + redis.opstreelabs.instance: redis-replication + labels: + app: redis-replication + redis-role: slave + redis_setup_type: replication + role: replication + name: redis-replication-replica + ownerReferences: + - apiVersion: redis.redis.opstreelabs.in/v1beta2 + controller: true + kind: RedisReplication + name: redis-replication +spec: + ports: + - name: redis-client + port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: redis-replication + redis-role: slave + redis_setup_type: replication + role: replication + sessionAffinity: None + type: ClusterIP