Repository: buildbuddy-io/buildbuddy-helm
Pull request #123: Make redis chart more configurable:
Author: login: vadimberezniker
Created: 2025-05-01T00:57:19Z | Merged: 2025-05-06T14:38:34Z

 - Allow deploying in "sharded" mode using a StatefulSet
 - Allow options other than maxMemory to be specified.


Diff:
diff --git a/charts/buildbuddy-redis/Chart.yaml b/charts/buildbuddy-redis/Chart.yaml
index 4bb71933..01ccc19d 100644
--- a/charts/buildbuddy-redis/Chart.yaml
+++ b/charts/buildbuddy-redis/Chart.yaml
@@ -1,7 +1,7 @@
 apiVersion: v1
 description: BuildBuddy Redis LRU
 name: buildbuddy-redis
-version: 0.0.11 # Chart version
+version: 0.0.12 # Chart version
 appVersion: 5.0.4 # Version of deployed app
 keywords:
   - buildbuddy
diff --git a/charts/buildbuddy-redis/templates/config.yaml b/charts/buildbuddy-redis/templates/config.yaml
index 686dc5e1..db0eaca2 100644
--- a/charts/buildbuddy-redis/templates/config.yaml
+++ b/charts/buildbuddy-redis/templates/config.yaml
@@ -8,7 +8,14 @@ metadata:
     app.kubernetes.io/managed-by: {{ .Release.Service }}
     helm.sh/chart: {{ include "buildbuddy.chart" . }}
 data:
+  {{- /* Make a deep copy of the default config */ -}}
+  {{- $c := deepCopy .Values.config }}
+  {{- /* maxMemory used to be a top level values option. If it's still being used copy it over to the config object. */ -}}
+  {{- if hasKey .Values "maxMemory" }}
+    {{- $_ := set $c "maxmemory" .Values.maxMemory }}
+  {{- end }}
   redis-config-file: |
-    maxmemory {{ .Values.maxMemory }}
-    maxmemory-policy allkeys-lru
-                
+{{- range $k, $v := $c }}
+    {{ $k }} {{ $v }}
+{{- end }}
+
diff --git a/charts/buildbuddy-redis/templates/deployment.yaml b/charts/buildbuddy-redis/templates/deployment.yaml
index fcc9740e..b4954e90 100644
--- a/charts/buildbuddy-redis/templates/deployment.yaml
+++ b/charts/buildbuddy-redis/templates/deployment.yaml
@@ -1,3 +1,4 @@
+{{- if not .Values.sharded }}
 apiVersion: apps/v1
 kind: Deployment
 metadata:
@@ -11,7 +12,7 @@ metadata:
     {{- .Values.extraPodLabels | toYaml | nindent 4 }}
     {{- end }}
 spec:
-  replicas: {{ .Values.replicas | default 1 }}
+  replicas: 1
   strategy:
     type: RollingUpdate
   selector:
@@ -76,3 +77,28 @@ spec:
             items:
               - key: redis-config-file
                 path: redis.conf
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "buildbuddy.name" . }}
+{{- if .Values.service.annotations }}
+  annotations:
+{{ toYaml .Values.service.annotations | indent 4 }}
+{{- end }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    helm.sh/chart: {{ include "buildbuddy.chart" . }}
+spec:
+  selector:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+  type: {{ .Values.service.type }}
+  ports:
+    - name: redis
+      protocol: 'TCP'
+      port: {{ .Values.service.internalRedisPort }}
+      targetPort: {{ .Values.service.internalRedisPort }}
+{{- end }}
diff --git a/charts/buildbuddy-redis/templates/service.yaml b/charts/buildbuddy-redis/templates/service.yaml
deleted file mode 100644
index f2fe3fb2..00000000
--- a/charts/buildbuddy-redis/templates/service.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
-  name: {{ include "buildbuddy.name" . }}
-{{- if .Values.service.annotations }}
-  annotations:
-{{ toYaml .Values.service.annotations | indent 4 }}
-{{- end }}
-  labels:
-    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
-    app.kubernetes.io/instance: {{ .Release.Name }}
-    app.kubernetes.io/managed-by: {{ .Release.Service }}
-    helm.sh/chart: {{ include "buildbuddy.chart" . }}
-spec:
-  selector:
-    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
-    app.kubernetes.io/instance: {{ .Release.Name }}
-  type: {{ .Values.service.type }}
-  ports:
-    - name: redis
-      protocol: 'TCP'
-      port: {{ .Values.service.internalRedisPort }}
-      targetPort: {{ .Values.service.internalRedisPort }}
-
diff --git a/charts/buildbuddy-redis/templates/statefulset.yaml b/charts/buildbuddy-redis/templates/statefulset.yaml
new file mode 100644
index 00000000..e40e2518
--- /dev/null
+++ b/charts/buildbuddy-redis/templates/statefulset.yaml
@@ -0,0 +1,140 @@
+{{- if .Values.sharded }}
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+spec:
+  maxUnavailable: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    helm.sh/chart: {{ include "buildbuddy.chart" . }}
+    {{- if .Values.extraPodLabels }}
+    {{- .Values.extraPodLabels | toYaml | nindent 4 }}
+    {{- end }}
+spec:
+  replicas: {{ .Values.replicas }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  serviceName: {{ include "buildbuddy.fullname" . }}
+  template:
+    metadata:
+      annotations:
+        {{- if .Values.extraPodAnnotations }}
+        {{- .Values.extraPodAnnotations | toYaml | nindent 8 }}
+        {{- end }}
+      labels:
+        app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        app.kubernetes.io/managed-by: {{ .Release.Service }}
+        helm.sh/chart: {{ include "buildbuddy.chart" . }}
+        {{- if .Values.extraPodLabels }}
+        {{- .Values.extraPodLabels | toYaml | nindent 8 }}
+        {{- end }}
+    spec:
+      {{- if .Values.nodeSelector}}
+      nodeSelector:
+        {{- toYaml .Values.nodeSelector | nindent 8 }}
+      {{- end }}
+      {{- if .Values.tolerations}}
+      tolerations:
+        {{- toYaml .Values.tolerations | nindent 8 }}
+      {{- end }}
+      affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchExpressions:
+                  - key: app.kubernetes.io/name
+                    operator: In
+                    values:
+                      - "{{ include "buildbuddy.name" . }}"
+                  - key: app.kubernetes.io/instance
+                    operator: In
+                    values:
+                      - "{{ .Release.Name }}"
+              topologyKey: "kubernetes.io/hostname"
+      containers:
+        - name: {{ .Chart.Name }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+          imagePullPolicy: {{ .Values.image.imagePullPolicy }}
+          command:
+            - redis-server
+            - "/redis-master/redis.conf"
+          resources:
+          {{- if .Values.resources }}
+            {{- .Values.resources | toYaml | nindent 12 }}
+          {{- end }}
+          env:
+          {{- if .Values.extraEnvVars }}
+            {{- .Values.extraEnvVars | toYaml | nindent 10 }}
+          {{- end }}
+          ports:
+            - name: redis
+              containerPort: {{ .Values.service.internalRedisPort }}
+          readinessProbe:
+            exec:
+              command:
+                - redis-cli
+                - info
+            initialDelaySeconds: 10
+            periodSeconds: 5
+          volumeMounts:
+            - mountPath: /redis-master-data
+              name: data
+            - mountPath: /redis-master
+              name: config
+            {{- if .Values.extraVolumeMounts -}}
+            {{ .Values.extraVolumeMounts | toYaml | nindent 12 }}
+            {{- end }}
+      volumes:
+        - name: data
+          emptyDir: {}
+        - name: config
+          configMap:
+            name: {{ include "buildbuddy.fullname" . }}-config
+            items:
+              - key: redis-config-file
+                path: redis.conf
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+{{- if .Values.service.annotations }}
+  annotations:
+{{ toYaml .Values.service.annotations | indent 4 }}
+{{- end }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    helm.sh/chart: {{ include "buildbuddy.chart" . }}
+spec:
+  selector:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+  clusterIP: None
+  publishNotReadyAddresses: true
+  ports:
+    - name: redis
+      protocol: 'TCP'
+      port: 6379
+      targetPort: 6379
+{{- end }}
diff --git a/charts/buildbuddy-redis/values.yaml b/charts/buildbuddy-redis/values.yaml
index a98efd98..5ec532c1 100644
--- a/charts/buildbuddy-redis/values.yaml
+++ b/charts/buildbuddy-redis/values.yaml
@@ -2,17 +2,21 @@
 ## This is a YAML-formatted file.
 ## Declare variables to be passed into your templates.
 
-## The BuildBuddy container image to use.
+## The Redis container image to use.
 image:
   repository: redis
   tag: 5.0.4
   imagePullPolicy: IfNotPresent
 
-## The number of app replicas to run.
-## If setting this number higher than 1, make sure to configure a mysql database (not sqlite) and gcs storage
-## so data can be shared across replicas.
-## Using multiple replicas with a sqlite3 database or disk storage is not supported.
-replicas: 1
+# Whether to create a sharded deployment using a StatefulSet.
+# If set to false, a single replica deployment is created.
+# For most users a single replica Redis instance will be sufficient.
+# Note: since this option affects the type of resources that are created
+# a consistent value should be specified for all helm commands (e.g. upgrade, delete, etc.)
+sharded: false
+## The number of Redis shards (replicas) to run.
+## Only used if "sharded" is set to true.
+replicas: 3
 
 ## The nodeSelector used for placing pods in separate node pools/groups
 # nodeSelector:
@@ -28,8 +32,14 @@ replicas: 1
 #     operator: Equal
 #     value: x86_64
 
-## Maximum memory redis will use, should be less than the kubernetes resource limits below.
-maxMemory: "5gb"
+
+# config specifies options to render in the redis configuration file.
+# The keys and values are materialized as-is inside the redis config.
+# Additional options may be added, if needed.
+config:
+  ## Maximum memory redis will use, should be less than the kubernetes resource limits below.
+  maxmemory: "5gb"
+  maxmemory-policy: "allkeys-lru"
 
 ## The default resources to give redis.
 resources:
@@ -40,7 +50,10 @@ resources:
     cpu: "1"
     memory: "5Gi"
 
-## Exposes the Redis service via a LoadBalancer on the given ports.
+## Exposes the Redis service via a service.
+# Only applicable to non-sharded deployments.
+# For sharded deployments, individual shards must be configured
+# in the BuildBuddy application config.
 service:
   type: ClusterIP
   internalRedisPort: 6379


Reviews:
user: login: sluongng
body: You might need to take a look at charts/buildbuddy-enterprise/templates/config.yaml so that the sharded config could be used with our enterprise helm chart as well.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T09:15:23Z
user: login: vadimberezniker
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T16:11:17Z
user: login: vadimberezniker
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T16:13:16Z
user: login: vadimberezniker
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T16:13:53Z
user: login: vadimberezniker
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T16:28:04Z
user: login: sluongng
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T16:34:11Z
user: login: vadimberezniker
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T19:20:44Z
user: login: sluongng
body: this lgtm. I will do a round of manual testing on Monday before merging this. Could you bump the chart version then it will save me a git push :P 
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T19:39:40Z
user: login: sluongng
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T14:34:40Z
user: login: sluongng
body: tested locally without the podAntiAffinity part and it worked fine.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T14:35:06Z

Review comments:
diff_hunk: @@ -40,7 +47,7 @@ resources:
     cpu: "1"
     memory: "5Gi"
 
-## Exposes the Redis service via a LoadBalancer on the given ports.
+## Exposes the Redis service via a service.
path: charts/buildbuddy-redis/values.yaml
user: login: sluongng
body: Nit: add a line to specify that this is not applicable for sharded configuration because of the Headless Service.
created_at: 2025-05-02T08:57:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2,17 +2,19 @@
 ## This is a YAML-formatted file.
 ## Declare variables to be passed into your templates.
 
-## The BuildBuddy container image to use.
+## The Redis container image to use.
 image:
   repository: redis
   tag: 5.0.4
   imagePullPolicy: IfNotPresent
 
-## The number of app replicas to run.
-## If setting this number higher than 1, make sure to configure a mysql database (not sqlite) and gcs storage
-## so data can be shared across replicas.
-## Using multiple replicas with a sqlite3 database or disk storage is not supported.
-replicas: 1
+# Whether to create a sharded deployment using a StatefulSet.
+# If set to false, a single replica deployment is created.
+# For most users a single replica Redis instance will be sufficient.
+sharded: false
+## The number of Redis shards (replicas) to run.
+## Only used if "sharded" is set to true.
+replicas: 3
path: charts/buildbuddy-redis/values.yaml
user: login: sluongng
body: Nit: this is a bit confusing to have 2 knobs controlling the same thing. What if we replace the "sharded" config with "replicas > 1"?
created_at: 2025-05-02T08:58:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,140 @@
+{{- if .Values.sharded }}
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+spec:
+  maxUnavailable: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    helm.sh/chart: {{ include "buildbuddy.chart" . }}
+    {{- if .Values.extraPodLabels }}
+    {{- .Values.extraPodLabels | toYaml | nindent 4 }}
+    {{- end }}
+spec:
+  replicas: {{ .Values.replicas }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  serviceName: {{ include "buildbuddy.fullname" . }}
+  template:
+    metadata:
+      annotations:
+        {{- if .Values.extraPodAnnotations }}
+        {{- .Values.extraPodAnnotations | toYaml | nindent 8 }}
+        {{- end }}
+      labels:
+        app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        app.kubernetes.io/managed-by: {{ .Release.Service }}
+        helm.sh/chart: {{ include "buildbuddy.chart" . }}
+        {{- if .Values.extraPodLabels }}
+        {{- .Values.extraPodLabels | toYaml | nindent 8 }}
+        {{- end }}
+    spec:
+      {{- if .Values.nodeSelector}}
+      nodeSelector:
+        {{- toYaml .Values.nodeSelector | nindent 8 }}
+      {{- end }}
+      {{- if .Values.tolerations}}
+      tolerations:
+        {{- toYaml .Values.tolerations | nindent 8 }}
+      {{- end }}
+      affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchExpressions:
+                  - key: app.kubernetes.io/name
+                    operator: In
+                    values:
+                      - "{{ include "buildbuddy.name" . }}"
+                  - key: app.kubernetes.io/instance
+                    operator: In
+                    values:
+                      - "{{ .Release.Name }}"
+              topologyKey: "kubernetes.io/hostname"
path: charts/buildbuddy-redis/templates/statefulset.yaml
user: login: sluongng
body: I wonder if this block is too strict and should be customizable. It forces folks who wish to have 3 replicas to have 3 nodes available, which can affect people with a tight hardware budget.
created_at: 2025-05-02T09:10:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,140 @@
+{{- if .Values.sharded }}
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+spec:
+  maxUnavailable: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    helm.sh/chart: {{ include "buildbuddy.chart" . }}
+    {{- if .Values.extraPodLabels }}
+    {{- .Values.extraPodLabels | toYaml | nindent 4 }}
+    {{- end }}
+spec:
+  replicas: {{ .Values.replicas }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  serviceName: {{ include "buildbuddy.fullname" . }}
+  template:
+    metadata:
+      annotations:
+        {{- if .Values.extraPodAnnotations }}
+        {{- .Values.extraPodAnnotations | toYaml | nindent 8 }}
+        {{- end }}
+      labels:
+        app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        app.kubernetes.io/managed-by: {{ .Release.Service }}
+        helm.sh/chart: {{ include "buildbuddy.chart" . }}
+        {{- if .Values.extraPodLabels }}
+        {{- .Values.extraPodLabels | toYaml | nindent 8 }}
+        {{- end }}
+    spec:
+      {{- if .Values.nodeSelector}}
+      nodeSelector:
+        {{- toYaml .Values.nodeSelector | nindent 8 }}
+      {{- end }}
+      {{- if .Values.tolerations}}
+      tolerations:
+        {{- toYaml .Values.tolerations | nindent 8 }}
+      {{- end }}
+      affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchExpressions:
+                  - key: app.kubernetes.io/name
+                    operator: In
+                    values:
+                      - "{{ include "buildbuddy.name" . }}"
+                  - key: app.kubernetes.io/instance
+                    operator: In
+                    values:
+                      - "{{ .Release.Name }}"
+              topologyKey: "kubernetes.io/hostname"
+      containers:
+        - name: {{ .Chart.Name }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+          imagePullPolicy: {{ .Values.image.imagePullPolicy }}
+          command:
+            - redis-server
+            - "/redis-master/redis.conf"
+          resources:
+          {{- if .Values.resources }}
+            {{- .Values.resources | toYaml | nindent 12 }}
+          {{- end }}
+          env:
+          {{- if .Values.extraEnvVars }}
+            {{- .Values.extraEnvVars | toYaml | nindent 10 }}
+          {{- end }}
+          ports:
+            - name: redis
+              containerPort: {{ .Values.service.internalRedisPort }}
+          readinessProbe:
+            exec:
+              command:
+                - redis-cli
+                - info
+            initialDelaySeconds: 10
+            periodSeconds: 5
path: charts/buildbuddy-redis/templates/statefulset.yaml
user: login: sluongng
body: Do we want this in our Deployment manifest as well?
created_at: 2025-05-02T09:10:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2,17 +2,19 @@
 ## This is a YAML-formatted file.
 ## Declare variables to be passed into your templates.
 
-## The BuildBuddy container image to use.
+## The Redis container image to use.
 image:
   repository: redis
   tag: 5.0.4
   imagePullPolicy: IfNotPresent
 
-## The number of app replicas to run.
-## If setting this number higher than 1, make sure to configure a mysql database (not sqlite) and gcs storage
-## so data can be shared across replicas.
-## Using multiple replicas with a sqlite3 database or disk storage is not supported.
-replicas: 1
+# Whether to create a sharded deployment using a StatefulSet.
+# If set to false, a single replica deployment is created.
+# For most users a single replica Redis instance will be sufficient.
+sharded: false
+## The number of Redis shards (replicas) to run.
+## Only used if "sharded" is set to true.
+replicas: 3
path: charts/buildbuddy-redis/values.yaml
user: login: vadimberezniker
body: I think relying on replicas is too subtle since this affects which k8s resources are created. 
I already don't like the fact that we are conditionally changing resource types based on a config option. This means someone has to make sure they pass the same values if they run "helm delete" otherwise not all resources may get cloned up, but I'm not sure what the best solution for helm is.
The only other option I can think of is to create a separate helm chart for a sharded redis deployment. 

created_at: 2025-05-02T16:11:17Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,140 @@
+{{- if .Values.sharded }}
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+spec:
+  maxUnavailable: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    helm.sh/chart: {{ include "buildbuddy.chart" . }}
+    {{- if .Values.extraPodLabels }}
+    {{- .Values.extraPodLabels | toYaml | nindent 4 }}
+    {{- end }}
+spec:
+  replicas: {{ .Values.replicas }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  serviceName: {{ include "buildbuddy.fullname" . }}
+  template:
+    metadata:
+      annotations:
+        {{- if .Values.extraPodAnnotations }}
+        {{- .Values.extraPodAnnotations | toYaml | nindent 8 }}
+        {{- end }}
+      labels:
+        app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        app.kubernetes.io/managed-by: {{ .Release.Service }}
+        helm.sh/chart: {{ include "buildbuddy.chart" . }}
+        {{- if .Values.extraPodLabels }}
+        {{- .Values.extraPodLabels | toYaml | nindent 8 }}
+        {{- end }}
+    spec:
+      {{- if .Values.nodeSelector}}
+      nodeSelector:
+        {{- toYaml .Values.nodeSelector | nindent 8 }}
+      {{- end }}
+      {{- if .Values.tolerations}}
+      tolerations:
+        {{- toYaml .Values.tolerations | nindent 8 }}
+      {{- end }}
+      affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchExpressions:
+                  - key: app.kubernetes.io/name
+                    operator: In
+                    values:
+                      - "{{ include "buildbuddy.name" . }}"
+                  - key: app.kubernetes.io/instance
+                    operator: In
+                    values:
+                      - "{{ .Release.Name }}"
+              topologyKey: "kubernetes.io/hostname"
path: charts/buildbuddy-redis/templates/statefulset.yaml
user: login: vadimberezniker
body: Could we tell them to run a single, larger redis instance? There's not much value in setting up a sharded deployment and then putting all the shards on the same node. We can always relax this later if it turns out to be a problem. 
created_at: 2025-05-02T16:13:16Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,140 @@
+{{- if .Values.sharded }}
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+spec:
+  maxUnavailable: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    helm.sh/chart: {{ include "buildbuddy.chart" . }}
+    {{- if .Values.extraPodLabels }}
+    {{- .Values.extraPodLabels | toYaml | nindent 4 }}
+    {{- end }}
+spec:
+  replicas: {{ .Values.replicas }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  serviceName: {{ include "buildbuddy.fullname" . }}
+  template:
+    metadata:
+      annotations:
+        {{- if .Values.extraPodAnnotations }}
+        {{- .Values.extraPodAnnotations | toYaml | nindent 8 }}
+        {{- end }}
+      labels:
+        app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        app.kubernetes.io/managed-by: {{ .Release.Service }}
+        helm.sh/chart: {{ include "buildbuddy.chart" . }}
+        {{- if .Values.extraPodLabels }}
+        {{- .Values.extraPodLabels | toYaml | nindent 8 }}
+        {{- end }}
+    spec:
+      {{- if .Values.nodeSelector}}
+      nodeSelector:
+        {{- toYaml .Values.nodeSelector | nindent 8 }}
+      {{- end }}
+      {{- if .Values.tolerations}}
+      tolerations:
+        {{- toYaml .Values.tolerations | nindent 8 }}
+      {{- end }}
+      affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchExpressions:
+                  - key: app.kubernetes.io/name
+                    operator: In
+                    values:
+                      - "{{ include "buildbuddy.name" . }}"
+                  - key: app.kubernetes.io/instance
+                    operator: In
+                    values:
+                      - "{{ .Release.Name }}"
+              topologyKey: "kubernetes.io/hostname"
+      containers:
+        - name: {{ .Chart.Name }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+          imagePullPolicy: {{ .Values.image.imagePullPolicy }}
+          command:
+            - redis-server
+            - "/redis-master/redis.conf"
+          resources:
+          {{- if .Values.resources }}
+            {{- .Values.resources | toYaml | nindent 12 }}
+          {{- end }}
+          env:
+          {{- if .Values.extraEnvVars }}
+            {{- .Values.extraEnvVars | toYaml | nindent 10 }}
+          {{- end }}
+          ports:
+            - name: redis
+              containerPort: {{ .Values.service.internalRedisPort }}
+          readinessProbe:
+            exec:
+              command:
+                - redis-cli
+                - info
+            initialDelaySeconds: 10
+            periodSeconds: 5
path: charts/buildbuddy-redis/templates/statefulset.yaml
user: login: vadimberezniker
body: Yeah, I should do that. 
created_at: 2025-05-02T16:13:53Z
author_association: MEMBER
diff_hunk: @@ -2,17 +2,19 @@
 ## This is a YAML-formatted file.
 ## Declare variables to be passed into your templates.
 
-## The BuildBuddy container image to use.
+## The Redis container image to use.
 image:
   repository: redis
   tag: 5.0.4
   imagePullPolicy: IfNotPresent
 
-## The number of app replicas to run.
-## If setting this number higher than 1, make sure to configure a mysql database (not sqlite) and gcs storage
-## so data can be shared across replicas.
-## Using multiple replicas with a sqlite3 database or disk storage is not supported.
-replicas: 1
+# Whether to create a sharded deployment using a StatefulSet.
+# If set to false, a single replica deployment is created.
+# For most users a single replica Redis instance will be sufficient.
+sharded: false
+## The number of Redis shards (replicas) to run.
+## Only used if "sharded" is set to true.
+replicas: 3
path: charts/buildbuddy-redis/values.yaml
user: login: vadimberezniker
body: Was pondering on this some more:
 - having 2 redis charts would be too confusing to new users, so let's ignore I even suggested that
 - IMO replicas is too basic of a config option to have it affect which resource types are created. Users may not think too hard about the replies value since it's common to most charts. 
 - I can add more documentation to the sharded option to explain how it affects resource types
created_at: 2025-05-02T16:28:04Z
author_association: MEMBER
diff_hunk: @@ -2,17 +2,19 @@
 ## This is a YAML-formatted file.
 ## Declare variables to be passed into your templates.
 
-## The BuildBuddy container image to use.
+## The Redis container image to use.
 image:
   repository: redis
   tag: 5.0.4
   imagePullPolicy: IfNotPresent
 
-## The number of app replicas to run.
-## If setting this number higher than 1, make sure to configure a mysql database (not sqlite) and gcs storage
-## so data can be shared across replicas.
-## Using multiple replicas with a sqlite3 database or disk storage is not supported.
-replicas: 1
+# Whether to create a sharded deployment using a StatefulSet.
+# If set to false, a single replica deployment is created.
+# For most users a single replica Redis instance will be sufficient.
+sharded: false
+## The number of Redis shards (replicas) to run.
+## Only used if "sharded" is set to true.
+replicas: 3
path: charts/buildbuddy-redis/values.yaml
user: login: sluongng
body: Yeah let’s keep the current config
created_at: 2025-05-02T16:34:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -40,7 +47,7 @@ resources:
     cpu: "1"
     memory: "5Gi"
 
-## Exposes the Redis service via a LoadBalancer on the given ports.
+## Exposes the Redis service via a service.
path: charts/buildbuddy-redis/values.yaml
user: login: vadimberezniker
body: updated
created_at: 2025-05-02T19:20:44Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,140 @@
+{{- if .Values.sharded }}
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+spec:
+  maxUnavailable: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "buildbuddy.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    helm.sh/chart: {{ include "buildbuddy.chart" . }}
+    {{- if .Values.extraPodLabels }}
+    {{- .Values.extraPodLabels | toYaml | nindent 4 }}
+    {{- end }}
+spec:
+  replicas: {{ .Values.replicas }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  serviceName: {{ include "buildbuddy.fullname" . }}
+  template:
+    metadata:
+      annotations:
+        {{- if .Values.extraPodAnnotations }}
+        {{- .Values.extraPodAnnotations | toYaml | nindent 8 }}
+        {{- end }}
+      labels:
+        app.kubernetes.io/name: {{ include "buildbuddy.name" . }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+        app.kubernetes.io/managed-by: {{ .Release.Service }}
+        helm.sh/chart: {{ include "buildbuddy.chart" . }}
+        {{- if .Values.extraPodLabels }}
+        {{- .Values.extraPodLabels | toYaml | nindent 8 }}
+        {{- end }}
+    spec:
+      {{- if .Values.nodeSelector}}
+      nodeSelector:
+        {{- toYaml .Values.nodeSelector | nindent 8 }}
+      {{- end }}
+      {{- if .Values.tolerations}}
+      tolerations:
+        {{- toYaml .Values.tolerations | nindent 8 }}
+      {{- end }}
+      affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchExpressions:
+                  - key: app.kubernetes.io/name
+                    operator: In
+                    values:
+                      - "{{ include "buildbuddy.name" . }}"
+                  - key: app.kubernetes.io/instance
+                    operator: In
+                    values:
+                      - "{{ .Release.Name }}"
+              topologyKey: "kubernetes.io/hostname"
path: charts/buildbuddy-redis/templates/statefulset.yaml
user: login: sluongng
body: Without deleting this manually, I was not able to test the statefulset mode locally in my single-node setup. I guess it's a small burden on the repo maintainer when verifying these changes.
created_at: 2025-05-06T14:34:40Z
author_association: CONTRIBUTOR

PR comments:
user: login: vadimberezniker
created_at: 2025-05-02T19:22:11Z
body: I also updated the non-sharded deployment to always specify a replica count of 1 because any other value does not make sense for redis used in a buildbuddy deployment. 
author_association: MEMBER
user: login: vadimberezniker
created_at: 2025-05-02T19:23:09Z
body: > You might need to take a look at charts/buildbuddy-enterprise/templates/config.yaml so that the sharded config could be used with our enterprise helm chart as well.

I'm planning to address that as a separate change. 
author_association: MEMBER
user: login: vadimberezniker
created_at: 2025-05-06T19:16:07Z
body: > tested locally without the podAntiAffinity part and it worked fine.

I was always testing in dev so that wasn't a problem for me. If it continues to be annoying we can add an option to turn this off. 
author_association: MEMBER