#!/bin/bash # 固定资产管理系统部署脚本 set -euo pipefail PROJECT_DIR="/opt/equipment-management" COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml" PROJECT_NAME="equipment-management" BACKUP_SCRIPT="$PROJECT_DIR/scripts/backup-equipment.sh" SKIP_BACKUP="${SKIP_BACKUP:-0}" HEALTHCHECK_ATTEMPTS="${HEALTHCHECK_ATTEMPTS:-12}" HEALTHCHECK_INTERVAL_SECONDS="${HEALTHCHECK_INTERVAL_SECONDS:-5}" HEALTHCHECK_URL="${HEALTHCHECK_URL:-http://localhost:3000/api/health}" EQUIPMENT_CONTAINERS=("equipment-frontend" "equipment-backend" "equipment-mysql") LEGACY_CONTAINERS=("shebeiguanli-frontend" "shebeiguanli-backend" "shebeiguanli-mysql") LEGACY_STATUS_BEFORE=() get_container_status() { local container="$1" docker inspect -f '{{.State.Status}}' "$container" 2>/dev/null || printf 'missing\n' } record_legacy_container_statuses() { local index container status echo ">>> 记录摄影设备借还系统容器状态(仅检查,不操作)..." for index in "${!LEGACY_CONTAINERS[@]}"; do container="${LEGACY_CONTAINERS[$index]}" status="$(get_container_status "$container")" LEGACY_STATUS_BEFORE[$index]="$status" echo " $container => $status" done } verify_legacy_container_statuses() { local index container before_status after_status local failed=0 echo ">>> 确认摄影设备借还系统未受影响(仅检查,不操作)..." for index in "${!LEGACY_CONTAINERS[@]}"; do container="${LEGACY_CONTAINERS[$index]}" before_status="${LEGACY_STATUS_BEFORE[$index]}" after_status="$(get_container_status "$container")" echo " $container => 部署前: $before_status,部署后: $after_status" if [ "$before_status" != "missing" ] && [ "$after_status" != "$before_status" ]; then echo " 错误:$container 状态发生变化。部署脚本未对该容器执行任何操作,请立即排查。" >&2 failed=1 fi done return "$failed" } verify_equipment_containers() { local container status local failed=0 echo ">>> 固定资产系统容器状态..." for container in "${EQUIPMENT_CONTAINERS[@]}"; do status="$(get_container_status "$container")" echo " $container => $status" if [ "$status" != "running" ]; then echo " 错误:固定资产容器 $container 未处于 running 状态。" >&2 failed=1 fi done return "$failed" } wait_for_backend_health() { local attempt echo ">>> 检查固定资产系统后端健康状态..." for ((attempt = 1; attempt <= HEALTHCHECK_ATTEMPTS; attempt++)); do if curl -fsS --max-time 5 "$HEALTHCHECK_URL" >/dev/null; then echo " 后端健康检查通过(第 ${attempt}/${HEALTHCHECK_ATTEMPTS} 次)" return 0 fi if [ "$attempt" -lt "$HEALTHCHECK_ATTEMPTS" ]; then echo " 第 ${attempt}/${HEALTHCHECK_ATTEMPTS} 次检查失败,${HEALTHCHECK_INTERVAL_SECONDS} 秒后重试..." sleep "$HEALTHCHECK_INTERVAL_SECONDS" fi done echo "后端健康检查失败:${HEALTHCHECK_URL},已尝试 ${HEALTHCHECK_ATTEMPTS} 次。" >&2 return 1 } if docker compose version >/dev/null 2>&1; then COMPOSE_CMD=(docker compose -p "$PROJECT_NAME" -f "$COMPOSE_FILE") elif command -v docker-compose >/dev/null 2>&1; then COMPOSE_CMD=(docker-compose -p "$PROJECT_NAME" -f "$COMPOSE_FILE") else echo "未找到 docker compose / docker-compose,无法部署。" exit 1 fi echo "==========================================" echo " 固定资产管理系统 - 安全部署脚本" echo "==========================================" echo "项目目录: $PROJECT_DIR" echo "Compose 文件: $COMPOSE_FILE" echo "Compose 项目名: $PROJECT_NAME" echo "备份脚本: $BACKUP_SCRIPT" echo "" if [ ! -f "$COMPOSE_FILE" ]; then echo "未找到 $COMPOSE_FILE" exit 1 fi if ! [[ "$HEALTHCHECK_ATTEMPTS" =~ ^[1-9][0-9]*$ ]]; then echo "HEALTHCHECK_ATTEMPTS 必须是正整数: $HEALTHCHECK_ATTEMPTS" exit 1 fi if ! [[ "$HEALTHCHECK_INTERVAL_SECONDS" =~ ^[0-9]+$ ]]; then echo "HEALTHCHECK_INTERVAL_SECONDS 必须是非负整数: $HEALTHCHECK_INTERVAL_SECONDS" exit 1 fi cd "$PROJECT_DIR" record_legacy_container_statuses if [ "$SKIP_BACKUP" = "1" ]; then echo ">>> 已设置 SKIP_BACKUP=1,跳过备份" else if [ ! -x "$BACKUP_SCRIPT" ]; then echo "备份脚本不存在或不可执行: $BACKUP_SCRIPT" exit 1 fi echo ">>> 先执行固定资产系统备份..." "$BACKUP_SCRIPT" fi echo ">>> 先构建固定资产系统镜像..." "${COMPOSE_CMD[@]}" build echo ">>> 镜像构建成功,开始更新固定资产系统容器..." "${COMPOSE_CMD[@]}" up -d --remove-orphans deployment_failed=0 if ! wait_for_backend_health; then deployment_failed=1 fi if ! verify_equipment_containers; then deployment_failed=1 fi if ! verify_legacy_container_statuses; then deployment_failed=1 fi if [ "$deployment_failed" -ne 0 ]; then echo "固定资产系统部署校验失败,请根据上述错误排查。" >&2 exit 1 fi echo "" echo "==========================================" echo " 部署完成" SERVER_HOST="${SERVER_HOST:-}" echo " 固定资产前端: http://$SERVER_HOST" echo " 固定资产后端: http://$SERVER_HOST:3000/api" echo " 摄影设备前端: http://$SERVER_HOST:8081" echo " 摄影设备后端: http://$SERVER_HOST:3001" echo "=========================================="