Skip to content

feat: Add Valkey Sentinel & HAProxy support in High Availability setup. - #137

Closed
khtee wants to merge 16 commits into
valkey-io:mainfrom
khtee:main
Closed

khtee wants to merge 16 commits into
valkey-io:mainfrom
khtee:main

Conversation

@khtee

@khtee khtee commented Feb 6, 2026

Copy link
Copy Markdown

Feat #22

@dmaes

dmaes commented Feb 11, 2026

Copy link
Copy Markdown

Nice work!

I have some notes/questions:

@khtee

khtee commented Feb 11, 2026

Copy link
Copy Markdown
Author

Nice work!

I have some notes/questions:

Good points! Will work on both improvements.

@yoannrt

yoannrt commented Feb 11, 2026

Copy link
Copy Markdown
Contributor

Good job,

I have some questions too,
I assume to discover who is master, you have to ask sentinel SENTINEL GET-MASTER-ADDR-BY-NAME mymaster ?
(Currently, the replica service is sticked to pod-0 in the STS)

Also, would that make sense to run sentinel as a side container in the replica STS pods ?

@amontalban

Copy link
Copy Markdown
Contributor

Thank you @khtee can't wait to get this merged in 🙏

@dmaes

dmaes commented Feb 14, 2026

Copy link
Copy Markdown

Also, would that make sense to run sentinel as a side container in the replica STS pods ?

You'll want to disable the default statefulset when sentinel is enabled

I got confused, thinking valkey-sentinel also runs the server process, it's been a while since I used redis/valkey. But yes, @khtee you'll want to run sentinel and the server side-to-side in the same pod, don't split them out in different statefulsets.

@yoannrt

yoannrt commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Do you plan on adding a HAProxy deployment, so clients don't have to be aware of sentinel?

@dmaes I guess when you suggest to implement HAproxy, it's for sentinel incompatible clients workloads ?
So this would be optional and the default implementation would be a valkey/sentinel HA setup ?

@khtee
khtee marked this pull request as draft February 18, 2026 23:57
@khtee khtee changed the title feat: Add Valkey Sentinel support in High Availability setup. feat: Add Valkey Sentinel & HAProxy support in High Availability setup. Feb 19, 2026
@khtee
khtee marked this pull request as ready for review February 19, 2026 01:19
@khtee
khtee marked this pull request as draft February 19, 2026 01:30
@khtee
khtee marked this pull request as ready for review February 19, 2026 06:11
@khtee

khtee commented Feb 19, 2026

Copy link
Copy Markdown
Author

Also, would that make sense to run sentinel as a side container in the replica STS pods ?

You'll want to disable the default statefulset when sentinel is enabled

I got confused, thinking valkey-sentinel also runs the server process, it's been a while since I used redis/valkey. But yes, @khtee you'll want to run sentinel and the server side-to-side in the same pod, don't split them out in different statefulsets.

Added following enhancements.

  • Sentinel now runs as a sidecar in valkey pod.
  • HAProxy with sidecar watcher to track failover.

@dmaes

dmaes commented Feb 19, 2026

Copy link
Copy Markdown

Do you plan on adding a HAProxy deployment, so clients don't have to be aware of sentinel?

@dmaes I guess when you suggest to implement HAproxy, it's for sentinel incompatible clients workloads ? So this would be optional and the default implementation would be a valkey/sentinel HA setup ?

That's correct.

The truly kubernetes-native way would probably be to have a sentinel-master Service, using a sentinel.valkey.io/master: "true" label selector, and then some watcher that updates that label on the correct Pod,
but a HAproxy deployment is the easier option to implement, and is how most other Redis charts do it.

Comment thread valkey/values.yaml Outdated
Comment thread valkey/templates/haproxy-deployment.yaml Outdated
Comment thread valkey/templates/haproxy-deployment.yaml
Comment thread valkey/values.yaml Outdated
Comment thread valkey/values.yaml
khtee and others added 5 commits February 20, 2026 09:53
Signed-off-by: KHTee <teekahhui@hotmail.com>
Co-authored-by: Dieter Maes <dieter.maes@dmaes.be>
Signed-off-by: khtee <75174583+khtee@users.noreply.github.com>
Signed-off-by: KHTee <teekahhui@hotmail.com>
Allow HAProxy to retry DNS resolution during startup when pending for Valkey node to start.

Essentially it does the following

- Try to use the last known IP.
- If none, query the libc resolver (DNS).
- If that fails, resolve to none (meaning the server has no IP address yet, but HAProxy won't crash) and wait for the runtime resolver health-checks to pick up the DNS correctly.

Signed-off-by: KHTee <teekahhui@hotmail.com>
@lazariv

lazariv commented Mar 2, 2026

Copy link
Copy Markdown

Waiting for this to be merged. Thanks for your work!

Comment thread valkey/templates/haproxy-configmap.yaml Outdated
Comment thread valkey/templates/haproxy-deployment.yaml
Comment thread valkey/values.yaml Outdated
Comment thread valkey/values.schema.json
jose and others added 3 commits April 7, 2026 14:29
- Updating HAProxy watcher for near-instant IP-based failover.
- Refactoring init scripts to support dynamic topology and universal auth/TLS injection.
- Adding smart L7 health checks in HAProxy to handle ACL-protected nodes.
- Fully parameterizing Service and ConfigMap ports for end-to-end flexibility.
…schema

Valkey Sentinel: Fixing Auth/ACL gaps in TLS environments and security hardening (Enhancements for PR valkey-io#137)
@@ -188,3 +188,34 @@ Validate replica authentication configuration
{{- end }}
{{- end -}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{{/*
Validate haproxy is used in replica mode
*/}}
{{- define "valkey.validateHaproxyRequirements" -}}
{{- if and .Values.haproxy.enabled (not .Values.replica.enabled) }}
{{- fail "Haproxy is only relevant in replica mode with clients incompatible with Sentinel." }}
{{- end }}
{{- end -}}
  • update of deploy_valkey.yaml to fail if haproxy is enabled in standalone mode.
Suggested change
{{- include "valkey.validateHaproxyRequirements" . }}

@lazariv lazariv left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redis/Valkey pub/sub (SUBSCRIBE) connections are long-lived and idle by design — they block waiting for messages. HAProxy's timeout client/timeout server treats them as stale and drops them, causing clients to see ConnectionError: Connection closed by server and forcing reconnect loops.

Adding timeout tunnel to the HAProxy defaults section solves this cleanly. In HAProxy, timeout tunnel governs bidirectional connections after the initial handshake — exactly the pattern pub/sub uses. Setting it to 0 keeps SUBSCRIBE connections alive indefinitely while preserving normal client/server timeouts as a safety net for regular command connections.

Without this, users running any pub/sub workload (Socket.IO, Celery, Sidekiq, etc.) through HAProxy must either set client/server timeouts to 0 (triggering HAProxy warnings) or accept periodic disconnects.

log global
timeout connect {{ .Values.haproxy.config.timeout.connect }}
timeout client {{ .Values.haproxy.config.timeout.client }}
timeout server {{ .Values.haproxy.config.timeout.server }}

@lazariv lazariv Apr 13, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
timeout server {{ .Values.haproxy.config.timeout.server }}
timeout server {{ .Values.haproxy.config.timeout.server }}
timeout tunnel {{ .Values.haproxy.config.timeout.tunnel }}
option clitcpka
option srvtcpka

Comment thread valkey/values.schema.json
},
"server": {
"type": "string"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
},
"tunnel": {
"type": "string"
}

Comment thread valkey/values.yaml
timeout:
connect: 5s
client: 1m
server: 1m

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
server: 1m
server: 1m
# Timeout for long-lived bidirectional connections (e.g. pub/sub).
# Set to 0 to keep pub/sub SUBSCRIBE connections alive indefinitely.
tunnel: 0s

@jose-10000

Copy link
Copy Markdown

I've implemented a preStop hook. I found that improper shutdowns during updates were tripping up Sentinel and risked data loss, so this change ensures a more graceful exit. I made a new pull request @khtee

@jose-10000

jose-10000 commented Apr 30, 2026

Copy link
Copy Markdown

I've added the workloadAnnotations block to haproxy-deployment.yaml. I noticed that the upstream main branch recently introduced workloadAnnotations for other workloads, so adding it here ensures HAProxy is aligned with main once this PR is eventually merged.

Do you have a rough ETA for this merge? Please let me know if there is anything else I can help review or test to get this PR over the finish line. I'm planning to adopt these changes soon and would like to have an idea of when it might be merged. Thanks!

@jose-10000

Copy link
Copy Markdown

I have some reservations about the approach of running Sentinel as a sidecar within the same pod as the Valkey instance.

The main concern is related to Helm upgrade workflows: when a pod is taken down during a rolling update or a Helm upgrade, the entire pod is terminated — including both the Valkey container and the Sentinel sidecar. This means we lose a Sentinel node during the upgrade process.

Losing a Sentinel during an upgrade can temporarily break the quorum. For example, in a typical 3-Sentinel setup, losing one during an upgrade leaves only 2 Sentinels, which may still meet quorum — but in smaller or less redundant setups, this can prevent failover from working correctly during the exact moment it may be needed most.

A more resilient architecture would deploy Sentinels as independent pods (e.g., via a separate StatefulSet), decoupled from the Valkey data pods. This ensures that Sentinel availability is not tied to the lifecycle of the data nodes, preserving quorum integrity throughout rolling updates and upgrades.

@dmaes

dmaes commented May 18, 2026

Copy link
Copy Markdown

@jose-10000 across all other best known redis sentinel helm charts, running in the same pod is the most common setup, and has been working just fine for most people. So I (and I think that goes for others too), never really considered using different statefulsets?

@jose-10000

Copy link
Copy Markdown

@jose-10000 across all other best known redis sentinel helm charts, running in the same pod is the most common setup, and has been working just fine for most people. So I (and I think that goes for others too), never really considered using different statefulsets?

Thanks for the context, @dmaes! Totally makes sense, I know most charts (like Bitnami) do it this way to keep things simplier. I just wanted to point out that coupling their lifecycles can be tricky for quorum during upgrades, but I'm fine keeping the current approach. Just wanted to share my two cents

@trabelsieyal

Copy link
Copy Markdown

Any idea when will this be released? can be amazing

@mlimardo1984

Copy link
Copy Markdown

Any idea when will this be released? can be amazing

Hello Team, just want to reiterate here that implementation is great and we are very much looking forward to have it released. Is there any news about it?

Thanks!

@jsoref

jsoref commented Jun 9, 2026

Copy link
Copy Markdown

@Nils98Ar

Copy link
Copy Markdown

@khtee You could add missing sign-offs in the last e.g. 10 commits via commit amend like this and force push:

git rebase HEAD~10 --exec 'git log -1 --format=%B | grep -qi "^Signed-off-by:" || git commit --amend -s --no-edit'
git push --force-with-lease

Comment on lines 329 to 330
- name: {{ $key }}
value: "{{ $val }}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it even cleaner to do this instead? #133

@kaisen-san

Copy link
Copy Markdown

Just FYI, besides the valid review comments people left on this PR, which I think should be taken into consideration, it also needs to be rebased, and some tests are failing. I also ran some local analysis and noted a few things that could be improved – I'll post the findings in another comment. I'm saying all this because I've noticed some people are expecting this to be merged, but I'm not sure if that will happen anytime soon (hope I'm wrong! 🙂)

@yoannrt

yoannrt commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

across all other best known redis sentinel helm charts, running in the same pod is the most common setup, and has been working just fine for most people. So I (and I think that goes for others too), never really considered using different statefulsets?

Hi @dmaes , I thought too running sentinel as a sidecar was the simplest/cleaner option but I'm reconsidering it since having those components in 2 different sts has some advantages.
@khtee I think you were in the right way from the beginning so I sent you a PR, see khtee#4 . Thanks again

@pat-s

pat-s commented Jul 28, 2026

Copy link
Copy Markdown

@daanvinken @Bloodraven21
Pinging you here as you've been most active lately in committing to main.

It would really be great to finalize this feature (in here or a separate clean branch) so this can finally find it's way in. I am also happy to clean up if there's a commitment to review and get this merged then, avoiding additional future conflicts.

Looking forwarding hearing back from you and getting HA support into the chart!

@kaisen-san

kaisen-san commented Jul 28, 2026

Copy link
Copy Markdown

@daanvinken @Bloodraven21 Pinging you here as you've been most active lately in committing to main.

It would really be great to finalize this feature (in here or a separate clean branch) so this can finally find it's way in. I am also happy to clean up if there's a commitment to review and get this merged then, avoiding additional future conflicts.

Looking forwarding hearing back from you and getting HA support into the chart!

Same. I have some improvements I'd like to submit, but I'm not sure if it's worth trying to include them in this PR or creating a separate one.

@Bloodraven21

Copy link
Copy Markdown
Collaborator

first can you rebase and make it up to date

second give me a exact values files to test it out on local

@Bloodraven21

Bloodraven21 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

@daanvinken @Bloodraven21 Pinging you here as you've been most active lately in committing to main.
It would really be great to finalize this feature (in here or a separate clean branch) so this can finally find it's way in. I am also happy to clean up if there's a commitment to review and get this merged then, avoiding additional future conflicts.
Looking forwarding hearing back from you and getting HA support into the chart!

Same. I have some improvements I'd like to submit, but I'm not sure if it's worth trying to include them in this PR or creating a separate one.

please make a spearate pr and raise it will look into it

@Bloodraven21

Copy link
Copy Markdown
Collaborator

@daanvinken @Bloodraven21 Pinging you here as you've been most active lately in committing to main.

It would really be great to finalize this feature (in here or a separate clean branch) so this can finally find it's way in. I am also happy to clean up if there's a commitment to review and get this merged then, avoiding additional future conflicts.

Looking forwarding hearing back from you and getting HA support into the chart!

please create a spearate one

danylo-ironsail pushed a commit to Ironsail-llc/valkey-helm that referenced this pull request Aug 25, 2026
PR valkey-io#137 hardcodes `podManagementPolicy: Parallel`, unguarded by sentinel and
with no values knob. Two problems for existing non-sentinel users:

- the field is IMMUTABLE, so applying it to an existing StatefulSet is
  rejected by the API server; adopting this chart would break the sync
- Parallel restarts every pod at once, where OrderedReady rolls the primary
  last -- for a replicated cache that turns a brief blip into a full outage

Now defaults to Parallel only when replica.sentinel.enabled (sentinel does
need pods up together to form quorum) and OrderedReady otherwise, matching
upstream. Overridable via .Values.podManagementPolicy.

Verified: production values (sentinel off) render OrderedReady, sentinel
values render Parallel. helm lint clean; unittest unchanged at 136 passed /
10 failed (those 10 pre-date this branch).

Worth upstreaming to valkey-io#137.
danylo-ironsail pushed a commit to Ironsail-llc/valkey-helm that referenced this pull request Aug 25, 2026
The watcher polls each Sentinel in turn to find the current master, using
valkey-cli with no -t. When the pod hosting the first Sentinel is the one that
just died, that connect blocks on TCP SYN retries -- ~127s with the default
tcp_syn_retries=6 -- before falling through to a live peer.

Measured in qa1 on a settled 3-node cluster: Sentinel promoted a replica in
~6s, but the watcher did not observe it for 141s, so HAProxy kept pointing at
the dead primary the whole time. Writes through the HAProxy endpoint failed
for the entire window (0 OK / 7 FAIL over a 150s poll). That is worse than
having no failover at all, and it is the single thing preventing this from
being production-usable.

Now bounded by haproxy.sentinelWatcher.connectTimeout (default 1s), so a dead
peer costs ~1s instead of ~127s.

Worth upstreaming to valkey-io#137 -- it makes the difference between advertised
"near-instant IP-based failover" and a two-minute outage.
danylo-ironsail pushed a commit to Ironsail-llc/valkey-helm that referenced this pull request Aug 25, 2026
…ontrols

Two problems found running this in production.

1. The PDB selects on name+instance only, and the HAProxy pods carry both.
   With haproxy.enabled the PDB covered 6 pods instead of 3, so minAvailable:2
   allowed 4 disruptions -- a drain could evict every StatefulSet pod while
   HAProxy alone satisfied the budget. Observed live: expected=6, allowed=4.
   Now excludes component=haproxy when HAProxy is on.

2. haproxy-deployment had no nodeSelector/affinity/topologySpreadConstraints/
   tolerations at all, so all replicas can land on one node. It fronts the
   write path, so it needs the same scheduling controls the StatefulSet has.

Both worth upstreaming to valkey-io#137.
@sgissi

sgissi commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Closing in favor of #234

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.