#!/bin/bash # IoT Platform 容器化一键部署脚本 (Podman) # 用法: # ./deploy.sh --build # 本地构建后部署 # ./deploy.sh --jar path/to/jar # 使用指定 jar 部署 # ./deploy.sh --build --jar path # 构建并使用指定 jar(覆盖) # # 环境变量: # SERVER_HOST 默认: 47.104.204.180 # SERVER_USER 默认: root # REMOTE_DIR 默认: /opt/iot-platform set -e # 配置 SERVER_HOST="${SERVER_HOST:-47.104.204.180}" SERVER_USER="${SERVER_USER:-root}" REMOTE_DIR="${REMOTE_DIR:-/mnt/iot-platform}" APP_NAME="iot-platform" LOCAL_JAR="" DO_BUILD=false NO_ROLLBACK=false # 颜色 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # 解析参数 while [[ $# -gt 0 ]]; do case $1 in --build) DO_BUILD=true shift ;; --no-rollback) NO_ROLLBACK=true shift ;; --jar) LOCAL_JAR="$2" shift 2 ;; --help|-h) echo "用法: ./deploy.sh [--build] [--no-rollback] [--jar ]" echo " --build 本地执行 mvn clean package" echo " --no-rollback 健康检查失败时不自动回滚,保留新版本用于排查" echo " --jar 指定要部署的 jar 文件路径" exit 0 ;; *) echo "未知参数: $1" exit 1 ;; esac done # 确定 jar 路径 if [ "$DO_BUILD" = true ]; then echo -e "${YELLOW}[deploy] 开始本地构建...${NC}" cd "$(dirname "$0")/.." mvn clean package -pl iot-platform -am -Dmaven.test.skip=true LOCAL_JAR="iot-platform/target/iot-platform.jar" echo -e "${GREEN}[deploy] 构建完成: ${LOCAL_JAR}${NC}" fi if [ -z "$LOCAL_JAR" ]; then # 默认使用本地 target 下的 jar cd "$(dirname "$0")/.." LOCAL_JAR="iot-platform/target/iot-platform.jar" fi if [ ! -f "$LOCAL_JAR" ]; then echo -e "${RED}[deploy] 错误: 找不到 jar 文件: ${LOCAL_JAR}${NC}" exit 1 fi JAR_NAME=$(basename "$LOCAL_JAR") TIMESTAMP=$(date +%Y%m%d-%H%M%S) BACKUP_NAME="${APP_NAME}-${TIMESTAMP}.jar" echo "========================================" echo "IoT Platform 部署" echo "========================================" echo "目标服务器: ${SERVER_USER}@${SERVER_HOST}" echo "远程目录: ${REMOTE_DIR}" echo "本地 JAR: ${LOCAL_JAR}" echo "========================================" # 步骤 1: 上传 JAR 到临时目录 echo -e "${YELLOW}[1/6] 上传 JAR 到服务器...${NC}" ssh "${SERVER_USER}@${SERVER_HOST}" "mkdir -p ${REMOTE_DIR}/tmp ${REMOTE_DIR}/backup" scp "${LOCAL_JAR}" "${SERVER_USER}@${SERVER_HOST}:${REMOTE_DIR}/tmp/${JAR_NAME}" echo -e "${GREEN}[1/6] 上传完成${NC}" # 步骤 2: 备份当前版本 echo -e "${YELLOW}[2/6] 备份当前版本...${NC}" ssh "${SERVER_USER}@${SERVER_HOST}" " if [ -f ${REMOTE_DIR}/${APP_NAME}.jar ]; then cp -a ${REMOTE_DIR}/${APP_NAME}.jar ${REMOTE_DIR}/backup/${BACKUP_NAME} echo ' 已备份: ${BACKUP_NAME}' ls -lh ${REMOTE_DIR}/backup/ | tail -5 # 清理旧备份,保留最近 10 个 BACKUP_COUNT=\$(ls -1t ${REMOTE_DIR}/backup/${APP_NAME}-*.jar 2>/dev/null | wc -l) if [ "\$BACKUP_COUNT" -gt 3 ]; then ls -1t ${REMOTE_DIR}/backup/${APP_NAME}-*.jar | tail -n +4 | xargs -r rm -f echo " 已清理旧备份,保留最近 3 个" fi else echo ' 无现有版本,跳过备份' fi " echo -e "${GREEN}[2/6] 备份完成${NC}" # 步骤 3: 停止旧容器 echo -e "${YELLOW}[3/6] 停止旧容器...${NC}" ssh "${SERVER_USER}@${SERVER_HOST}" "podman stop ${APP_NAME} >/dev/null 2>&1 && podman rm ${APP_NAME} >/dev/null 2>&1 || true" sleep 2 echo -e "${GREEN}[3/6] 旧容器已清理${NC}" # 步骤 4: 替换 JAR 并构建镜像 echo -e "${YELLOW}[4/6] 替换 JAR 并构建镜像...${NC}" ssh "${SERVER_USER}@${SERVER_HOST}" " cp ${REMOTE_DIR}/tmp/${JAR_NAME} ${REMOTE_DIR}/${APP_NAME}.jar chmod 644 ${REMOTE_DIR}/${APP_NAME}.jar rm -f ${REMOTE_DIR}/tmp/${JAR_NAME} echo ' 新 JAR:' ls -lh ${REMOTE_DIR}/${APP_NAME}.jar echo ' 构建镜像...' cd ${REMOTE_DIR} && podman build -t ${APP_NAME}:latest . >/dev/null 2>&1 echo ' 镜像构建完成' podman image prune -f >/dev/null 2>&1 echo ' 已清理 dangling 镜像' podman images | grep ${APP_NAME} " echo -e "${GREEN}[4/6] 镜像构建完成${NC}" # 步骤 5: 启动容器 echo -e "${YELLOW}[5/6] 启动容器...${NC}" ssh "${SERVER_USER}@${SERVER_HOST}" " podman run -d \ --name ${APP_NAME} \ --network bridge \ --restart unless-stopped \ -p 8887:8887 \ -v /mnt/iot-platform/logs:/opt/iot-platform/logs \ localhost/${APP_NAME}:latest >/dev/null 2>&1 " sleep 5 echo -e "${GREEN}[5/6] 容器已启动${NC}" # 步骤 6: 健康检查 echo -e "${YELLOW}[6/6] 健康检查...${NC}" if ssh "${SERVER_USER}@${SERVER_HOST}" "bash ${REMOTE_DIR}/bin/health-check.sh localhost 8887 60"; then echo -e "${GREEN}[6/6] 健康检查通过,部署成功!${NC}" echo "" echo "========================================" echo "部署摘要" echo "========================================" echo "时间: ${TIMESTAMP}" echo "JAR: ${LOCAL_JAR}" echo "备份: ${BACKUP_NAME}" echo "状态: 成功" echo "" echo "容器状态:" ssh "${SERVER_USER}@${SERVER_HOST}" "podman ps | grep ${APP_NAME}" echo "" echo "查看日志:" echo " ssh ${SERVER_USER}@${SERVER_HOST} 'podman logs -f ${APP_NAME}'" exit 0 else echo -e "${RED}[6/6] 健康检查失败!${NC}" echo -e "${YELLOW}保留容器用于排查,不自动回滚${NC}" echo "" echo "排查命令:" echo " ssh ${SERVER_USER}@${SERVER_HOST} 'podman logs -f ${APP_NAME}'" echo " ssh ${SERVER_USER}@${SERVER_HOST} 'podman ps | grep ${APP_NAME}'" echo " ssh ${SERVER_USER}@${SERVER_HOST} 'curl -s http://localhost:8887/actuator/health'" exit 1 fi