You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[chart/redis-ha][BUG] Generated haproxy backend config is not IPv6-safe (start-time-only resolution, no resolvers, unbracketed addresses) #420
config-haproxy_init.sh resolves each announce Service DNS name once at container start and seds the raw IP into the generated haproxy.cfg (server Rn <addr>:port, tcp-check expect string REPLACE_ANNOUNCEn). On a dual-stack or IPv6-primary cluster:
The resolved address can be IPv6, and server <unbracketed-v6>:<port> is invalid HAProxy syntax (requires [addr]:port).
There is no resolvers section, so backends never re-resolve at runtime — announce DNS changes (pod/Service recreation) require a haproxy restart.
To Reproduce.
Dual-stack cluster where announce Service names resolve AAAA (or announce Services converted to IPv6-only).
Generated backend config works regardless of address family: at minimum bracket IPv6 literals (JoinHostPort-style); ideally emit FQDN server lines plus a resolvers section pointing at kube-dns so backends re-resolve at runtime.
Additional context.
The sentinel.{resolveHostnames,announceHostnames} path already produces FQDN server lines — recommending it for dual-stack (or making FQDN+resolvers the default posture) would close this. HAProxy itself supports everything needed (bracketed literals; resolvers with AAAA since 1.8). Reproduce details verified against redis-ha 4.38.0 consumed via argo-cd 10.4.2 on GKE dual-stack. I'm willing to open a PR for this.
Correction after digging into the chart source (verified redis-ha-4.38.0 through current master — charts/redis-ha/templates/_configs.tpl is unchanged between them): the server Rn <addr>:port part of the repro doesn't hold.
The server R{{ $i }} lines are rendered with the announce Service DNS names (server R0 <release>-redis-ha-announce-0:26379), not resolved IPs — haproxy resolves them itself at startup.
The only place config-haproxy_init.sh interpolates the resolved address is tcp-check expect string REPLACE_ANNOUNCEn, which is a substring match against Sentinel's reply, not an address position. An unbracketed IPv6 there is valid — and required to match: the pod sets sentinel announce-ip to the same bare getent result, so Sentinel replies with the bare IPv6. Bracketing the expect string would actually break master detection (check_if_redis_is_master_* would never pass → the use-server conditions would never fire).
The part that does hold: there's no resolvers section, so the DNS-based server lines are resolved once at startup and never re-resolved — announce Service/pod recreation requires a haproxy restart. That's the gap worth fixing here (FQDN server lines + resolvers pointing at kube-dns, or defaulting sentinel.resolveHostnames/sentinel.announceHostnames on), and sentinel.resolveHostnames: true + sentinel.announceHostnames: true works as a posture on dual-stack today.
Suggest refocusing this issue on runtime re-resolution — happy to test a PR direction.
Activity
aqeelat commentedon Sep 4, 2026
Correction after digging into the chart source (verified
redis-ha-4.38.0through currentmaster—charts/redis-ha/templates/_configs.tplis unchanged between them): theserver Rn <addr>:portpart of the repro doesn't hold.server R{{ $i }}lines are rendered with the announce Service DNS names (server R0 <release>-redis-ha-announce-0:26379), not resolved IPs — haproxy resolves them itself at startup.config-haproxy_init.shinterpolates the resolved address istcp-check expect string REPLACE_ANNOUNCEn, which is a substring match against Sentinel's reply, not an address position. An unbracketed IPv6 there is valid — and required to match: the pod setssentinel announce-ipto the same baregetentresult, so Sentinel replies with the bare IPv6. Bracketing the expect string would actually break master detection (check_if_redis_is_master_*would never pass → theuse-serverconditions would never fire).The part that does hold: there's no
resolverssection, so the DNS-based server lines are resolved once at startup and never re-resolved — announce Service/pod recreation requires a haproxy restart. That's the gap worth fixing here (FQDN server lines +resolverspointing at kube-dns, or defaultingsentinel.resolveHostnames/sentinel.announceHostnameson), andsentinel.resolveHostnames: true+sentinel.announceHostnames: trueworks as a posture on dual-stack today.Suggest refocusing this issue on runtime re-resolution — happy to test a PR direction.