@@ -2,12 +2,16 @@ package k8sutils
22
33import (
44 "context"
5+ "fmt"
56 "strconv"
67 "strings"
78
9+ common "github.com/OT-CONTAINER-KIT/redis-operator/api/common/v1beta2"
810 rcvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/rediscluster/v1beta2"
11+ "github.com/OT-CONTAINER-KIT/redis-operator/internal/image"
912 "github.com/OT-CONTAINER-KIT/redis-operator/internal/util"
1013 corev1 "k8s.io/api/core/v1"
14+ "k8s.io/apimachinery/pkg/api/resource"
1115 "k8s.io/apimachinery/pkg/util/intstr"
1216 "k8s.io/client-go/kubernetes"
1317 "k8s.io/utils/ptr"
@@ -283,6 +287,16 @@ func (service RedisClusterSTS) CreateRedisClusterSetup(ctx context.Context, cr *
283287 labels := getRedisLabels (stateFulName , cluster , service .RedisStateFulType , cr .ObjectMeta .Labels )
284288 annotations := generateStatefulSetsAnots (cr .ObjectMeta , cr .Spec .KubernetesConfig .IgnoreAnnotations )
285289 objectMetaInfo := generateObjectMetaInformation (stateFulName , cr .Namespace , labels , annotations )
290+
291+ // Prepare sidecars: combine user-defined sidecars with automatic role detector
292+ sidecars := []common.Sidecar {}
293+ if cr .Spec .Sidecars != nil {
294+ sidecars = append (sidecars , * cr .Spec .Sidecars ... )
295+ }
296+ // Always add Redis agent sidecar for Redis Cluster
297+ redisAgentSidecar := generateAgentSidecar (cr )
298+ sidecars = append (sidecars , redisAgentSidecar )
299+
286300 err := CreateOrUpdateStateFul (
287301 ctx ,
288302 cl ,
@@ -292,7 +306,7 @@ func (service RedisClusterSTS) CreateRedisClusterSetup(ctx context.Context, cr *
292306 redisClusterAsOwner (cr ),
293307 generateRedisClusterInitContainerParams (cr ),
294308 generateRedisClusterContainerParams (ctx , cl , cr , service .SecurityContext , service .ReadinessProbe , service .LivenessProbe , service .RedisStateFulType , service .Resources ),
295- cr . Spec . Sidecars ,
309+ & sidecars ,
296310 )
297311 if err != nil {
298312 log .FromContext (ctx ).Error (err , "Cannot create statefulset for Redis" , "Setup.Type" , service .RedisStateFulType )
@@ -390,3 +404,82 @@ func (service RedisClusterService) createOrUpdateClusterNodePortService(ctx cont
390404 }
391405 return nil
392406}
407+
408+ // generateAgentSidecar creates a Redis agent sidecar configuration for Redis Cluster
409+ // The agent currently performs role detection and may be extended with additional functionality in the future
410+ func generateAgentSidecar (cr * rcvb2.RedisCluster ) common.Sidecar {
411+ operatorImage , _ := util .CoalesceEnv ("OPERATOR_IMAGE" , image .GetOperatorImage ())
412+ redisPort := "6379"
413+ if cr .Spec .Port != nil {
414+ redisPort = fmt .Sprintf ("%d" , * cr .Spec .Port )
415+ }
416+ envVars := []corev1.EnvVar {
417+ {
418+ Name : "POD_NAME" ,
419+ ValueFrom : & corev1.EnvVarSource {
420+ FieldRef : & corev1.ObjectFieldSelector {
421+ FieldPath : "metadata.name" ,
422+ },
423+ },
424+ },
425+ {
426+ Name : "POD_NAMESPACE" ,
427+ ValueFrom : & corev1.EnvVarSource {
428+ FieldRef : & corev1.ObjectFieldSelector {
429+ FieldPath : "metadata.namespace" ,
430+ },
431+ },
432+ },
433+ }
434+
435+ // Add Redis password environment variable if configured
436+ if cr .Spec .KubernetesConfig .ExistingPasswordSecret != nil {
437+ envVars = append (envVars , corev1.EnvVar {
438+ Name : "REDIS_PASSWORD" ,
439+ ValueFrom : & corev1.EnvVarSource {
440+ SecretKeyRef : & corev1.SecretKeySelector {
441+ LocalObjectReference : corev1.LocalObjectReference {
442+ Name : * cr .Spec .KubernetesConfig .ExistingPasswordSecret .Name ,
443+ },
444+ Key : * cr .Spec .KubernetesConfig .ExistingPasswordSecret .Key ,
445+ },
446+ },
447+ })
448+ }
449+
450+ // Default resource requirements for role detector
451+ resources := & corev1.ResourceRequirements {
452+ Requests : corev1.ResourceList {
453+ corev1 .ResourceCPU : resource .MustParse ("10m" ),
454+ corev1 .ResourceMemory : resource .MustParse ("32Mi" ),
455+ },
456+ Limits : corev1.ResourceList {
457+ corev1 .ResourceCPU : resource .MustParse ("50m" ),
458+ corev1 .ResourceMemory : resource .MustParse ("64Mi" ),
459+ },
460+ }
461+
462+ // Build complete command with arguments
463+ command := []string {
464+ "/operator" ,
465+ "agent" ,
466+ "server" ,
467+ "--redis-addr=127.0.0.1:" + redisPort ,
468+ "--detect-interval=10s" ,
469+ }
470+
471+ if cr .Spec .KubernetesConfig .ExistingPasswordSecret != nil {
472+ command = append (command , "--redis-password=$(REDIS_PASSWORD)" )
473+ }
474+
475+ return common.Sidecar {
476+ Name : "agent" ,
477+ Image : operatorImage ,
478+ ImagePullPolicy : corev1 .PullIfNotPresent ,
479+ Command : command ,
480+ EnvVars : & envVars ,
481+ Resources : resources ,
482+ // SecurityContext can be omitted - the container image already runs as non-root
483+ // and inherits pod-level security context if needed
484+ }
485+ }
0 commit comments