diff --git a/.woodpecker/build-linux.yml b/.woodpecker/build-linux.yml index 8cdd984..ef4ecfd 100644 --- a/.woodpecker/build-linux.yml +++ b/.woodpecker/build-linux.yml @@ -3,28 +3,33 @@ matrix: - linux/amd64 - linux/arm64 -platform: ${platform} - labels: type: exec + platform: ${platform} -pipeline: +steps: - name: publish-linux image: bash commands: - - export VERSION=$([ -z $CI_COMMIT_TAG ] && echo latest || echo $CI_COMMIT_TAG)-$(sed 's#/#-#g' <<< $CI_SYSTEM_ARCH) + - export VERSION=$([ -z $CI_COMMIT_TAG ] && echo latest || echo $CI_COMMIT_TAG)-$(sed 's#/#-#g' <<< $CI_SYSTEM_PLATFORM) - echo $CONTAINER_PASSWORD | podman login $DRYCC_REGISTRY --username $CONTAINER_USERNAME --password-stdin > /dev/null 2>&1 - make podman-build podman-immutable-push - secrets: - - codename - - dev_registry - - drycc_registry - - container_username - - container_password + environment: + CODENAME: + from_secret: codename + DEV_REGISTRY: + from_secret: dev_registry + DRYCC_REGISTRY: + from_secret: drycc_registry + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password when: event: - push - tag + - cron depends_on: - test-linux \ No newline at end of file diff --git a/.woodpecker/chart.yaml b/.woodpecker/chart.yaml index 3204cf5..cfcd3ec 100644 --- a/.woodpecker/chart.yaml +++ b/.woodpecker/chart.yaml @@ -1,30 +1,33 @@ -platform: linux/amd64 - labels: type: exec + platform: linux/amd64 -pipeline: +steps: - name: generate-chart - type: local image: bash commands: - export VERSION=$(sed 's#v##' <<< $CI_COMMIT_TAG) - export IMAGE_TAG=$([ ! -z $CI_COMMIT_TAG ] && echo \"$VERSION\" || echo \"canary\") - - export APP_VERSION=$([ ! -z $CI_COMMIT_TAG ] && echo $VERSION || echo 1.0.0) + - export APP_VERSION=$([ -z $CI_COMMIT_TAG ] && echo $CI_COMMIT_SHA || echo $VERSION) - export CHART_VERSION=$([ -z $CI_COMMIT_TAG ] && echo 1.0.0 || echo $VERSION) - sed -i "s/imageTag:\ \"canary\"/imageTag:\ $IMAGE_TAG/g" charts/$${CI_REPO_NAME}/values.yaml - helm package -u charts/$${CI_REPO_NAME} --version $CHART_VERSION --app-version $APP_VERSION - echo $CONTAINER_PASSWORD | helm registry login $DRYCC_REGISTRY -u $CONTAINER_USERNAME --password-stdin - helm push $${CI_REPO_NAME}-$CHART_VERSION.tgz oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts) - secrets: - - dev_registry - - drycc_registry - - container_username - - container_password + environment: + DEV_REGISTRY: + from_secret: dev_registry + DRYCC_REGISTRY: + from_secret: drycc_registry + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password when: event: - push - tag + - cron depends_on: -- manifest \ No newline at end of file +- manifest diff --git a/.woodpecker/manifest.yml b/.woodpecker/manifest.yml index 2d5c4e5..19fc70c 100644 --- a/.woodpecker/manifest.yml +++ b/.woodpecker/manifest.yml @@ -1,20 +1,21 @@ -platform: linux/amd64 - labels: type: exec + platform: linux/amd64 -pipeline: +steps: - name: generate-manifest image: bash commands: - sed -i "s/{{project}}/$${CI_REPO_NAME}/g" .woodpecker/manifest.tmpl - sed -i "s/registry.drycc.cc/$${DRYCC_REGISTRY}/g" .woodpecker/manifest.tmpl - secrets: - - drycc_registry + environment: + DRYCC_REGISTRY: + from_secret: drycc_registry when: event: - tag - push + - cron - name: publish-manifest image: bash @@ -27,13 +28,16 @@ pipeline: -v $(pwd):$(pwd) -w $(pwd) docker.io/plugins/manifest - secrets: - - container_username - - container_password + environment: + CONTAINER_USERNAME: + from_secret: container_username + CONTAINER_PASSWORD: + from_secret: container_password when: event: - tag - push + - cron depends_on: - build-linux diff --git a/.woodpecker/test-linux.yml b/.woodpecker/test-linux.yml index 313179e..194832f 100644 --- a/.woodpecker/test-linux.yml +++ b/.woodpecker/test-linux.yml @@ -3,20 +3,22 @@ matrix: - linux/amd64 - linux/arm64 -platform: ${platform} - labels: type: exec + platform: ${platform} -pipeline: +steps: - name: test-linux image: bash commands: - make test - secrets: - - codename - - dev_registry + environment: + CODENAME: + from_secret: codename + DEV_REGISTRY: + from_secret: dev_registry when: event: - push - tag + - cron diff --git a/Makefile b/Makefile index 0e01839..6c8d6c9 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,14 @@ # Some uses for short name: # - Container image name # - Kubernetes service, rc, pod, secret, volume names -SHORT_NAME := redis +SHORT_NAME := valkey DRYCC_REGISTRY ?= ${DEV_REGISTRY} IMAGE_PREFIX ?= drycc PLATFORM ?= linux/amd64,linux/arm64 include versioning.mk -SHELL_SCRIPTS = $(wildcard _scripts/*.sh) rootfs/bin/boot +SHELL_SCRIPTS = $(wildcard _test/*.sh) rootfs/bin/valkey-start rootfs/scripts/* # The following variables describe the containerized development environment # and other build options @@ -29,7 +29,8 @@ podman-build: podman build --build-arg CODENAME=${CODENAME} -t ${IMAGE} rootfs podman tag ${IMAGE} ${MUTABLE_IMAGE} -test: test-style +test: podman-build test-style + ./_test/test.sh ${VERSION} test-style: ${DEV_ENV_CMD} shellcheck $(SHELL_SCRIPTS) diff --git a/README.md b/README.md index a195ec9..ea5a0de 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,21 @@ -# Drycc Redis -[![Build Status](https://woodpecker.drycc.cc/api/badges/drycc/redis/status.svg)](https://woodpecker.drycc.cc/drycc/redis) +# Drycc Valkey +[![Build Status](https://woodpecker.drycc.cc/api/badges/drycc/valkey/status.svg)](https://woodpecker.drycc.cc/drycc/valkey) Drycc (pronounced DAY-iss) Workflow is an open source Platform as a Service (PaaS) that adds a developer-friendly layer to any [Kubernetes](http://kubernetes.io) cluster, making it easy to deploy and manage applications on your own servers. +## Usage + +Different components use different db, as follows: + +* `controller` use db 0 +* `passport` use db 1 +* `grafana` use db 2 +* `manager` use db 10 +* `helmbroker` use db 11 + +The above are the default configurations for each component. + ## Description -A Container image for running standalone (not clustered) Redis on a Kubernetes cluster. +A Container image for running standalone (not clustered) Valkey on a Kubernetes cluster. [v2.18]: https://github.com/drycc/workflow/releases/tag/v2.18.0 diff --git a/_test/test.sh b/_test/test.sh new file mode 100755 index 0000000..574b989 --- /dev/null +++ b/_test/test.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash + +VERSION="$1" + +CONTAINER_PROXY_NAME="valkey-benchmark-proxy" +CONTAINER_MASTER_NAME="valkey-benchmark-master" +CONTAINER_SLAVE1_NAME="valkey-benchmark-slave1" +CONTAINER_SLAVE2_NAME="valkey-benchmark-slave2" +DRYCC_VALKEY_PASSWORD=123456 + +function clean_before_exit { + # delay before exiting, so stdout/stderr flushes through the logging system + clean-valkey +} +trap clean_before_exit EXIT + +start-valkey-master() { + podman run -d \ + --rm \ + --env "REDISCLI_AUTH=$DRYCC_VALKEY_PASSWORD" \ + --env "DRYCC_VALKEY_PASSWORD=$DRYCC_VALKEY_PASSWORD" \ + --name "$CONTAINER_MASTER_NAME" \ + "registry.drycc.cc/drycc/valkey:$VERSION" \ + sleep infinity + + master_ip=$(podman exec "$CONTAINER_MASTER_NAME" hostname -i | tr -d '\r\n') + podman exec --env "DRYCC_VALKEY_SENTINEL=$master_ip" "$CONTAINER_MASTER_NAME" init-stack valkey-start server "$master_ip" & + podman exec --env "DRYCC_VALKEY_SENTINEL=$master_ip" "$CONTAINER_MASTER_NAME" init-stack valkey-start sentinel "$master_ip" & +} + +start-valkey-slave1() { + podman run -d \ + --rm \ + --env "REDISCLI_AUTH=$DRYCC_VALKEY_PASSWORD" \ + --env "DRYCC_VALKEY_PASSWORD=$DRYCC_VALKEY_PASSWORD" \ + --name "$CONTAINER_SLAVE1_NAME" \ + "registry.drycc.cc/drycc/valkey:$VERSION" \ + sleep infinity + + slave1_ip=$(podman exec -it "$CONTAINER_SLAVE1_NAME" hostname -i | tr -d '\r\n') + podman exec --env "DRYCC_VALKEY_SENTINEL=$master_ip" "$CONTAINER_SLAVE1_NAME" init-stack valkey-start server "$slave1_ip" & + podman exec --env "DRYCC_VALKEY_SENTINEL=$master_ip" "$CONTAINER_SLAVE1_NAME" init-stack valkey-start sentinel "$slave1_ip" & +} + +start-valkey-slave2() { + podman run -d \ + --rm \ + --env "REDISCLI_AUTH=$DRYCC_VALKEY_PASSWORD" \ + --env "DRYCC_VALKEY_PASSWORD=$DRYCC_VALKEY_PASSWORD" \ + --name "$CONTAINER_SLAVE2_NAME" \ + "registry.drycc.cc/drycc/valkey:$VERSION" \ + sleep infinity + + slave2_ip=$(podman exec -it "$CONTAINER_SLAVE2_NAME" hostname -i | tr -d '\r\n') + podman exec --env "DRYCC_VALKEY_SENTINEL=$master_ip" "$CONTAINER_SLAVE2_NAME" init-stack valkey-start server "$slave2_ip" & + podman exec --env "DRYCC_VALKEY_SENTINEL=$master_ip" "$CONTAINER_SLAVE2_NAME" init-stack valkey-start sentinel "$slave2_ip" & +} + +start-valkey-proxy() { + podman run -d \ + --rm \ + --env "REDISCLI_AUTH=$DRYCC_VALKEY_PASSWORD" \ + --env "DRYCC_VALKEY_PASSWORD=$DRYCC_VALKEY_PASSWORD" \ + --name "$CONTAINER_PROXY_NAME" \ + "registry.drycc.cc/drycc/valkey:$VERSION" \ + sleep infinity + + podman exec --env "DRYCC_VALKEY_SENTINEL=$master_ip" "$CONTAINER_PROXY_NAME" init-stack valkey-start proxy & +} + +clean-valkey() { + { + podman kill "$CONTAINER_PROXY_NAME" + podman kill "$CONTAINER_SLAVE1_NAME" + podman kill "$CONTAINER_SLAVE2_NAME" + podman kill "$CONTAINER_MASTER_NAME" + } >>/dev/null 2>&1 +} + +clean-valkey +start-valkey-master +start-valkey-slave1 +start-valkey-slave2 +start-valkey-proxy +echo "run valkey proxy benchmark..." +podman exec "$CONTAINER_PROXY_NAME" init-stack valkey-benchmark -p 16379 -a $DRYCC_VALKEY_PASSWORD + +echo "run valkey master benchmark..." +podman exec "$CONTAINER_MASTER_NAME" init-stack valkey-benchmark -a $DRYCC_VALKEY_PASSWORD + +echo "check slave all keys..." +KEYS=$(podman exec "$CONTAINER_MASTER_NAME" bash -c 'init-stack valkey-cli KEYS "*"') +if [[ "${KEYS}" == "" ]]; then + echo "error: there is no data from the database" + exit 1 +fi + +echo "check sentinel $CONTAINER_MASTER_NAME get master..." +MASTER=$(podman exec "$CONTAINER_MASTER_NAME" init-stack valkey-cli -p 26379 sentinel get-master-addr-by-name drycc) +if [[ "${MASTER}" == "" ]]; then + echo "error: unable to obtain master information" + exit 1 +fi + +echo "check sentinel $CONTAINER_SLAVE1_NAME get master..." +MASTER=$(podman exec "$CONTAINER_SLAVE1_NAME" init-stack valkey-cli -p 26379 sentinel get-master-addr-by-name drycc) +if [[ "${MASTER}" == "" ]]; then + echo "error: unable to obtain master information" + exit 1 +fi + +echo "check sentinel $CONTAINER_SLAVE2_NAME get master..." +MASTER=$(podman exec "$CONTAINER_SLAVE2_NAME" init-stack valkey-cli -p 26379 sentinel get-master-addr-by-name drycc) +if [[ "${MASTER}" == "" ]]; then + echo "error: unable to obtain master information" + exit 1 +fi + +echo "check sentinel $CONTAINER_MASTER_NAME get slaves..." +SLAVES=$(podman exec "$CONTAINER_MASTER_NAME" init-stack valkey-cli -p 26379 sentinel replicas drycc) +if [[ "${SLAVES}" == "" ]]; then + echo "error: unable to obtain slaves information" + exit 1 +fi + +echo "check sentinel $CONTAINER_SLAVE1_NAME get slaves..." +SLAVES=$(podman exec "$CONTAINER_SLAVE1_NAME" init-stack valkey-cli -p 26379 sentinel replicas drycc) +if [[ "${SLAVES}" == "" ]]; then + echo "error: unable to obtain slaves information" + exit 1 +fi + +echo "check sentinel $CONTAINER_SLAVE2_NAME get slaves..." +SLAVES=$(podman exec "$CONTAINER_SLAVE2_NAME" init-stack valkey-cli -p 26379 sentinel replicas drycc) +if [[ "${SLAVES}" == "" ]]; then + echo "error: unable to obtain slaves information" + exit 1 +fi + +echo "all test ok..." diff --git a/charts/redis/templates/redis-secret-creds.yaml b/charts/redis/templates/redis-secret-creds.yaml deleted file mode 100644 index ca96a29..0000000 --- a/charts/redis/templates/redis-secret-creds.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: redis-creds - labels: - app: drycc-redis - heritage: drycc - annotations: - "helm.sh/hook": pre-install -data: - {{ if eq .Values.global.redisLocation "on-cluster"}} - {{- $redisAddrs := (list ) }} - {{ $redisNodeCount := .Values.replicas | int }} - {{- range $i := until $redisNodeCount }} - {{- $redisAddrs = (append $redisAddrs (printf "drycc-redis-%d.drycc-redis.%s.svc.%s:6379" $i $.Release.Namespace $.Values.global.clusterDomain)) }} - {{- end -}} - addrs: {{ join "," $redisAddrs | b64enc }} - password: {{ randAlphaNum 32 | b64enc }} - {{ else if eq .Values.global.redisLocation "off-cluster"}} - addrs: {{ .Values.addrs | b64enc }} - password: {{ .Values.password | b64enc }} - {{ end }} diff --git a/charts/redis/templates/redis-statefulset.yaml b/charts/redis/templates/redis-statefulset.yaml deleted file mode 100644 index a51ba06..0000000 --- a/charts/redis/templates/redis-statefulset.yaml +++ /dev/null @@ -1,77 +0,0 @@ -{{- if eq .Values.global.redisLocation "on-cluster" }} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: drycc-redis - labels: - heritage: drycc - annotations: - component.drycc.cc/version: {{ .Values.imageTag }} -spec: - serviceName: drycc-redis - replicas: {{ .Values.replicas }} - selector: - matchLabels: - app: drycc-redis - template: - metadata: - labels: {{- include "common.labels.standard" . | nindent 8 }} - app: drycc-redis - spec: - affinity: - podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset.type "component" "" "extraMatchLabels" .Values.podAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} - podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset.type "component" "" "extraMatchLabels" .Values.podAntiAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} - nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values ) | nindent 10 }} - containers: - - name: drycc-redis - image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/redis:{{ .Values.imageTag }} - imagePullPolicy: {{ .Values.imagePullPolicy }} - {{- if or (.Values.limitsCpu) (.Values.limitsMemory)}} - resources: - limits: - {{- if (.Values.limitsCpu) }} - cpu: {{.Values.limitsCpu}} - {{- end}} - {{- if (.Values.limitsMemory) }} - memory: {{.Values.limitsMemory}} - {{- end}} - {{- end}} - args: - - "/bin/boot" - - "--port" - - "6379" - ports: - - containerPort: 6379 - env: - - name: DRYCC_REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: redis-creds - key: password - {{- if .Values.persistence.enabled }} - volumeMounts: - - name: redis-data - mountPath: /data - {{- end }} - securityContext: - fsGroup: 1001 - runAsGroup: 1001 - runAsUser: 1001 - {{- if .Values.persistence.enabled }} - volumeClaimTemplates: - - metadata: - name: redis-data - spec: - accessModes: [ "ReadWriteOnce" ] - {{- if .Values.persistence.storageClass }} - {{- if (eq "-" .Values.persistence.storageClass) }} - storageClassName: "" - {{- else }} - storageClassName: "{{ .Values.persistence.storageClass }}" - {{- end }} - {{- end }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} - {{- end }} -{{- end }} diff --git a/charts/redis/templates/redis-svc.yaml b/charts/redis/templates/redis-svc.yaml deleted file mode 100644 index 0a47609..0000000 --- a/charts/redis/templates/redis-svc.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if eq .Values.global.redisLocation "on-cluster" }} -apiVersion: v1 -kind: Service -metadata: - name: drycc-redis - annotations: - {{- with .Values.service.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - labels: - heritage: drycc -spec: - clusterIP: None - selector: - app: drycc-redis -{{- end }} diff --git a/charts/redis/values.yaml b/charts/redis/values.yaml deleted file mode 100644 index 55e9d6e..0000000 --- a/charts/redis/values.yaml +++ /dev/null @@ -1,48 +0,0 @@ -imageOrg: "drycc" -imagePullPolicy: "Always" -imageTag: "canary" -imageRegistry: "registry.drycc.cc" -# limitsCpu: "100m" -# limitsMemory: "50Mi" - -nodeAffinityPreset: - key: "drycc.cc/node" - type: "soft" - values: - - "true" - -podAffinityPreset: - type: "" - extraMatchLabels: - security: "drycc-security" - -podAntiAffinityPreset: - type: "soft" - extraMatchLabels: - app: "drycc-redis" - -# The following parameters are configured only when using an on-cluster Redis instance -replicas: 1 - -# The following parameters are configured only when using an off-cluster Redis instance -addrs: "" # A list of clusters: "127.0.0.1:7001/1,127.0.0.2:7002/1" -password: "redis password" # "" == no password - -# Service -service: - # Provide any additional service annotations - annotations: {} - -# GCP PDs and EBS volumes are supported only -persistence: - enabled: false # Set to true to enable persistence - size: 5Gi - storageClass: "" - -global: - # Set the location of Workflow's redis instance - # - # Valid values are: - # - on-cluster: Run Redis within the Kubernetes cluster - # - off-cluster: Run Redis outside the Kubernetes cluster (configure in redis section) - redisLocation: "on-cluster" \ No newline at end of file diff --git a/charts/redis/Chart.yaml b/charts/valkey/Chart.yaml similarity index 64% rename from charts/redis/Chart.yaml rename to charts/valkey/Chart.yaml index 9272cb1..5e7e12d 100644 --- a/charts/redis/Chart.yaml +++ b/charts/valkey/Chart.yaml @@ -1,12 +1,12 @@ -name: redis -home: https://github.com/drycc/redis +name: valkey +home: https://github.com/drycc/valkey apiVersion: v2 appVersion: 1.0.0 dependencies: - name: common repository: oci://registry.drycc.cc/charts version: ~1.1.2 -description: A Redis database for use inside a Kubernetes cluster. +description: A Valkey database for use inside a Kubernetes cluster. maintainers: - name: Drycc Team email: engineering@drycc.com diff --git a/charts/valkey/templates/valkey-secret-creds.yaml b/charts/valkey/templates/valkey-secret-creds.yaml new file mode 100644 index 0000000..33c81d2 --- /dev/null +++ b/charts/valkey/templates/valkey-secret-creds.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: valkey-creds + labels: + app: drycc-valkey + heritage: drycc +data: + password: {{ include "common.secrets.lookup" (dict "secret" "valkey-creds" "key" "password" "defaultValue" (randAlphaNum 32) "context" $) }} diff --git a/charts/valkey/templates/valkey-statefulset.yaml b/charts/valkey/templates/valkey-statefulset.yaml new file mode 100644 index 0000000..be223df --- /dev/null +++ b/charts/valkey/templates/valkey-statefulset.yaml @@ -0,0 +1,290 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: drycc-valkey + labels: + heritage: drycc + annotations: + component.drycc.cc/version: {{ .Values.imageTag }} +spec: + serviceName: drycc-valkey + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: drycc-valkey + template: + metadata: + labels: {{- include "common.labels.standard" . | nindent 8 }} + app: drycc-valkey + spec: + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset.type "component" "" "extraMatchLabels" .Values.podAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset.type "component" "" "extraMatchLabels" .Values.podAntiAffinityPreset.extraMatchLabels "topologyKey" "" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values ) | nindent 10 }} + containers: + - name: drycc-valkey-proxy + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/valkey:{{ .Values.imageTag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }} + {{- else }} + args: + - valkey-start + - proxy + {{- end }} + env: + - name: DRYCC_VALKEY_PASSWORD + valueFrom: + secretKeyRef: + name: valkey-creds + key: password + - name: DRYCC_VALKEY_SENTINEL + value: drycc-valkey + ports: + - containerPort: 16379 + {{- with index .Values "proxy" "resources" }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + startupProbe: + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 22 + tcpSocket: + port: 16379 + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + tcpSocket: + port: 16379 + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 + tcpSocket: + port: 16379 + - name: drycc-valkey-server + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/valkey:{{ .Values.imageTag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }} + {{- else }} + args: + - valkey-start + - server + - $(POD_NAME).drycc-valkey + {{- end }} + ports: + - containerPort: 6379 + {{- with index .Values "server" "resources" }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: DRYCC_VALKEY_SENTINEL + value: drycc-valkey + - name: DRYCC_VALKEY_PASSWORD + valueFrom: + secretKeyRef: + name: valkey-creds + key: password + startupProbe: + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 22 + tcpSocket: + port: 6379 + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + exec: + command: + - init-stack + - sh + - -c + - /scripts/ping_liveness_local.sh 5 + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 + exec: + command: + - init-stack + - sh + - -c + - /scripts/ping_readiness_local.sh 1 + {{- if .Values.persistence.enabled }} + volumeMounts: + - name: valkey-data + mountPath: /data + {{- end }} + lifecycle: + preStop: + exec: + command: + - init-stack + - /bin/bash + - -c + - /scripts/prestop-valkey.sh + - name: drycc-valkey-sentinel + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/valkey:{{ .Values.imageTag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }} + {{- else }} + args: + - valkey-start + - sentinel + - $(POD_NAME).drycc-valkey + {{- end }} + ports: + - containerPort: 26379 + {{- with index .Values "sentinel" "resources" }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: DRYCC_VALKEY_SENTINEL + value: drycc-valkey + - name: DRYCC_VALKEY_PASSWORD + valueFrom: + secretKeyRef: + name: valkey-creds + key: password + startupProbe: + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 22 + tcpSocket: + port: 26379 + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + exec: + command: + - init-stack + - sh + - -c + - /scripts/ping_sentinel.sh 5 + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 5 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 5 + exec: + command: + - init-stack + - sh + - -c + - /scripts/ping_sentinel.sh 1 + {{- if .Values.persistence.enabled }} + volumeMounts: + - name: valkey-data + mountPath: /data + {{- end }} + lifecycle: + preStop: + exec: + command: + - init-stack + - /bin/bash + - -c + - /scripts/prestop-sentinel.sh + - name: drycc-valkey-metrics + image: {{.Values.imageRegistry}}/{{.Values.imageOrg}}/valkey:{{ .Values.imageTag }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 10 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 10 }} + {{- else }} + command: + - init-stack + args: + - redis_exporter + {{- end }} + ports: + - containerPort: 9121 + env: + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: valkey-creds + key: password + startupProbe: + initialDelaySeconds: 10 + tcpSocket: + port: 9121 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 15 + successThreshold: 1 + livenessProbe: + initialDelaySeconds: 5 + httpGet: + path: / + port: 9121 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + readinessProbe: + initialDelaySeconds: 5 + httpGet: + path: / + port: 9121 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + securityContext: + fsGroup: 1001 + runAsGroup: 1001 + runAsUser: 1001 + {{- if .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: valkey-data + spec: + accessModes: [ "ReadWriteOnce" ] + {{- if .Values.persistence.storageClass }} + {{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" + {{- end }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- end }} diff --git a/charts/valkey/templates/valkey-svc.yaml b/charts/valkey/templates/valkey-svc.yaml new file mode 100644 index 0000000..c38af8c --- /dev/null +++ b/charts/valkey/templates/valkey-svc.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: Service +metadata: + name: drycc-valkey + annotations: + prometheus.io/path: /metrics + prometheus.io/port: "9121" + prometheus.io/scrape: "true" + {{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + heritage: drycc +spec: + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: proxy + port: 16379 + targetPort: 16379 + protocol: TCP + - name: server + port: 6379 + targetPort: 6379 + protocol: TCP + - name: metrics + port: 9121 + targetPort: 9121 + protocol: TCP + - name: sentinel + port: 26379 + targetPort: 26379 + protocol: TCP + selector: + app: drycc-valkey diff --git a/charts/valkey/values.yaml b/charts/valkey/values.yaml new file mode 100644 index 0000000..bf19ca1 --- /dev/null +++ b/charts/valkey/values.yaml @@ -0,0 +1,76 @@ +imageOrg: "drycc" +imagePullPolicy: "Always" +imageTag: "canary" +imageRegistry: "registry.drycc.cc" + +## Enable diagnostic mode +## +diagnosticMode: + ## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden) + ## + enabled: false + ## @param diagnosticMode.command Command to override all containers + ## + command: + - sleep + ## @param diagnosticMode.args Args to override all containers + ## + args: + - infinity + +nodeAffinityPreset: + key: "drycc.cc/node" + type: "soft" + values: + - "true" + +podAffinityPreset: + type: "" + extraMatchLabels: + security: "drycc-security" + +podAntiAffinityPreset: + type: "soft" + extraMatchLabels: + app: "drycc-valkey" + +# The following parameters are configured only when using an on-cluster Valkey instance +replicas: 3 + +# Service +service: + # Provide any additional service annotations + annotations: {} + +proxy: + resources: {} + # limits: + # cpu: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi + +server: + resources: {} + # limits: + # cpu: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi + +sentinel: + resources: {} + # limits: + # cpu: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi + +# GCP PDs and EBS volumes are supported only +persistence: + enabled: false # Set to true to enable persistence + size: 5Gi + storageClass: "" diff --git a/rootfs/Dockerfile b/rootfs/Dockerfile index 41de670..6068bee 100644 --- a/rootfs/Dockerfile +++ b/rootfs/Dockerfile @@ -1,18 +1,23 @@ ARG CODENAME FROM registry.drycc.cc/drycc/base:${CODENAME} -ENV DRYCC_UID=1001 \ +ARG DRYCC_UID=1001 \ DRYCC_GID=1001 \ DRYCC_HOME_DIR=/data \ - REDIS_VERSION="7.0.11" + VALKEY_VERSION="9.0.0" \ + VALKEY_SENTINEL_PROXY_VERSION="2.0.1" \ + REDIS_EXPORTER_VERSION="1.80.1" RUN groupadd drycc --gid ${DRYCC_GID} \ && useradd drycc -u ${DRYCC_UID} -g ${DRYCC_GID} -s /bin/bash -m -d ${DRYCC_HOME_DIR} -COPY bin/boot /bin/boot -COPY etc/redis/redis.conf /etc/redis/redis.conf +COPY scripts /scripts +COPY etc/valkey /etc/valkey +COPY bin/valkey-start /bin/valkey-start -RUN install-stack redis ${REDIS_VERSION} \ +RUN install-stack valkey ${VALKEY_VERSION} \ + && install-stack valkey-sentinel-proxy ${VALKEY_SENTINEL_PROXY_VERSION} \ + && install-stack redis_exporter $REDIS_EXPORTER_VERSION \ && rm -rf \ /usr/share/doc \ /usr/share/man \ @@ -27,9 +32,8 @@ RUN install-stack redis ${REDIS_VERSION} \ /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/IBM* \ /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/EBC* \ && mkdir -p /usr/share/man/man{1..8} \ - && chown -R ${DRYCC_UID}:${DRYCC_GID} /etc/redis ${DRYCC_HOME_DIR} + && chown -R ${DRYCC_UID}:${DRYCC_GID} /etc/valkey ${DRYCC_HOME_DIR} USER ${DRYCC_UID} WORKDIR ${DRYCC_HOME_DIR} -CMD ["/bin/boot"] -EXPOSE 6379 +EXPOSE 6379 9121 26379 diff --git a/rootfs/bin/boot b/rootfs/bin/boot deleted file mode 100755 index d45af80..0000000 --- a/rootfs/bin/boot +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -set -eof pipefail - -REDIS_CONFIG_FILE=/etc/redis/redis.conf - -# Set password -if [ -n "$DRYCC_REDIS_PASSWORD" ]; then - printf "\nrequirepass %s" "$DRYCC_REDIS_PASSWORD" >> $REDIS_CONFIG_FILE -fi - -exec redis-server $REDIS_CONFIG_FILE "$@" diff --git a/rootfs/bin/valkey-start b/rootfs/bin/valkey-start new file mode 100755 index 0000000..d8204d8 --- /dev/null +++ b/rootfs/bin/valkey-start @@ -0,0 +1,126 @@ +#!/usr/bin/env bash + +# shellcheck disable=SC1091 +. /scripts/init.sh + +print_usage() { + echo "Valid commands for valkey-start:" + echo "" + echo "proxy start valkey proxy" + echo "server start valkey server" + echo "sentinel start valkey sentinel" + echo "" + echo "Such as 'valkey-start server valkey.valkey.svc' to start valkey server." +} + +remove_in_file() { + local filename="${1:?filename is required}" + local match_regex="^\s*${2:?match regex is required} .*" + sed -i "/$match_regex/d" "$filename" +} + +get_master_info() { + export REDISCLI_AUTH=${DRYCC_VALKEY_PASSWORD} + command="valkey-cli -h ${DRYCC_VALKEY_SENTINEL} -p ${SENTINEL_PORT} sentinel get-master-addr-by-name drycc 2>>/dev/null" + eval "$command" +} + +wait_for_valkey() { + local host="${1:?host is required}" + local port="${2:?port is required}" + local retries="${3:-30}" + log "Waiting for valkey (${host}:${port}) to be ready..." + for ((i = 1; i <= retries; i += 1)); do + if valkey-cli -h "$host" -p "$port" ping 2>/dev/null | grep -q PONG; then + log "Valkey (${host}:${port}) is ready." + return 0 + fi + sleep 2s + done + error "Valkey (${host}:${port}) did not become ready in time" +} + +start_valkey_proxy() { + wait_for_valkey "${DRYCC_VALKEY_SENTINEL}" "${SENTINEL_PORT}" + exec valkey-sentinel-proxy \ + --listen=:16379 \ + --master=drycc \ + --max-procs=4 \ + --sentinel-addr="${DRYCC_VALKEY_SENTINEL}":26379 \ + --sentinel-pass="${DRYCC_VALKEY_PASSWORD}" +} + +start_valkey_server() { + announce_ip="$1" + VALKEY_CONFIG_FILE=/data/server/valkey.conf + if [ ! -f ${VALKEY_CONFIG_FILE} ]; then + cp -rf /etc/valkey/valkey-default.conf ${VALKEY_CONFIG_FILE} + fi + + # Clean old + remove_in_file ${VALKEY_CONFIG_FILE} masterauth + remove_in_file ${VALKEY_CONFIG_FILE} requirepass + remove_in_file ${VALKEY_CONFIG_FILE} replicaof + remove_in_file ${VALKEY_CONFIG_FILE} replica-announce-ip + remove_in_file ${VALKEY_CONFIG_FILE} replica-announce-port + { + printf "\nmasterauth %s" "${DRYCC_VALKEY_PASSWORD}" + printf "\nrequirepass %s" "${DRYCC_VALKEY_PASSWORD}" + printf "\nreplica-announce-ip %s" "${announce_ip}" + printf "\nreplica-announce-port %s" "${SERVER_PORT}" + } >> ${VALKEY_CONFIG_FILE} + # Set server slaveof + if get_master_info; then + # shellcheck disable=SC2207 + master_info=($(get_master_info)) + if [ "${master_info[0]}" != "${announce_ip}" ]; then + printf "\nreplicaof %s %s" "${master_info[0]}" "${master_info[1]}" >> "${VALKEY_CONFIG_FILE}" + fi + fi + exec valkey-server "${VALKEY_CONFIG_FILE}" +} + +start_valkey_sentinel() { + announce_ip="$1" + VALKEY_SENTINEL_CONFIG_FILE=/data/sentinel/valkey-sentinel.conf + if [ ! -f ${VALKEY_SENTINEL_CONFIG_FILE} ]; then + cp -rf /etc/valkey/valkey-sentinel-default.conf ${VALKEY_SENTINEL_CONFIG_FILE} + fi + + # Clean old + remove_in_file ${VALKEY_SENTINEL_CONFIG_FILE} masterauth + remove_in_file ${VALKEY_SENTINEL_CONFIG_FILE} requirepass + remove_in_file ${VALKEY_SENTINEL_CONFIG_FILE} primaryauth + remove_in_file ${VALKEY_SENTINEL_CONFIG_FILE} "sentinel auth-pass" + remove_in_file ${VALKEY_SENTINEL_CONFIG_FILE} "sentinel announce-ip" + remove_in_file ${VALKEY_SENTINEL_CONFIG_FILE} "sentinel announce-port" + remove_in_file ${VALKEY_SENTINEL_CONFIG_FILE} "sentinel monitor" + + # Set sentinel config + { + printf "\nmasterauth %s" "${DRYCC_VALKEY_PASSWORD}" + printf "\nrequirepass %s" "${DRYCC_VALKEY_PASSWORD}" + printf "\nprimaryauth %s" "${DRYCC_VALKEY_PASSWORD}" + printf "\nsentinel auth-pass drycc %s" "${DRYCC_VALKEY_PASSWORD}" + printf "\nsentinel announce-ip %s" "${announce_ip}" + printf "\nsentinel announce-port %s" "${SENTINEL_PORT}" + } >> ${VALKEY_SENTINEL_CONFIG_FILE} + + # Set monitor + if get_master_info; then + # shellcheck disable=SC2207 + master_info=($(get_master_info)) + printf "\nsentinel monitor drycc %s %s 2" "${master_info[0]}" "${master_info[1]}" >> ${VALKEY_SENTINEL_CONFIG_FILE} + else + printf "\nsentinel monitor drycc %s %s 2" "${announce_ip}" "${SERVER_PORT}" >> ${VALKEY_SENTINEL_CONFIG_FILE} + fi + exec valkey-server $VALKEY_SENTINEL_CONFIG_FILE --sentinel +} + +command="$1" +if [[ ${command} == "proxy" || ${command} == "server" || ${command} == "sentinel" ]]; then + "start_valkey_$command" "$2" +else + print_usage + exit 1 +fi diff --git a/rootfs/etc/redis/redis.conf b/rootfs/etc/valkey/valkey-default.conf similarity index 90% rename from rootfs/etc/redis/redis.conf rename to rootfs/etc/valkey/valkey-default.conf index 58673f3..0b51917 100644 --- a/rootfs/etc/redis/redis.conf +++ b/rootfs/etc/valkey/valkey-default.conf @@ -1,6 +1,7 @@ daemonize no bind 0.0.0.0 logfile "" +dir "/data/server" save 900 1 save 300 10 diff --git a/rootfs/etc/valkey/valkey-sentinel-default.conf b/rootfs/etc/valkey/valkey-sentinel-default.conf new file mode 100644 index 0000000..429f3b6 --- /dev/null +++ b/rootfs/etc/valkey/valkey-sentinel-default.conf @@ -0,0 +1,10 @@ +daemonize no +bind 0.0.0.0 +logfile "" +dir "/data/sentinel" + +sentinel resolve-hostnames yes +sentinel announce-hostnames yes +sentinel down-after-milliseconds drycc 60000 +sentinel failover-timeout drycc 180000 +sentinel parallel-syncs drycc 1 diff --git a/rootfs/scripts/init.sh b/rootfs/scripts/init.sh new file mode 100755 index 0000000..e9ee373 --- /dev/null +++ b/rootfs/scripts/init.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# Constants +RESET='\033[0m' +RED='\033[38;5;1m' +MAGENTA='\033[38;5;5m' +CYAN='\033[38;5;6m' + +log() { + # 'is_boolean_yes' is defined in libvalidations.sh, but depends on this file so we cannot source it + local bool="${DRYCC_QUIET:-false}" + # comparison is performed without regard to the case of alphabetic characters + shopt -s nocasematch + if ! [[ "$bool" = 1 || "$bool" =~ ^(yes|true)$ ]]; then + printf "%b\\n" "${CYAN}${MODULE:-} ${MAGENTA}$(date "+%T.%2N ")${RESET}${*}" >&2 + fi +} + +error() { + log "${RED}ERROR${RESET} ==> ${*}" + exit 1 +} + +######################## +# Retries a command a given number of times +# Arguments: +# $1 - cmd (as a string) +# $2 - max retries. Default: 12 +# $3 - sleep between retries (in seconds). Default: 5 +# Returns: +# Boolean +######################### +retry_while() { + local cmd="${1:?cmd is missing}" + local retries="${2:-12}" + local sleep_time="${3:-5}" + local return_value=1 + + read -r -a command <<<"$cmd" + for ((i = 1; i <= retries; i += 1)); do + "${command[@]}" && return_value=0 && break + sleep "$sleep_time" + done + return $return_value +} + +init_default_env() { + if [[ -z "$DRYCC_VALKEY_SENTINEL" ]]; then + error "DRYCC_VALKEY_SENTINEL cannot be empty" + fi + if [[ -z "$DRYCC_VALKEY_PASSWORD" ]]; then + error "DRYCC_VALKEY_PASSWORD cannot be empty" + fi + mkdir -p /data/{server,sentinel} + SERVER_PORT=${SERVER_PORT:-6379} + SENTINEL_PORT=${SENTINEL_PORT:-26379} + REDISCLI_AUTH="$DRYCC_VALKEY_PASSWORD" + export SERVER_PORT SENTINEL_PORT REDISCLI_AUTH +} + +init_default_env diff --git a/rootfs/scripts/ping_liveness_local.sh b/rootfs/scripts/ping_liveness_local.sh new file mode 100755 index 0000000..baf72d2 --- /dev/null +++ b/rootfs/scripts/ping_liveness_local.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# shellcheck disable=SC1091 +. /scripts/init.sh + +response=$( + timeout -s 3 "$1" \ + valkey-cli \ + -h localhost \ + -p "${SERVER_PORT}" \ + ping +) +if [ "$?" -eq "124" ]; then + echo "Timed out" + exit 1 +fi +responseFirstWord=$(echo "$response" | head -n1 | awk '{print $1;}') +if [ "$response" != "PONG" ] && [ "$responseFirstWord" != "LOADING" ] && [ "$responseFirstWord" != "MASTERDOWN" ]; then + echo "$response" + exit 1 +fi \ No newline at end of file diff --git a/rootfs/scripts/ping_readiness_local.sh b/rootfs/scripts/ping_readiness_local.sh new file mode 100755 index 0000000..df10bac --- /dev/null +++ b/rootfs/scripts/ping_readiness_local.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# shellcheck disable=SC1091 +. /scripts/init.sh + +response=$( + timeout -s 3 "$1" \ + valkey-cli \ + -h localhost \ + -p "${SERVER_PORT}" \ + ping +) +if [ "$?" -eq "124" ]; then + echo "Timed out" + exit 1 +fi +if [ "$response" != "PONG" ]; then + echo "$response" + exit 1 +fi \ No newline at end of file diff --git a/rootfs/scripts/ping_sentinel.sh b/rootfs/scripts/ping_sentinel.sh new file mode 100755 index 0000000..159f4c8 --- /dev/null +++ b/rootfs/scripts/ping_sentinel.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# shellcheck disable=SC1091 +. /scripts/init.sh + +response=$( + timeout -s 3 "$1" \ + valkey-cli \ + -h localhost \ + -p "${SENTINEL_PORT}" \ + ping +) +if [ "$?" -eq "124" ]; then + echo "Timed out" + exit 1 +fi +if [ "$response" != "PONG" ]; then + echo "$response" + exit 1 +fi diff --git a/rootfs/scripts/prestop-sentinel.sh b/rootfs/scripts/prestop-sentinel.sh new file mode 100755 index 0000000..0bb158b --- /dev/null +++ b/rootfs/scripts/prestop-sentinel.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# shellcheck disable=SC1091 +. /scripts/init.sh + +run_sentinel_command() { + valkey-cli -h "$DRYCC_VALKEY_SENTINEL" -p "${SENTINEL_PORT}" sentinel "$@" +} + +failover_finished() { + # shellcheck disable=SC2207 + SENTINEL_INFO=($(run_sentinel_command get-master-addr-by-name drycc)) + VALKEY_MASTER_HOST="${SENTINEL_INFO[0]}" + [[ "$VALKEY_MASTER_HOST" != "$(hostname -I | xargs)" ]] +} + +if ! failover_finished; then + echo "I am the master pod and you are stopping me. Starting sentinel failover" + # if I am the master, issue a command to failover once and then wait for the failover to finish + run_sentinel_command failover drycc + if retry_while "failover_finished" 30 1; then + echo "Master has been successfuly failed over to a different pod." + exit 0 + else + echo "Master failover failed" + exit 1 + fi +else + exit 0 +fi \ No newline at end of file diff --git a/rootfs/scripts/prestop-valkey.sh b/rootfs/scripts/prestop-valkey.sh new file mode 100755 index 0000000..275cee6 --- /dev/null +++ b/rootfs/scripts/prestop-valkey.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# shellcheck disable=SC1091 +. /scripts/init.sh + +run_valkey_command() { + valkey-cli -h localhost -p "${SERVER_PORT}" "$@" +} + +failover_finished() { + VALKEY_ROLE=$(run_valkey_command role | head -1) + [[ "$VALKEY_ROLE" != "master" ]] +} + +if ! failover_finished; then + echo "Waiting for sentinel to run failover for up to {{ sub .Values.sentinel.terminationGracePeriodSeconds 10 }}s" + retry_while "failover_finished" 30 1 +else + exit 0 +fi