1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2025-12-13 01:45:59 +00:00

Add redis-to-valkey migratior

This commit is contained in:
FreddleSpl0it
2025-02-28 15:49:28 +01:00
parent c27000215e
commit 0698159f07
3 changed files with 138 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
FROM python:3.13.2-alpine3.21
WORKDIR /app
COPY migrate.py /app/migrate.py
RUN pip install --no-cache-dir redis
CMD ["python", "/app/migrate.py"]

View File

@@ -0,0 +1,78 @@
import subprocess
import redis
import time
import os
# Container names
SOURCE_CONTAINER = "redis-old-mailcow"
DEST_CONTAINER = "valkey-mailcow"
VALKEYPASS = os.getenv("VALKEYPASS")
def migrate_redis():
src_redis = redis.StrictRedis(host=SOURCE_CONTAINER, port=6379, db=0, password=VALKEYPASS, decode_responses=False)
dest_redis = redis.StrictRedis(host=DEST_CONTAINER, port=6379, db=0, password=VALKEYPASS, decode_responses=False)
cursor = 0
batch_size = 100
migrated_count = 0
print("Starting migration...")
while True:
cursor, keys = src_redis.scan(cursor=cursor, match="*", count=batch_size)
keys_to_migrate = [key for key in keys if not key.startswith(b"PHPREDIS_SESSION:")]
for key in keys_to_migrate:
key_type = src_redis.type(key)
print(f"Import {key} of type {key_type}")
if key_type == b"string":
value = src_redis.get(key)
dest_redis.set(key, value)
elif key_type == b"hash":
value = src_redis.hgetall(key)
dest_redis.hset(key, mapping=value)
elif key_type == b"list":
value = src_redis.lrange(key, 0, -1)
for v in value:
dest_redis.rpush(key, v)
elif key_type == b"set":
value = src_redis.smembers(key)
for v in value:
dest_redis.sadd(key, v)
elif key_type == b"zset":
value = src_redis.zrange(key, 0, -1, withscores=True)
for v, score in value:
dest_redis.zadd(key, {v: score})
# Preserve TTL if exists
ttl = src_redis.ttl(key)
if ttl > 0:
dest_redis.expire(key, ttl)
migrated_count += 1
if cursor == 0:
break # No more keys to scan
print(f"Migration completed! {migrated_count} keys migrated.")
print("Forcing Valkey to save data...")
try:
dest_redis.save() # Immediate RDB save (blocking)
dest_redis.bgrewriteaof() # Rewrites the AOF file in the background
print("Data successfully saved to disk.")
except Exception as e:
print(f"Failed to save data: {e}")
# Main script execution
if __name__ == "__main__":
try:
migrate_redis()
finally:
pass

View File

@@ -0,0 +1,52 @@
#!/bin/bash
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
source "${SCRIPT_DIR}/../mailcow.conf"
VOLUME="${COMPOSE_PROJECT_NAME}_redis-vol-1"
if ! docker volume inspect "$VOLUME" &>/dev/null; then
echo "Error: Docker volume '$VOLUME' does not exist. Nothing to migrate."
exit 1
fi
read -p "Do you want to proceed with the migration of your old redis data to valkey? (y/n) " CONFIRM
if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "Migration aborted."
exit 0
fi
# Run the old Redis container
docker run -d --name redis-old-mailcow \
--restart always \
--network ${COMPOSE_PROJECT_NAME}_mailcow-network \
--hostname redis-old \
--volume ${VOLUME}:/data/ \
--volume ${SCRIPT_DIR}/../data/conf/valkey/valkey-conf.sh:/valkey-conf.sh:z \
--entrypoint "/bin/sh" \
-e VALKEYPASS="${VALKEYPASS}" \
redis:7.4.2-alpine -c "/valkey-conf.sh && redis-server /valkey.conf"
# Wait for old Redis to be ready
echo "Waiting for redis-old-mailcow to be ready..."
until docker exec redis-old-mailcow redis-cli -a "$VALKEYPASS" ping | grep -q "PONG"; do
echo "Redis not ready yet..."
sleep 2
done
echo "redis-old-mailcow is ready!"
# Run the migrate container
docker run --rm --name valkeymigrator-mailcow \
--network ${COMPOSE_PROJECT_NAME}_mailcow-network \
-e VALKEYPASS="${VALKEYPASS}" \
mailcow/valkeymigrator:0.1
echo "Migration completed!"
docker stop redis-old-mailcow
docker rm redis-old-mailcow
read -p "Do you want to delete the old Redis volume? (y/n) " CONFIRM
if [[ "$CONFIRM" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
docker volume rm "$VOLUME"
echo "Docker volume '$VOLUME' has been deleted."
fi