Copied production-quality Dockerfile from hostuk (FrankenPHP 1-php8.5, Octane, Supervisor, Redis). Added docker-compose.yml with Traefik labels for lthn.io, api.lthn.io, docs.lthn.io, explorer.lthn.io. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
173 lines
5.1 KiB
Bash
173 lines
5.1 KiB
Bash
#!/bin/sh
|
|
set -e
|
|
|
|
# Redis Multi-Host Replication Entrypoint
|
|
# Configures Redis as master or replica based on REDIS_NODES env var
|
|
# First IP in REDIS_NODES becomes master, all others are replicas
|
|
|
|
# Default values
|
|
REDIS_PORT=${REDIS_PORT:-6379}
|
|
REDIS_SENTINEL_PORT=${REDIS_SENTINEL_PORT:-26379}
|
|
REDIS_MASTER_NAME=${REDIS_MASTER_NAME:-hosthub}
|
|
REDIS_DIR=/data/redis
|
|
REDIS_CONF=/etc/redis.conf
|
|
SENTINEL_CONF=/etc/sentinel.conf
|
|
|
|
mkdir -p $REDIS_DIR
|
|
|
|
# Container-friendly Redis options (suppress kernel warnings we can't fix)
|
|
CONTAINER_OPTS="--stop-writes-on-bgsave-error no --save '' --appendonly no"
|
|
|
|
# If no REDIS_NODES and no REDIS_REPLICATION_KEY, run standalone without auth
|
|
if [ -z "$REDIS_NODES" ] && [ -z "$REDIS_REPLICATION_KEY" ]; then
|
|
echo "[Redis] No replication configured, running standalone (no auth)..."
|
|
redis-server --port $REDIS_PORT --dir $REDIS_DIR $CONTAINER_OPTS \
|
|
--loglevel warning --daemonize yes
|
|
|
|
# Wait for Redis to be ready before letting other services start
|
|
for i in 1 2 3 4 5; do
|
|
if redis-cli -p $REDIS_PORT ping 2>/dev/null | grep -q PONG; then
|
|
echo "[Redis] Standalone Redis is ready"
|
|
exit 0
|
|
fi
|
|
echo "[Redis] Waiting for Redis to start... ($i/5)"
|
|
sleep 1
|
|
done
|
|
echo "[Redis] Warning: Redis may not be fully ready"
|
|
exit 0
|
|
fi
|
|
|
|
# If no REDIS_NODES but has password, run standalone with auth
|
|
if [ -z "$REDIS_NODES" ]; then
|
|
echo "[Redis] Running standalone with authentication..."
|
|
redis-server --port $REDIS_PORT --dir $REDIS_DIR $CONTAINER_OPTS \
|
|
--loglevel warning --requirepass "$REDIS_REPLICATION_KEY" --daemonize yes
|
|
|
|
# Wait for Redis to be ready before letting other services start
|
|
for i in 1 2 3 4 5; do
|
|
if redis-cli -a "$REDIS_REPLICATION_KEY" -p $REDIS_PORT ping 2>/dev/null | grep -q PONG; then
|
|
echo "[Redis] Standalone Redis (with auth) is ready"
|
|
exit 0
|
|
fi
|
|
echo "[Redis] Waiting for Redis to start... ($i/5)"
|
|
sleep 1
|
|
done
|
|
echo "[Redis] Warning: Redis may not be fully ready"
|
|
exit 0
|
|
fi
|
|
|
|
# Replication mode - determine our role
|
|
echo "[Redis] Replication mode enabled"
|
|
echo "[Redis] Nodes: $REDIS_NODES"
|
|
|
|
# Get our IP - try multiple methods
|
|
MY_IP=$(hostname -i 2>/dev/null | awk '{print $1}')
|
|
if [ -z "$MY_IP" ]; then
|
|
MY_IP=$(ip route get 1 2>/dev/null | awk '{print $NF;exit}')
|
|
fi
|
|
if [ -z "$MY_IP" ]; then
|
|
MY_IP="127.0.0.1"
|
|
fi
|
|
|
|
MASTER_IP=$(echo $REDIS_NODES | cut -d',' -f1 | tr -d ' ')
|
|
echo "[Redis] My IP: $MY_IP, Master IP: $MASTER_IP"
|
|
|
|
# Generate redis.conf
|
|
cat > $REDIS_CONF <<EOF
|
|
# Redis Configuration - Auto-generated
|
|
port $REDIS_PORT
|
|
bind 0.0.0.0
|
|
dir $REDIS_DIR
|
|
requirepass $REDIS_REPLICATION_KEY
|
|
masterauth $REDIS_REPLICATION_KEY
|
|
|
|
# Persistence
|
|
save 900 1
|
|
save 300 10
|
|
save 60 10000
|
|
appendonly yes
|
|
appendfsync everysec
|
|
|
|
# Memory management
|
|
maxmemory 256mb
|
|
maxmemory-policy allkeys-lru
|
|
|
|
# Replication settings
|
|
replica-read-only yes
|
|
replica-serve-stale-data yes
|
|
repl-diskless-sync yes
|
|
repl-diskless-sync-delay 5
|
|
EOF
|
|
|
|
# Determine role based on IP match
|
|
if [ "$MY_IP" = "$MASTER_IP" ]; then
|
|
echo "[Redis] Starting as MASTER"
|
|
ROLE="master"
|
|
else
|
|
echo "[Redis] Starting as REPLICA of $MASTER_IP:$REDIS_PORT"
|
|
ROLE="replica"
|
|
echo "replicaof $MASTER_IP $REDIS_PORT" >> $REDIS_CONF
|
|
fi
|
|
|
|
# Generate sentinel.conf
|
|
# Count nodes for quorum (majority needed)
|
|
NODE_COUNT=$(echo $REDIS_NODES | tr ',' '\n' | wc -l | tr -d ' ')
|
|
QUORUM=$(( (NODE_COUNT / 2) + 1 ))
|
|
echo "[Redis] Sentinel quorum: $QUORUM of $NODE_COUNT nodes"
|
|
|
|
cat > $SENTINEL_CONF <<EOF
|
|
# Sentinel Configuration - Auto-generated
|
|
port $REDIS_SENTINEL_PORT
|
|
bind 0.0.0.0
|
|
dir $REDIS_DIR
|
|
|
|
# Monitor the master
|
|
sentinel monitor $REDIS_MASTER_NAME $MASTER_IP $REDIS_PORT $QUORUM
|
|
sentinel auth-pass $REDIS_MASTER_NAME $REDIS_REPLICATION_KEY
|
|
|
|
# Timing settings
|
|
sentinel down-after-milliseconds $REDIS_MASTER_NAME 5000
|
|
sentinel failover-timeout $REDIS_MASTER_NAME 60000
|
|
sentinel parallel-syncs $REDIS_MASTER_NAME 1
|
|
|
|
# Announce our IP for proper failover
|
|
sentinel announce-ip $MY_IP
|
|
sentinel announce-port $REDIS_SENTINEL_PORT
|
|
EOF
|
|
|
|
# Add known sentinels (other nodes)
|
|
for NODE in $(echo $REDIS_NODES | tr ',' ' '); do
|
|
if [ "$NODE" != "$MY_IP" ]; then
|
|
echo "sentinel known-sentinel $REDIS_MASTER_NAME $NODE $REDIS_SENTINEL_PORT" >> $SENTINEL_CONF
|
|
fi
|
|
done
|
|
|
|
# Start Redis
|
|
echo "[Redis] Starting Redis server..."
|
|
redis-server $REDIS_CONF --daemonize yes
|
|
|
|
# Wait for Redis to be ready
|
|
sleep 2
|
|
if redis-cli -a "$REDIS_REPLICATION_KEY" ping 2>/dev/null | grep -q PONG; then
|
|
echo "[Redis] Redis is ready"
|
|
else
|
|
echo "[Redis] Warning: Redis may not be fully ready"
|
|
fi
|
|
|
|
# Start Sentinel
|
|
echo "[Redis] Starting Sentinel..."
|
|
redis-sentinel $SENTINEL_CONF --daemonize yes
|
|
|
|
# Wait for Sentinel
|
|
sleep 1
|
|
if redis-cli -p $REDIS_SENTINEL_PORT ping 2>/dev/null | grep -q PONG; then
|
|
echo "[Redis] Sentinel is ready"
|
|
|
|
# Show replication info
|
|
echo "[Redis] Replication status:"
|
|
redis-cli -a "$REDIS_REPLICATION_KEY" INFO replication 2>/dev/null | grep -E "^role:|^master_host:|^connected_slaves:" || true
|
|
else
|
|
echo "[Redis] Warning: Sentinel may not be fully ready"
|
|
fi
|
|
|
|
echo "[Redis] Setup complete (role: $ROLE)"
|