Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions addons/valkey/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
apiVersion: v2
name: valkey
description: "Valkey is an open-source, high-performance key/value store. This addon provisions Valkey Cluster topologies on KubeBlocks. Valkey speaks the Redis protocol and uses Redis-compatible cluster bootstrap; this is a sibling addon to `redis` so upstream redis evolution does not conflict with our Valkey customizations."

type: application

version: 0.1.0

appVersion: "9.0.4"

# Add a dependency to the kubeblocks definition library chart, same as the redis addon.
dependencies:
- name: kblib
version: 0.1.0
repository: file://../kblib
alias: extra

home: https://valkey.io/
icon: https://valkey.io/img/Valkey_Logo_Color.svg
keywords:
- valkey
- redis
- database
- nosql
- cluster

maintainers:
- name: GetStream
url: https://github.com/GetStream/kubeblocks-addons/

annotations:
addon.kubeblocks.io/kubeblocks-version: ">=1.0.0"
addon.kubeblocks.io/model: "key-value"
addon.kubeblocks.io/provider: "community"
129 changes: 129 additions & 0 deletions addons/valkey/config/valkey-cluster-config.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
bind * -::*
tcp-backlog 511
timeout 0
ignore-warnings ARM64-COW-BUG
tcp-keepalive 300
daemonize no
pidfile /var/run/redis_6379.pid
{{ block "logsBlock" . }}
loglevel notice
logfile "/data/running.log"
{{ end }}
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir /data
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-sync-max-replicas 0
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes

# AOF on: required for data preservation across image-swap restarts. Without
# AOF, shutdown-save races with shutdown-timeout under concurrent writes, and
# a flushed dump.rdb can wipe a shard via the "empty master returns" cluster
# bus path. With AOF, every write is on disk within ~1s; restart replays AOF.
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
aof-timestamp-enabled no

# No scheduled BGSAVE: AOF gives us continuous durability; periodic BGSAVE
# forks add latency without adding safety.
save ""

# Generous shutdown budget: AOF makes the final save cheap, but during AOF
# rewrite or under load there can still be I/O to drain. Paired with the
# cmpd's terminationGracePeriodSeconds (must be > this value).
shutdown-timeout 25

slowlog-log-slower-than 10000
slowlog-max-len 128

# Observability: log event-loop stalls > 25ms. Negligible overhead, big
# diagnostic value (without it, LATENCY DOCTOR returns nothing).
latency-monitor-threshold 25

notify-keyspace-events ""
hash-max-listpack-entries 512
hash-max-listpack-value 64
list-max-listpack-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-listpack-entries 128
zset-max-listpack-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
enable-debug-command yes
aclfile /etc/redis/users.acl

# Single IO thread: at the pod CPU limit, 4 IO threads + main thread caused
# CFS throttling (~8% of periods at 1500m). Our workload is fine
# single-threaded. STARTUP-ONLY (CONFIG SET rejects io-threads).
io-threads 1
io-threads-do-reads yes

# configuration for valkey cluster (Redis-protocol compatible)
cluster-enabled yes
cluster-config-file /data/nodes.conf
cluster-allow-replica-migration no
cluster-node-timeout 5000
cluster-replica-validity-factor 0
cluster-require-full-coverage yes
cluster-allow-reads-when-down no

# Eviction policy: allkeys-lru (cache mode — we want eviction across the
# whole keyspace, not just keys with TTLs).
maxmemory-policy allkeys-lru
# maxmemory: 85% of the pod memory limit, leaving ~15% headroom for
# connection / replication buffers. Persistence is disabled, so no RDB-fork
# memory doubling concern.
{{- $limit_memory := default 0 $.PHY_MEMORY | int }}
{{- if gt $limit_memory 0 }}
maxmemory {{ mulf $limit_memory 0.85 | int }}
{{- end }}

{{- if eq (index $ "TLS_ENABLED") "true" }}
tls-cert-file {{ $.TLS_MOUNT_PATH }}/tls.crt
tls-key-file {{ $.TLS_MOUNT_PATH }}/tls.key
tls-ca-cert-file {{ $.TLS_MOUNT_PATH }}/ca.crt
tls-auth-clients no
tls-replication yes
tls-cluster yes
port 0
{{- end -}}
32 changes: 32 additions & 0 deletions addons/valkey/scripts-ut-spec/utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash

# utils functions for shellspec unit tests

convert_tpl_to_bash() {
local input_file="$1"
local output_file="$2"

sed -e '/^{{\/\*$/,/^\*\/}}$/d' \
-e '/^{{-.*}}/d' \
-e 's/{{- define ".*" }}//' \
-e 's/{{- end }}//' \
"$input_file" >> "$output_file"
}

generate_common_library() {
local library_file="$1"

libcommons_tpl_file="../../kblib/templates/_libcommons.tpl"
libpods_tpl_file="../../kblib/templates/_libpods.tpl"
libstrings_tpl_file="../../kblib/templates/_libstrings.tpl"
libenvs_tpl_file="../../kblib/templates/_libenvs.tpl"
libcompvars_tpl_file="../../kblib/templates/_libcompvars.tpl"
libututils_tpl_file="../../kblib/templates/_libututils.tpl"

convert_tpl_to_bash $libcommons_tpl_file "$library_file"
convert_tpl_to_bash $libpods_tpl_file "$library_file"
convert_tpl_to_bash $libstrings_tpl_file "$library_file"
convert_tpl_to_bash $libenvs_tpl_file "$library_file"
convert_tpl_to_bash $libcompvars_tpl_file "$library_file"
convert_tpl_to_bash $libututils_tpl_file "$library_file"
}
114 changes: 114 additions & 0 deletions addons/valkey/scripts-ut-spec/valkey_cluster_common_spec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# shellcheck shell=bash
# shellcheck disable=SC2034

# Tightly scoped spec for the Valkey-specific edits to the cluster bootstrap
# helpers. Full coverage of the upstream script behaviour lives in the redis
# addon's spec; here we cover only what the valkey addon adds:
#
# - build_single_shard_addslots_command (new helper for 1-shard provisioning)
# - create_redis_cluster branch on primary_count == 1

# validate_shell_type_and_version defined in shellspec/spec_helper.sh used to validate the expected shell type and version this script needs to run.
if ! validate_shell_type_and_version "bash" 4 &>/dev/null; then
echo "valkey_cluster_common_spec.sh skip cases because dependency bash version 4 or higher is not installed."
exit 0
fi

source ./utils.sh

common_library_file="./common.sh"
generate_common_library $common_library_file

Describe "Valkey Cluster Common Bash Script Tests"
Include $common_library_file
Include ../valkey-cluster-scripts/valkey-cluster-common.sh

init() {
# ut_mode=true makes unset_xtrace_when_ut_mode_false / set_xtrace_when_ut_mode_false
# no-op so xtrace doesn't leak into stderr expectations.
ut_mode="true"
}
BeforeAll "init"

cleanup() {
rm -f $common_library_file
}
AfterAll 'cleanup'

setup_redis_cli_env() {
REDIS_CLI_TLS_CMD=""
}
Before "setup_redis_cli_env"

Describe "build_single_shard_addslots_command()"
Context "without password"
It "uses CLUSTER ADDSLOTSRANGE 0 16383"
node_endpoint="172.0.0.1:6379"

When call build_single_shard_addslots_command "$node_endpoint"
The output should eq "redis-cli -h 172.0.0.1 -p 6379 cluster addslotsrange 0 16383"
The stderr should include "initialize single-shard cluster command: redis-cli -h 172.0.0.1 -p 6379 cluster addslotsrange 0 16383"
End
End

Context "with password"
setup() {
export REDIS_DEFAULT_PASSWORD="password"
}
Before "setup"

un_setup() {
unset REDIS_DEFAULT_PASSWORD
}
After "un_setup"

It "passes auth via -a and masks password in log"
node_endpoint="172.0.0.1:6379"

When call build_single_shard_addslots_command "$node_endpoint"
The output should eq "redis-cli -h 172.0.0.1 -p 6379 -a password cluster addslotsrange 0 16383"
The stderr should include "initialize single-shard cluster command: redis-cli -h 172.0.0.1 -p 6379 -a ******** cluster addslotsrange 0 16383"
End
End
End

Describe "create_redis_cluster()"
Context "with a single primary"
build_single_shard_addslots_command() {
echo "ADDSLOTS_CMD"
}
build_redis_cluster_create_command() {
echo "MULTI_SHARD_CMD"
}
ADDSLOTS_CMD() { return 0; }
MULTI_SHARD_CMD() { echo "should not be called"; return 1; }

It "uses the single-shard ADDSLOTS path and skips --cluster create"
primary_nodes="172.0.0.1:6379 "

When call create_redis_cluster "$primary_nodes"
The status should be success
The stdout should not include "should not be called"
End
End

Context "with multiple primaries"
build_single_shard_addslots_command() {
echo "ADDSLOTS_CMD"
}
build_redis_cluster_create_command() {
echo "MULTI_SHARD_CMD"
}
ADDSLOTS_CMD() { echo "should not be called"; return 1; }
MULTI_SHARD_CMD() { return 0; }

It "uses the upstream --cluster create path"
primary_nodes="172.0.0.1:6379 172.0.0.2:6379 172.0.0.3:6379 "

When call create_redis_cluster "$primary_nodes"
The status should be success
The stdout should not include "should not be called"
End
End
End
End
Loading