Skip to content

Commit 34e8fec

Browse files
pcamminadiclaude
andcommitted
fix: use pod FQDN for replica-announce-ip and sentinel announce-ip
When running Redis Replication with Sentinel behind a service mesh (e.g. Istio), pod IPs can be non-routable loopback addresses. This adds resolveHostnames/announceHostnames fields to RedisReplicationSpec so that replicas and sentinels announce their FQDN instead of their pod IP. Also fixes a bug where sentinel announce-ip was incorrectly set to the master's address instead of the sentinel's own address. Signed-off-by: pcamminadi <53015959+pcamminadi@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9299c99 commit 34e8fec

File tree

8 files changed

+83
-3
lines changed

8 files changed

+83
-3
lines changed

api/redisreplication/v1beta2/redisreplication_types.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,15 @@ type RedisReplicationSpec struct {
3030
EnvVars *[]corev1.EnvVar `json:"env,omitempty"`
3131
TopologySpreadConstrains []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"`
3232
HostPort *int `json:"hostPort,omitempty"`
33-
Sentinel *Sentinel `json:"sentinel,omitempty"`
33+
// ResolveHostnames enables resolving hostnames instead of using IP addresses. Set to "yes" to enable.
34+
// Required when running with a service mesh (e.g. Istio) where pod IPs may not be routable.
35+
// +kubebuilder:default:="no"
36+
ResolveHostnames string `json:"resolveHostnames,omitempty"`
37+
// AnnounceHostnames enables announcing hostnames (FQDN) instead of IP addresses. Set to "yes" to enable.
38+
// When enabled, replica-announce-ip and sentinel announce-ip will use the pod's FQDN.
39+
// +kubebuilder:default:="no"
40+
AnnounceHostnames string `json:"announceHostnames,omitempty"`
41+
Sentinel *Sentinel `json:"sentinel,omitempty"`
3442
}
3543

3644
type Sentinel struct {

charts/redis-operator/crds/crds.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14351,6 +14351,12 @@ spec:
1435114351
type: array
1435214352
type: object
1435314353
type: object
14354+
announceHostnames:
14355+
default: "no"
14356+
description: |-
14357+
AnnounceHostnames enables announcing hostnames (FQDN) instead of IP addresses. Set to "yes" to enable.
14358+
When enabled, replica-announce-ip and sentinel announce-ip will use the pod's FQDN.
14359+
type: string
1435414360
clusterSize:
1435514361
format: int32
1435614362
type: integer
@@ -15909,6 +15915,12 @@ spec:
1590915915
required:
1591015916
- image
1591115917
type: object
15918+
resolveHostnames:
15919+
default: "no"
15920+
description: |-
15921+
ResolveHostnames enables resolving hostnames instead of using IP addresses. Set to "yes" to enable.
15922+
Required when running with a service mesh (e.g. Istio) where pod IPs may not be routable.
15923+
type: string
1591215924
securityContext:
1591315925
description: |-
1591415926
SecurityContext holds security configuration that will be applied to a container.

charts/redis-replication/templates/redis-replication.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ spec:
117117
{{- if .Values.env }}
118118
env: {{ toYaml .Values.env | nindent 4 }}
119119
{{- end }}
120+
{{- if .Values.resolveHostnames }}
121+
resolveHostnames: {{ .Values.resolveHostnames | quote }}
122+
{{- end }}
123+
{{- if .Values.announceHostnames }}
124+
announceHostnames: {{ .Values.announceHostnames | quote }}
125+
{{- end }}
120126
{{- if .Values.pdb.enabled }}
121127
pdb:
122128
enabled: {{ .Values.pdb.enabled }}

charts/redis-replication/values.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,12 @@ env: []
195195
# - name: VAR_NAME
196196
# value: "value1"
197197

198+
# -- Set to "yes" to resolve and announce hostnames instead of IPs.
199+
# Required when running with service mesh (e.g. Istio) where pod IPs may be loopback addresses.
200+
# When enabled, replica-announce-ip will use the pod's FQDN instead of its IP.
201+
resolveHostnames: ""
202+
announceHostnames: ""
203+
198204
pdb:
199205
enabled: false
200206
minAvailable: 1

config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,12 @@ spec:
10801080
type: array
10811081
type: object
10821082
type: object
1083+
announceHostnames:
1084+
default: "no"
1085+
description: |-
1086+
AnnounceHostnames enables announcing hostnames (FQDN) instead of IP addresses. Set to "yes" to enable.
1087+
When enabled, replica-announce-ip and sentinel announce-ip will use the pod's FQDN.
1088+
type: string
10831089
clusterSize:
10841090
format: int32
10851091
type: integer
@@ -2638,6 +2644,12 @@ spec:
26382644
required:
26392645
- image
26402646
type: object
2647+
resolveHostnames:
2648+
default: "no"
2649+
description: |-
2650+
ResolveHostnames enables resolving hostnames instead of using IP addresses. Set to "yes" to enable.
2651+
Required when running with a service mesh (e.g. Istio) where pod IPs may not be routable.
2652+
type: string
26412653
securityContext:
26422654
description: |-
26432655
SecurityContext holds security configuration that will be applied to a container.

internal/agent/bootstrap/redis/config.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,21 @@ func GenerateConfig() error {
9595
}
9696
} else {
9797
fmt.Println("Setting up redis in standalone mode")
98+
99+
// For replication mode, set replica-announce-ip to the pod's FQDN so
100+
// that sentinels track replicas by hostname rather than ephemeral pod IP.
101+
// This is required when running with Istio or other service meshes where
102+
// the pod IP seen by Redis (e.g. 127.0.0.6) is not routable externally.
103+
announceHostnames := util.CoalesceEnv1("ANNOUNCE_HOSTNAMES", "no")
104+
resolveHostnames := util.CoalesceEnv1("RESOLVE_HOSTNAMES", "no")
105+
if announceHostnames == "yes" && resolveHostnames == "yes" {
106+
if fqdnName, err := fqdn.FqdnHostname(); err != nil {
107+
log.Printf("Warning: Failed to get FQDN for replica-announce-ip: %v", err)
108+
} else {
109+
cfg.Append("replica-announce-ip", fqdnName)
110+
cfg.Append("replica-announce-port", redisPort)
111+
}
112+
}
98113
}
99114

100115
if tlsMode == "true" {

internal/agent/bootstrap/sentinel/config.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
agentutil "github.com/OT-CONTAINER-KIT/redis-operator/internal/agent/util"
88
"github.com/OT-CONTAINER-KIT/redis-operator/internal/util"
9+
"github.com/Showmax/go-fqdn"
910
)
1011

1112
// defaultSentinelConfig from https://github.com/OT-CONTAINER-KIT/redis/blob/master/sentinel.conf
@@ -74,9 +75,17 @@ func GenerateConfig() error {
7475
cfg.Append("sentinel myid", sentinelID)
7576
}
7677

77-
// If resolveHostnames is set to yes, then we need to announce the hostnames
78+
// If resolveHostnames and announceHostnames are both enabled, announce
79+
// this sentinel's own FQDN hostname so that peer sentinels and clients
80+
// can reach it by DNS name rather than an ephemeral pod IP.
81+
// The `ip` variable holds the *master's* address, NOT the sentinel's own
82+
// address, so we must resolve the sentinel pod's FQDN independently.
7883
if announceHostnames == "yes" && resolveHostnames == "yes" {
79-
cfg.Append("sentinel announce-ip", ip)
84+
if sentinelFQDN, err := fqdn.FqdnHostname(); err != nil {
85+
fmt.Printf("Warning: Failed to get FQDN for sentinel announce-ip: %v\n", err)
86+
} else {
87+
cfg.Append("sentinel announce-ip", sentinelFQDN)
88+
}
8089
}
8190
}
8291

internal/k8sutils/redis-replication.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/common"
99
"github.com/OT-CONTAINER-KIT/redis-operator/internal/util"
1010
"github.com/OT-CONTAINER-KIT/redis-operator/internal/util/maps"
11+
corev1 "k8s.io/api/core/v1"
1112
"k8s.io/client-go/kubernetes"
1213
"k8s.io/utils/ptr"
1314
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -151,6 +152,17 @@ func generateRedisReplicationContainerParams(cr *rrvb2.RedisReplication) contain
151152
if cr.Spec.EnvVars != nil {
152153
containerProp.EnvVars = cr.Spec.EnvVars
153154
}
155+
if cr.Spec.ResolveHostnames == "yes" || cr.Spec.AnnounceHostnames == "yes" {
156+
hostnameEnvVars := []corev1.EnvVar{
157+
{Name: "RESOLVE_HOSTNAMES", Value: cr.Spec.ResolveHostnames},
158+
{Name: "ANNOUNCE_HOSTNAMES", Value: cr.Spec.AnnounceHostnames},
159+
}
160+
if containerProp.EnvVars != nil {
161+
*containerProp.EnvVars = append(*containerProp.EnvVars, hostnameEnvVars...)
162+
} else {
163+
containerProp.EnvVars = &hostnameEnvVars
164+
}
165+
}
154166
if cr.Spec.Storage != nil {
155167
containerProp.AdditionalVolume = cr.Spec.Storage.VolumeMount.Volume
156168
containerProp.AdditionalMountPath = cr.Spec.Storage.VolumeMount.MountPath

0 commit comments

Comments
 (0)