mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-09 22:13:18 +09:00
fix(redis): delete the Sentinel PDB left behind on scale-down
Setting sentinel.disablePodDisruptionBudget only stops the operator from ensuring the PDB; it never deletes the one it created while three Sentinels ran. An existing instance scaled to one Redis pod therefore kept minAvailable 1 on its single Sentinel, which refuses every eviction. A post-upgrade hook deletes rfs-<release> in that case. Assisted-by: LLM Signed-off-by: Mattia Eleuteri <mattia@hidora.io>
This commit is contained in:
5 files changed
+206
-3
No files matched your search
@@ -79,7 +79,7 @@ See [`docs/operations/resource-presets.md`](../../../docs/operations/resource-pr
|
||||
|
||||
### sentinel
|
||||
|
||||
`sentinel.resources` and `sentinel.resourcesPreset` size the three Sentinel pods separately from the Redis pods. A Sentinel holds only its configuration and the failover state, so it needs a small fraction of what a Redis replica holding the dataset does. When the `sentinel` block sets neither, the Sentinel pods are sized like the Redis pods, which is how every instance was sized before these parameters existed.
|
||||
`sentinel.resources` and `sentinel.resourcesPreset` size the Sentinel pods separately from the Redis pods. A Sentinel holds only its configuration and the failover state, so it needs a small fraction of what a Redis replica holding the dataset does. When the `sentinel` block sets neither, the Sentinel pods are sized like the Redis pods, which is how every instance was sized before these parameters existed.
|
||||
|
||||
```yaml
|
||||
resourcesPreset: u1.small
|
||||
|
||||
@@ -47,3 +47,7 @@ These presets are for basic testing and not meant to be used in production
|
||||
{{- printf "ERROR: Preset key '%s' invalid. Allowed values are %s" .type (join "," (keys $presets)) | fail -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "redis.sentinelReplicas" -}}
|
||||
{{- ternary 1 3 (le (int .Values.replicas) 1) -}}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,119 @@
|
||||
{{- /*
|
||||
An instance scaled down to one Redis pod keeps the Sentinel PDB the operator
|
||||
created while it ran three Sentinels: setting disablePodDisruptionBudget only
|
||||
stops the operator from ensuring it, never deletes it, and minAvailable 1 on
|
||||
a single Sentinel refuses every eviction. A fresh install with one replica
|
||||
never gets that PDB, so this runs on upgrade only.
|
||||
*/}}
|
||||
{{- if and .Release.IsUpgrade (eq (include "redis.sentinelReplicas" . | int) 1) }}
|
||||
{{- $name := printf "%s-sentinel-pdb" .Release.Name }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
annotations:
|
||||
helm.sh/hook: post-upgrade
|
||||
helm.sh/hook-weight: "0"
|
||||
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
annotations:
|
||||
helm.sh/hook: post-upgrade
|
||||
helm.sh/hook-weight: "0"
|
||||
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||
rules:
|
||||
- apiGroups: ["policy"]
|
||||
resources: ["poddisruptionbudgets"]
|
||||
resourceNames: ["rfs-{{ .Release.Name }}"]
|
||||
verbs: ["get", "delete"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
annotations:
|
||||
helm.sh/hook: post-upgrade
|
||||
helm.sh/hook-weight: "0"
|
||||
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ $name }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ $name }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
annotations:
|
||||
helm.sh/hook: post-upgrade
|
||||
helm.sh/hook-weight: "5"
|
||||
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||
spec:
|
||||
ttlSecondsAfterFinished: 3600
|
||||
# Bounds the kubectl call too: a --request-timeout would make kubectl skip
|
||||
# its in-cluster credentials (hack/check-hook-request-timeout.bats).
|
||||
activeDeadlineSeconds: 120
|
||||
backoffLimit: 2
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
policy.cozystack.io/allow-to-apiserver: "true"
|
||||
spec:
|
||||
serviceAccountName: {{ $name }}
|
||||
restartPolicy: Never
|
||||
terminationGracePeriodSeconds: 10
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534
|
||||
runAsGroup: 65534
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: delete-pdb
|
||||
image: '{{ include "cozy-lib.image" (list "clastix/kubectl:v1.32@sha256:b9ef7d8dbe65bcc81a46c09b8dc7543103055021c4f43287bf59e92a8f4fe05c" $) }}'
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
env:
|
||||
- name: HOME
|
||||
value: /tmp
|
||||
command:
|
||||
- kubectl
|
||||
- --namespace={{ .Release.Namespace }}
|
||||
- delete
|
||||
- poddisruptionbudget
|
||||
- rfs-{{ .Release.Name }}
|
||||
- --ignore-not-found=true
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
@@ -14,9 +14,11 @@
|
||||
watch it. One Sentinel still lets the operator find the master (its quorum is
|
||||
replicas/2+1, so 1). The operator gives the Sentinel Deployment a PDB with
|
||||
minAvailable 1 whenever Redis has two replicas or fewer, which on a single
|
||||
Sentinel would block every node drain, so that PDB is dropped with it.
|
||||
Sentinel would block every node drain, so that PDB is dropped with it; the
|
||||
operator does not delete a PDB it stops managing, hence
|
||||
hooks/sentinel-pdb.yaml.
|
||||
*/}}
|
||||
{{- $sentinelReplicas := ternary 1 3 (le (int .Values.replicas) 1) -}}
|
||||
{{- $sentinelReplicas := include "redis.sentinelReplicas" . | int -}}
|
||||
{{- $sentinelPreset := $sentinel.resourcesPreset | default .Values.resourcesPreset -}}
|
||||
{{- $sentinelResources := .Values.resources -}}
|
||||
{{- if or $sentinel.resources $sentinel.resourcesPreset -}}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
suite: stale Sentinel PDB removed on scale-down to one Redis pod
|
||||
|
||||
# The operator only stops ensuring the Sentinel PDB once
|
||||
# disablePodDisruptionBudget is set; it never deletes the one it created while
|
||||
# three Sentinels ran. Left in place, its minAvailable 1 refuses every eviction
|
||||
# of the single Sentinel and blocks node drains.
|
||||
|
||||
templates:
|
||||
- templates/hooks/sentinel-pdb.yaml
|
||||
|
||||
release:
|
||||
name: my-redis
|
||||
namespace: tenant-test
|
||||
|
||||
set:
|
||||
_cluster:
|
||||
cluster-domain: cluster.local
|
||||
_namespace:
|
||||
host: example.com
|
||||
|
||||
tests:
|
||||
- it: deletes the operator's Sentinel PDB on an upgrade to one replica
|
||||
release:
|
||||
upgrade: true
|
||||
set:
|
||||
replicas: 1
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: Job
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.annotations["helm.sh/hook"]
|
||||
value: post-upgrade
|
||||
- equal:
|
||||
path: spec.template.spec.containers[0].command
|
||||
value:
|
||||
- kubectl
|
||||
- --namespace=tenant-test
|
||||
- delete
|
||||
- poddisruptionbudget
|
||||
- rfs-my-redis
|
||||
- --ignore-not-found=true
|
||||
- notMatchRegex:
|
||||
path: spec.template.spec.containers[0].command[4]
|
||||
pattern: request-timeout
|
||||
|
||||
- it: lets the hook delete only that PDB
|
||||
release:
|
||||
upgrade: true
|
||||
set:
|
||||
replicas: 1
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: Role
|
||||
asserts:
|
||||
- equal:
|
||||
path: rules
|
||||
value:
|
||||
- apiGroups: ["policy"]
|
||||
resources: ["poddisruptionbudgets"]
|
||||
resourceNames: ["rfs-my-redis"]
|
||||
verbs: ["get", "delete"]
|
||||
|
||||
- it: renders nothing on install, where no such PDB exists
|
||||
set:
|
||||
replicas: 1
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 0
|
||||
|
||||
- it: renders nothing while three Sentinels run
|
||||
release:
|
||||
upgrade: true
|
||||
set:
|
||||
replicas: 2
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 0
|
||||
Reference in new issue
Block a user