cc / docker-entrypoint.sh
hequ's picture
Update docker-entrypoint.sh
8783c2d verified
#!/bin/sh
# shellcheck shell=sh
set -e
TS() { date "+%Y-%m-%d %H:%M:%S"; }
log() { echo "[$(TS)] [entrypoint] $*"; }
# -----------------------------------------------------------------------------
# 基础目录
# -----------------------------------------------------------------------------
mkdir -p /app/logs /app/data /app/temp
# Redis 数据目录放在 /app/data/redis,这样能随备份一起保存/恢复
REDIS_DIR="${REDIS_DIR:-/app/data/redis}"
mkdir -p "${REDIS_DIR}"
# -----------------------------------------------------------------------------
# 导出备份相关环境变量(给子进程可见)
# -----------------------------------------------------------------------------
export HF_TOKEN="${HF_TOKEN:-}"
export DATASET_ID="${DATASET_ID:-}"
export SYNC_INTERVAL MAX_BACKUPS BACKUP_PREFIX BACKUP_PATHS BACKUP_EXCLUDE
# 若未指定,给出对持久化友好的默认值(相对路径,配合 tar -C /)
BACKUP_PATHS="${BACKUP_PATHS:-app/data,app/data/redis}"
BACKUP_EXCLUDE="${BACKUP_EXCLUDE:-*.tmp,*.cache,**/.DS_Store}"
export BACKUP_PATHS BACKUP_EXCLUDE
# -----------------------------------------------------------------------------
# 在任何服务启动前先尝试恢复数据(包含 Redis 的 RDB/AOF)
# -----------------------------------------------------------------------------
if [ -n "$HF_TOKEN" ] && [ -n "$DATASET_ID" ]; then
/app/tools/hf-backup.sh restore || log "Restore skipped/failed, continue."
else
log "未配置 HF_TOKEN/DATASET_ID,跳过恢复。"
fi
# -----------------------------------------------------------------------------
# 启动(内置或外置)Redis
# -----------------------------------------------------------------------------
REDIS_HOST="${REDIS_HOST:-127.0.0.1}"
REDIS_PORT="${REDIS_PORT:-6379}"
start_internal_redis="false"
case "$REDIS_HOST" in
""|"127.0.0.1"|"localhost") start_internal_redis="true" ;;
esac
if [ "$start_internal_redis" = "true" ]; then
log "Starting embedded Redis on 127.0.0.1:${REDIS_PORT} ..."
if [ -n "${REDIS_PASSWORD:-}" ]; then
redis-server \
--port "${REDIS_PORT}" --bind 127.0.0.1 \
--dir "${REDIS_DIR}" \
--dbfilename dump.rdb \
--appendonly yes --appendfilename appendonly.aof \
--appendfsync everysec \
--save 60 1 \
--requirepass "${REDIS_PASSWORD}" &
else
redis-server \
--port "${REDIS_PORT}" --bind 127.0.0.1 \
--dir "${REDIS_DIR}" \
--dbfilename dump.rdb \
--appendonly yes --appendfilename appendonly.aof \
--appendfsync everysec \
--save 60 1 &
fi
else
log "Using EXTERNAL Redis at ${REDIS_HOST}:${REDIS_PORT}, skip embedded Redis."
fi
# 等待 Redis 就绪
log "Waiting for Redis on ${REDIS_HOST}:${REDIS_PORT} ..."
i=0
while :; do
if [ -n "${REDIS_PASSWORD:-}" ]; then
if redis-cli -h "${REDIS_HOST}" -p "${REDIS_PORT}" -a "${REDIS_PASSWORD}" ping >/dev/null 2>&1; then
break
fi
else
if redis-cli -h "${REDIS_HOST}" -p "${REDIS_PORT}" ping >/dev/null 2>&1; then
break
fi
fi
i=$((i+1))
if [ "$i" -ge 60 ]; then
log "Redis not ready after 60s, exit."
exit 1
fi
sleep 1
done
log "Redis is ready."
# -----------------------------------------------------------------------------
# 备份守护进程(可选:开机先做一份一次性备份)
# BACKUP_ON_START=true 时,先执行一次上传,随后开启守护
# -----------------------------------------------------------------------------
if [ -n "$HF_TOKEN" ] && [ -n "$DATASET_ID" ]; then
if [ "${BACKUP_ON_START:-false}" = "true" ]; then
/app/tools/hf-backup.sh once || log "First backup failed (ignored)."
fi
# 同时输出到控制台和日志文件,便于在 HF 控制台直接看到
/app/tools/hf-backup.sh daemon 2>&1 | tee -a /app/logs/hf-backup.log &
log "启动 HF Dataset 备份服务(间隔 ${SYNC_INTERVAL:-3600}s,保留 ${MAX_BACKUPS:-10} 份)"
else
log "未配置 HF_TOKEN/DATASET_ID,跳过备份守护进程。"
fi
# -----------------------------------------------------------------------------
# 可选:强制重置管理员(会删除 init.json)
# -----------------------------------------------------------------------------
if [ "${FORCE_ADMIN_RESET:-false}" = "true" ]; then
log "FORCE_ADMIN_RESET=true, remove /app/data/init.json"
rm -f /app/data/init.json
fi
# -----------------------------------------------------------------------------
# 初始化管理员 / 应用准备
# -----------------------------------------------------------------------------
if [ -n "${ADMIN_USERNAME:-}" ] && [ -n "${ADMIN_PASSWORD:-}" ]; then
log "Bootstrapping admin user: ${ADMIN_USERNAME}"
else
log "ADMIN_USERNAME/ADMIN_PASSWORD 未设置,将按已有 init.json 或默认逻辑处理。"
fi
npm run setup
# -----------------------------------------------------------------------------
# 启动应用
# -----------------------------------------------------------------------------
HOST="${HOST:-0.0.0.0}"
PORT="${PORT:-7860}"
log "Starting app on ${HOST}:${PORT} ..."
exec node src/app.js