From 6ddd468423f5446ccc679d12a562fa3828b999f8 Mon Sep 17 00:00:00 2001 From: Thomas Neidhart Date: Thu, 3 Sep 2026 08:45:52 +0200 Subject: [PATCH 1/3] chore: replace the redis cluster in docker-compose with valkey Swap the six-node Redis cluster for Valkey 9.1: valkey/valkey images, valkey-server/valkey-cli, data under ./data/valkey, and the compose profile renamed from `redis` to `valkey`. redis.conf becomes valkey.conf with masteruser/masterauth renamed to primaryuser/primaryauth. REDISCLI_AUTH stays, as valkey-cli still reads the password from it. Valkey bootstraps a cluster the same way Redis does, but the surrounding compose setup is tidied up while we are here: - the six node services differ only in name, port and data directory, so they now share an x-valkey-node anchor - the init service waits for the nodes to be healthy instead of sleeping for a fixed 10s, and passes --cluster-yes rather than piping in a yes - init is idempotent: it only creates the cluster when node-1 still knows just itself, so a restart on existing data no longer fails. It checks known nodes rather than cluster_state because nodes.conf is loaded at startup while the state only turns ok once the nodes have gossiped redisinsight is replaced by valkey-admin, which serves the same purpose for Valkey and takes its connection from the environment, so there is no manual setup in the UI. It listens on 8080, published as 8090 because the server service already publishes 8080. Co-Authored-By: Claude Opus 5 (1M context) --- docker-compose.yml | 206 ++++++++++------------- server/src/dev/resources/application.yml | 2 +- redis.conf => valkey.conf | 6 +- 3 files changed, 90 insertions(+), 124 deletions(-) rename redis.conf => valkey.conf (68%) diff --git a/docker-compose.yml b/docker-compose.yml index b985fd304..b323c2fba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,19 @@ +x-valkey-image: &valkey-image valkey/valkey:9.1 + +# The six cluster nodes below differ only in name, published port and data directory. +x-valkey-node: &valkey-node + image: *valkey-image + command: valkey-server /etc/valkey.conf + environment: + # valkey-cli still reads the password from REDISCLI_AUTH + - REDISCLI_AUTH=openvsx + healthcheck: + test: ["CMD", "valkey-cli", "-p", "7000", "--user", "openvsx", "ping"] + interval: 5s + retries: 5 + profiles: + - valkey + services: postgres: @@ -52,156 +68,106 @@ services: profiles: - kibana - redis-node-1: - image: redis:7.2 - container_name: redis-node-1 + valkey-node-1: + <<: *valkey-node + container_name: valkey-node-1 ports: - "7001:7000" - command: redis-server /etc/redis.conf volumes: - - ./redis.conf:/etc/redis.conf - - ./data/redis/node-1:/data - environment: - - REDISCLI_AUTH=openvsx - healthcheck: - test: ["CMD", "redis-cli", "-p", "7000", "--user", "openvsx", "ping"] - interval: 5s - retries: 5 - profiles: - - redis + - ./valkey.conf:/etc/valkey.conf + - ./data/valkey/node-1:/data - redis-node-2: - image: redis:7.2 - container_name: redis-node-2 - depends_on: - redis-node-1: - condition: service_healthy + valkey-node-2: + <<: *valkey-node + container_name: valkey-node-2 ports: - "7002:7000" - command: redis-server /etc/redis.conf volumes: - - ./redis.conf:/etc/redis.conf - - ./data/redis/node-2:/data - environment: - - REDISCLI_AUTH=openvsx - healthcheck: - test: ["CMD", "redis-cli", "-p", "7000", "--user", "openvsx", "ping"] - interval: 5s - retries: 5 - profiles: - - redis + - ./valkey.conf:/etc/valkey.conf + - ./data/valkey/node-2:/data - redis-node-3: - image: redis:7.2 - container_name: redis-node-3 - depends_on: - redis-node-2: - condition: service_healthy + valkey-node-3: + <<: *valkey-node + container_name: valkey-node-3 ports: - "7003:7000" - command: redis-server /etc/redis.conf volumes: - - ./redis.conf:/etc/redis.conf - - ./data/redis/node-3:/data - environment: - - REDISCLI_AUTH=openvsx - healthcheck: - test: ["CMD", "redis-cli", "-p", "7000", "--user", "openvsx", "ping"] - interval: 5s - retries: 5 - profiles: - - redis + - ./valkey.conf:/etc/valkey.conf + - ./data/valkey/node-3:/data - redis-node-4: - image: redis:7.2 - container_name: redis-node-4 - depends_on: - redis-node-3: - condition: service_healthy + valkey-node-4: + <<: *valkey-node + container_name: valkey-node-4 ports: - "7004:7000" - command: redis-server /etc/redis.conf volumes: - - ./redis.conf:/etc/redis.conf - - ./data/redis/node-4:/data - environment: - - REDISCLI_AUTH=openvsx - healthcheck: - test: ["CMD", "redis-cli", "-p", "7000", "--user", "openvsx", "ping"] - interval: 5s - retries: 5 - profiles: - - redis + - ./valkey.conf:/etc/valkey.conf + - ./data/valkey/node-4:/data - redis-node-5: - image: redis:7.2 - container_name: redis-node-5 - depends_on: - redis-node-4: - condition: service_healthy + valkey-node-5: + <<: *valkey-node + container_name: valkey-node-5 ports: - "7005:7000" - command: redis-server /etc/redis.conf volumes: - - ./redis.conf:/etc/redis.conf - - ./data/redis/node-5:/data - environment: - - REDISCLI_AUTH=openvsx - healthcheck: - test: ["CMD", "redis-cli", "-p", "7000", "--user", "openvsx", "ping"] - interval: 5s - retries: 5 - profiles: - - redis + - ./valkey.conf:/etc/valkey.conf + - ./data/valkey/node-5:/data - redis-node-6: - image: redis:7.2 - container_name: redis-node-6 - depends_on: - redis-node-5: - condition: service_healthy + valkey-node-6: + <<: *valkey-node + container_name: valkey-node-6 ports: - "7006:7000" - command: redis-server /etc/redis.conf volumes: - - ./redis.conf:/etc/redis.conf - - ./data/redis/node-6:/data - environment: - - REDISCLI_AUTH=openvsx - healthcheck: - test: ["CMD", "redis-cli", "-p", "7000", "--user", "openvsx", "ping"] - interval: 5s - retries: 5 - profiles: - - redis + - ./valkey.conf:/etc/valkey.conf + - ./data/valkey/node-6:/data - redis-cluster-init: - image: redis:7.2 + valkey-cluster-init: + image: *valkey-image depends_on: - - redis-node-1 - - redis-node-2 - - redis-node-3 - - redis-node-4 - - redis-node-5 - - redis-node-6 + valkey-node-1: + condition: service_healthy + valkey-node-2: + condition: service_healthy + valkey-node-3: + condition: service_healthy + valkey-node-4: + condition: service_healthy + valkey-node-5: + condition: service_healthy + valkey-node-6: + condition: service_healthy environment: - REDISCLI_AUTH=openvsx + # Nodes keep their nodes.conf in ./data/valkey, so on a restart the cluster is already + # formed and `--cluster create` would fail. Only create when node-1 still knows just itself, + # which keeps `up` idempotent. Checking known nodes rather than cluster_state avoids a race: + # nodes.conf is loaded at startup, while the state only turns ok once the nodes have gossiped. entrypoint: > - bash -c " - sleep 10; - echo yes | redis-cli --user openvsx --cluster create - redis-node-1:7000 redis-node-2:7000 redis-node-3:7000 - redis-node-4:7000 redis-node-5:7000 redis-node-6:7000 - --cluster-replicas 1" - profiles: - - redis - - redisinsight: - image: redis/redisinsight + sh -c " + if valkey-cli -h valkey-node-1 -p 7000 --user openvsx cluster info + | grep -qE 'cluster_known_nodes:1([^0-9]|$$)'; + then valkey-cli --user openvsx --cluster create + valkey-node-1:7000 valkey-node-2:7000 valkey-node-3:7000 + valkey-node-4:7000 valkey-node-5:7000 valkey-node-6:7000 + --cluster-replicas 1 --cluster-yes; + else echo 'valkey cluster already initialized'; + fi" + profiles: + - valkey + + # Web UI for the cluster above; the connection is pre-configured, no manual setup in the UI. + valkey-admin: + image: valkey/valkey-admin:1.1.1 ports: - - '5540:5540' + - '8090:8080' + environment: + - VALKEY_HOST=valkey-node-1 + - VALKEY_PORT=7000 + - VALKEY_USERNAME=openvsx + - VALKEY_PASSWORD=openvsx profiles: - - redisinsight + - valkey-admin server: image: eclipse-temurin:25-jdk diff --git a/server/src/dev/resources/application.yml b/server/src/dev/resources/application.yml index c2913e9b0..77a40bbe6 100644 --- a/server/src/dev/resources/application.yml +++ b/server/src/dev/resources/application.yml @@ -16,7 +16,7 @@ spring: exclude: org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration profiles: include: ovsx -# connect to redis cluster configured in docker-compose.yml +# connect to valkey cluster configured in docker-compose.yml # data: # redis: # cluster: diff --git a/redis.conf b/valkey.conf similarity index 68% rename from redis.conf rename to valkey.conf index c148d85b8..217a2fbb4 100644 --- a/redis.conf +++ b/valkey.conf @@ -1,4 +1,4 @@ -# Configuration for Redis nodes in docker-compose.yml +# Configuration for Valkey nodes in docker-compose.yml port 7000 cluster-enabled yes cluster-config-file nodes.conf @@ -8,5 +8,5 @@ maxmemory 64mb maxmemory-policy allkeys-lru user default off user openvsx on >openvsx ~* +@all allchannels -masteruser openvsx -masterauth openvsx +primaryuser openvsx +primaryauth openvsx From 80ee57ad0068a4c53cd32824ee80efc8b3091fb2 Mon Sep 17 00:00:00 2001 From: Thomas Neidhart Date: Thu, 3 Sep 2026 09:28:57 +0200 Subject: [PATCH 2/3] fixup: make valkey-admin discover the cluster reliably Valkey Admin discovers the topology from the pre-configured connection once at startup and never retries, so it has to start after the cluster exists - otherwise it comes up alongside the nodes, finds no cluster and sits idle with no collectors. Wait for valkey-cluster-init to complete. That dependency crosses a profile boundary, so the cluster services join the valkey-admin profile as well: `--profile valkey-admin` now brings up the cluster plus the UI, while `--profile valkey` stays cluster-only. Also set DEPLOYMENT_MODE and VALKEY_AUTH_TYPE explicitly. Both match the image defaults, but they are what upstream's Docker deployment docs spell out for a pre-configured connection. Co-Authored-By: Claude Opus 5 (1M context) --- docker-compose.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index b323c2fba..9e747fb35 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,8 +11,10 @@ x-valkey-node: &valkey-node test: ["CMD", "valkey-cli", "-p", "7000", "--user", "openvsx", "ping"] interval: 5s retries: 5 + # The admin UI depends on the cluster, so starting it starts the cluster too. profiles: - valkey + - valkey-admin services: @@ -155,15 +157,24 @@ services: fi" profiles: - valkey + - valkey-admin - # Web UI for the cluster above; the connection is pre-configured, no manual setup in the UI. + # Web UI for the cluster above. Pre-configuring the connection makes Valkey Admin discover the + # cluster topology from node-1 on startup and spawn a metrics collector per primary, so there is + # no manual setup in the UI. DEPLOYMENT_MODE=Web is the image default, set here to be explicit. valkey-admin: image: valkey/valkey-admin:1.1.1 + # Discovery is a one-shot at startup with no retry, so wait for the cluster to exist. + depends_on: + valkey-cluster-init: + condition: service_completed_successfully ports: - '8090:8080' environment: + - DEPLOYMENT_MODE=Web - VALKEY_HOST=valkey-node-1 - VALKEY_PORT=7000 + - VALKEY_AUTH_TYPE=password - VALKEY_USERNAME=openvsx - VALKEY_PASSWORD=openvsx profiles: From 403df1ad6300f9f11d14150ad0b58327458ad469 Mon Sep 17 00:00:00 2001 From: Thomas Neidhart Date: Thu, 3 Sep 2026 09:35:49 +0200 Subject: [PATCH 3/3] docs: note what to enter in the valkey-admin connection dialog In Web mode the UI manages connections itself, so pre-configuring the connection starts metrics collection but does not populate the UI - it still asks for one on first use. Record the values that work, including why the published localhost ports are not among them. Co-Authored-By: Claude Opus 5 (1M context) --- docker-compose.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 9e747fb35..7eee25687 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -160,8 +160,12 @@ services: - valkey-admin # Web UI for the cluster above. Pre-configuring the connection makes Valkey Admin discover the - # cluster topology from node-1 on startup and spawn a metrics collector per primary, so there is - # no manual setup in the UI. DEPLOYMENT_MODE=Web is the image default, set here to be explicit. + # cluster topology from node-1 on startup and spawn a metrics collector per primary, so metrics + # are already being collected when you open it. In Web mode the UI still manages connections + # itself, so it asks you to create one on first use - enter host `valkey-node-1`, port `7000`, + # user `openvsx`, password `openvsx` (the admin server resolves the host inside the compose + # network, so the published 127.0.0.1:7001-7006 ports do not work here). + # DEPLOYMENT_MODE=Web is the image default, set here to be explicit. valkey-admin: image: valkey/valkey-admin:1.1.1 # Discovery is a one-shot at startup with no retry, so wait for the cluster to exist.