Skip to content

[chart/redis-ha][BUG] Generated haproxy backend config is not IPv6-safe (start-time-only resolution, no resolvers, unbracketed addresses) #420

Open

Description

@aqeelat

Describe the bug.

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:

  1. The resolved address can be IPv6, and server <unbracketed-v6>:<port> is invalid HAProxy syntax (requires [addr]:port).
  2. There is no resolvers section, so backends never re-resolve at runtime — announce DNS changes (pod/Service recreation) require a haproxy restart.

To Reproduce.

  1. Dual-stack cluster where announce Service names resolve AAAA (or announce Services converted to IPv6-only).
  2. Default values (sentinel.resolveHostnames: false, sentinel.announceHostnames: false).
  3. Init script writes server Rn 2600:…:6379 style lines → invalid config.

Expected behavior.

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.

Activity

  1. aqeelat commented on Sep 4, 2026

    @aqeelat
    Author

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions