优化启动脚本
This commit is contained in:
+103
-6
@@ -11,6 +11,7 @@ BACKEND_DATA_DIR="${PROJECT_ROOT}/apps/backend/data"
|
|||||||
BACKEND_CONTAINER_UID=1001
|
BACKEND_CONTAINER_UID=1001
|
||||||
BACKEND_CONTAINER_GID=1001
|
BACKEND_CONTAINER_GID=1001
|
||||||
HEALTH_URL=""
|
HEALTH_URL=""
|
||||||
|
READY_TIMEOUT="${READY_TIMEOUT:-120}"
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
printf '\033[1;34m[deploy]\033[0m %s\n' "$*"
|
printf '\033[1;34m[deploy]\033[0m %s\n' "$*"
|
||||||
@@ -60,6 +61,8 @@ validate_env_file() {
|
|||||||
fail ".env 仍包含示例占位值,请替换后再部署。"
|
fail ".env 仍包含示例占位值,请替换后再部署。"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
[[ "${READY_TIMEOUT}" =~ ^[1-9][0-9]*$ ]] || fail "READY_TIMEOUT 必须是正整数秒数,当前值:${READY_TIMEOUT}"
|
||||||
|
|
||||||
local site_addr
|
local site_addr
|
||||||
site_addr="$(read_env_value CADDY_SITE_ADDR)"
|
site_addr="$(read_env_value CADDY_SITE_ADDR)"
|
||||||
[[ -n "${site_addr}" ]] || fail ".env 缺少 CADDY_SITE_ADDR。"
|
[[ -n "${site_addr}" ]] || fail ".env 缺少 CADDY_SITE_ADDR。"
|
||||||
@@ -100,28 +103,122 @@ ensure_data_dir() {
|
|||||||
warn "sudo chown -R ${BACKEND_CONTAINER_UID}:${BACKEND_CONTAINER_GID} ${BACKEND_DATA_DIR}"
|
warn "sudo chown -R ${BACKEND_CONTAINER_UID}:${BACKEND_CONTAINER_GID} ${BACKEND_DATA_DIR}"
|
||||||
}
|
}
|
||||||
|
|
||||||
deploy_stack() {
|
check_compose_config() {
|
||||||
|
log "检查 Docker Compose 配置"
|
||||||
|
docker compose config >/dev/null || fail "Docker Compose 配置校验失败。"
|
||||||
|
}
|
||||||
|
|
||||||
|
pull_base_images() {
|
||||||
log "拉取基础镜像"
|
log "拉取基础镜像"
|
||||||
docker compose pull --ignore-buildable
|
docker compose pull --ignore-buildable
|
||||||
|
}
|
||||||
|
|
||||||
log "构建并启动服务"
|
build_images() {
|
||||||
if docker compose up -d --build; then
|
log "构建后端镜像"
|
||||||
|
docker compose build backend || fail "后端镜像构建失败。"
|
||||||
|
|
||||||
|
log "构建 Web 镜像"
|
||||||
|
docker compose build web || fail "Web 镜像构建失败。"
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_service() {
|
||||||
|
local service="$1"
|
||||||
|
local label="$2"
|
||||||
|
local attempt container_id status health_status
|
||||||
|
|
||||||
|
log "等待 ${label} 就绪"
|
||||||
|
|
||||||
|
for ((attempt = 1; attempt <= READY_TIMEOUT; attempt++)); do
|
||||||
|
container_id="$(docker compose ps -q "${service}" 2>/dev/null || true)"
|
||||||
|
if [[ -n "${container_id}" ]]; then
|
||||||
|
status="$(docker inspect -f '{{.State.Status}}' "${container_id}" 2>/dev/null || true)"
|
||||||
|
health_status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{end}}' "${container_id}" 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [[ -n "${health_status}" && "${health_status}" == "healthy" ]]; then
|
||||||
|
log "${label} 已就绪"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${health_status}" && "${status}" == "running" ]]; then
|
||||||
|
log "${label} 已启动"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${status}" == "exited" || "${status}" == "dead" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
print_diagnostics
|
||||||
|
fail "${label} 启动超时,请根据上面的日志排查。"
|
||||||
|
}
|
||||||
|
|
||||||
|
start_postgres() {
|
||||||
|
log "启动 PostgreSQL"
|
||||||
|
if docker compose up -d --no-deps postgres; then
|
||||||
|
wait_for_service postgres "PostgreSQL"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_diagnostics
|
print_diagnostics
|
||||||
fail "docker compose 启动失败,请根据上面的日志排查。"
|
fail "PostgreSQL 启动失败,请根据上面的日志排查。"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_database_migrations() {
|
||||||
|
log "执行数据库迁移"
|
||||||
|
if docker compose run --rm --no-deps backend node dist/db/migrate.js; then
|
||||||
|
log "数据库迁移完成"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_diagnostics
|
||||||
|
fail "数据库迁移失败,请根据上面的日志排查。"
|
||||||
|
}
|
||||||
|
|
||||||
|
restart_backend() {
|
||||||
|
log "重建并启动后端"
|
||||||
|
if docker compose up -d --no-deps --force-recreate backend; then
|
||||||
|
wait_for_service backend "后端"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_diagnostics
|
||||||
|
fail "后端启动失败,请根据上面的日志排查。"
|
||||||
|
}
|
||||||
|
|
||||||
|
restart_web() {
|
||||||
|
log "重建并启动 Web 入口"
|
||||||
|
if docker compose up -d --no-deps --force-recreate --remove-orphans web; then
|
||||||
|
wait_for_service web "Web"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_diagnostics
|
||||||
|
fail "Web 启动失败,请根据上面的日志排查。"
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy_stack() {
|
||||||
|
check_compose_config
|
||||||
|
pull_base_images
|
||||||
|
build_images
|
||||||
|
start_postgres
|
||||||
|
run_database_migrations
|
||||||
|
restart_backend
|
||||||
|
restart_web
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_for_health() {
|
wait_for_health() {
|
||||||
log "等待服务健康检查:${HEALTH_URL}"
|
log "等待服务健康检查:${HEALTH_URL}"
|
||||||
|
|
||||||
for _ in $(seq 1 60); do
|
for _ in $(seq 1 "${READY_TIMEOUT}"); do
|
||||||
if curl -fsS "${HEALTH_URL}" >/dev/null 2>&1; then
|
if curl -fsS "${HEALTH_URL}" >/dev/null 2>&1; then
|
||||||
log "服务已就绪"
|
log "服务已就绪"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
sleep 2
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
print_diagnostics
|
print_diagnostics
|
||||||
|
|||||||
Reference in New Issue
Block a user