#!/bin/bash ############################################## # 校园新闻管理系统 - 构建和打包脚本 # 功能: # 1. 从git拉取最新代码 # 2. 编译后端jar包 # 3. 构建前端dist # 4. 制作Docker镜像 # 5. 保存镜像到文件(用于离线部署) ############################################## set -e # 遇到错误立即退出 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 日志函数 log_info() { echo -e "${GREEN}[INFO]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_step() { echo -e "${BLUE}[STEP]${NC} $1" } # 项目路径 PROJECT_ROOT=$(cd "$(dirname "$0")" && pwd) SERV_PATH="${PROJECT_ROOT}/schoolNewsServ" WEB_PATH="${PROJECT_ROOT}/schoolNewsWeb" DOCKER_PATH="${PROJECT_ROOT}/docker" BUILD_OUTPUT="${PROJECT_ROOT}/build-output" IMAGE_VERSION=$(date +%Y%m%d_%H%M%S) echo "==========================================" echo "校园新闻管理系统 - 构建脚本" echo "==========================================" log_info "构建版本: ${IMAGE_VERSION}" log_info "项目路径: ${PROJECT_ROOT}" echo "==========================================" echo "" # 创建输出目录 mkdir -p "${BUILD_OUTPUT}" # ================================================ # 步骤1: Git Pull # ================================================ log_step "步骤1: 拉取最新代码" cd "${PROJECT_ROOT}" # 检查是否有未提交的更改 if [[ $(git status --porcelain) ]]; then log_warn "检测到未提交的更改" read -p "是否继续拉取代码?(y/n): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_error "已取消构建" exit 1 fi fi log_info "从远程仓库拉取代码..." if git pull origin main 2>/dev/null || git pull origin master 2>/dev/null; then log_info "代码拉取完成" else log_warn "代码拉取失败或已是最新版本,继续构建..." fi echo "" # ================================================ # 步骤2: 构建后端jar包 # ================================================ log_step "步骤2: 构建后端jar包" cd "${SERV_PATH}" log_info "清理旧的构建..." mvn clean -q log_info "开始编译后端项目..." log_info "执行: mvn package -DskipTests -pl admin -am" if mvn package -DskipTests -pl admin -am; then log_info "后端编译成功" else log_error "后端编译失败" exit 1 fi # 验证jar包 JAR_FILE="${SERV_PATH}/admin/target/admin-1.0.0.jar" if [ -f "${JAR_FILE}" ]; then JAR_SIZE=$(du -h "${JAR_FILE}" | cut -f1) log_info "✅ jar包已生成: ${JAR_SIZE}" log_info " 路径: ${JAR_FILE}" else log_error "❌ jar包未找到" exit 1 fi echo "" # ================================================ # 步骤3: 构建前端dist # ================================================ log_step "步骤3: 构建前端项目" cd "${WEB_PATH}" # 检查node_modules if [ ! -d "node_modules" ]; then log_info "安装前端依赖..." npm install fi log_info "清理旧的构建..." rm -rf dist log_info "开始构建前端项目..." log_info "执行: npm run build" if npm run build; then log_info "前端构建成功" else log_error "前端构建失败" exit 1 fi # 验证dist目录 DIST_DIR="${WEB_PATH}/dist" if [ -d "${DIST_DIR}" ]; then DIST_SIZE=$(du -sh "${DIST_DIR}" | cut -f1) FILE_COUNT=$(find "${DIST_DIR}" -type f | wc -l) log_info "✅ dist目录已生成: ${DIST_SIZE} (${FILE_COUNT}个文件)" log_info " 路径: ${DIST_DIR}" else log_error "❌ dist目录未找到" exit 1 fi echo "" # ================================================ # 步骤4: 制作Docker镜像 # ================================================ log_step "步骤4: 制作Docker镜像" cd "${PROJECT_ROOT}" # 构建MySQL镜像 log_info "构建MySQL镜像(包含数据库初始化)..." log_info "执行: docker build -t school-news-mysql:${IMAGE_VERSION} -f docker/Dockerfile.mysql ." if docker build -t school-news-mysql:${IMAGE_VERSION} -f docker/Dockerfile.mysql .; then log_info "✅ MySQL镜像构建成功" docker tag school-news-mysql:${IMAGE_VERSION} school-news-mysql:latest log_info " 镜像标签: school-news-mysql:${IMAGE_VERSION}" log_info " 镜像标签: school-news-mysql:latest" else log_error "❌ MySQL镜像构建失败" exit 1 fi echo "" # 构建后端镜像 log_info "构建后端镜像..." log_info "执行: docker build -t school-news-serv:${IMAGE_VERSION} -f docker/Dockerfile.serv ." if docker build -t school-news-serv:${IMAGE_VERSION} -f docker/Dockerfile.serv .; then log_info "✅ 后端镜像构建成功" # 同时打上latest标签 docker tag school-news-serv:${IMAGE_VERSION} school-news-serv:latest log_info " 镜像标签: school-news-serv:${IMAGE_VERSION}" log_info " 镜像标签: school-news-serv:latest" else log_error "❌ 后端镜像构建失败" exit 1 fi echo "" # 构建前端镜像 log_info "构建前端镜像..." log_info "执行: docker build -t school-news-web:${IMAGE_VERSION} -f docker/Dockerfile.web ." if docker build -t school-news-web:${IMAGE_VERSION} -f docker/Dockerfile.web .; then log_info "✅ 前端镜像构建成功" # 同时打上latest标签 docker tag school-news-web:${IMAGE_VERSION} school-news-web:latest log_info " 镜像标签: school-news-web:${IMAGE_VERSION}" log_info " 镜像标签: school-news-web:latest" else log_error "❌ 前端镜像构建失败" exit 1 fi echo "" # 查看镜像信息 log_info "Docker镜像列表:" docker images | grep -E "school-news-(mysql|serv|web)" | head -10 echo "" # ================================================ # 步骤5: 保存镜像到文件 # ================================================ log_step "步骤5: 保存Docker镜像" cd "${BUILD_OUTPUT}" # 保存MySQL镜像 MYSQL_IMAGE_FILE="school-news-mysql_${IMAGE_VERSION}.tar" log_info "保存MySQL镜像到文件..." log_info "执行: docker save -o ${MYSQL_IMAGE_FILE} school-news-mysql:${IMAGE_VERSION}" if docker save -o "${MYSQL_IMAGE_FILE}" school-news-mysql:${IMAGE_VERSION}; then MYSQL_SIZE=$(du -h "${MYSQL_IMAGE_FILE}" | cut -f1) log_info "✅ MySQL镜像已保存: ${MYSQL_SIZE}" log_info " 文件: ${BUILD_OUTPUT}/${MYSQL_IMAGE_FILE}" else log_error "❌ MySQL镜像保存失败" exit 1 fi echo "" # 保存后端镜像 SERV_IMAGE_FILE="school-news-serv_${IMAGE_VERSION}.tar" log_info "保存后端镜像到文件..." log_info "执行: docker save -o ${SERV_IMAGE_FILE} school-news-serv:${IMAGE_VERSION}" if docker save -o "${SERV_IMAGE_FILE}" school-news-serv:${IMAGE_VERSION}; then SERV_SIZE=$(du -h "${SERV_IMAGE_FILE}" | cut -f1) log_info "✅ 后端镜像已保存: ${SERV_SIZE}" log_info " 文件: ${BUILD_OUTPUT}/${SERV_IMAGE_FILE}" else log_error "❌ 后端镜像保存失败" exit 1 fi echo "" # 保存前端镜像 WEB_IMAGE_FILE="school-news-web_${IMAGE_VERSION}.tar" log_info "保存前端镜像到文件..." log_info "执行: docker save -o ${WEB_IMAGE_FILE} school-news-web:${IMAGE_VERSION}" if docker save -o "${WEB_IMAGE_FILE}" school-news-web:${IMAGE_VERSION}; then WEB_SIZE=$(du -h "${WEB_IMAGE_FILE}" | cut -f1) log_info "✅ 前端镜像已保存: ${WEB_SIZE}" log_info " 文件: ${BUILD_OUTPUT}/${WEB_IMAGE_FILE}" else log_error "❌ 前端镜像保存失败" exit 1 fi echo "" # 压缩镜像文件(可选) log_info "是否压缩镜像文件?(y/n): " read -p "" -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then log_info "压缩镜像文件..." if command -v gzip &> /dev/null; then log_info "使用gzip压缩..." gzip -f "${SERV_IMAGE_FILE}" gzip -f "${WEB_IMAGE_FILE}" SERV_GZ_SIZE=$(du -h "${SERV_IMAGE_FILE}.gz" | cut -f1) WEB_GZ_SIZE=$(du -h "${WEB_IMAGE_FILE}.gz" | cut -f1) log_info "✅ 压缩完成" log_info " 后端: ${SERV_GZ_SIZE} (${SERV_IMAGE_FILE}.gz)" log_info " 前端: ${WEB_GZ_SIZE} (${WEB_IMAGE_FILE}.gz)" else log_warn "gzip未安装,跳过压缩" fi fi echo "" # ================================================ # 生成部署说明文件 # ================================================ log_info "生成部署说明文件..." DEPLOY_INFO_FILE="${BUILD_OUTPUT}/部署说明_${IMAGE_VERSION}.txt" cat > "${DEPLOY_INFO_FILE}" << EOF ======================================== 校园新闻管理系统 - Docker镜像部署说明 ======================================== 构建信息: 构建时间: $(date '+%Y-%m-%d %H:%M:%S') 版本号: ${IMAGE_VERSION} 构建主机: $(hostname) Git分支: $(git branch --show-current 2>/dev/null || echo "未知") Git提交: $(git rev-parse --short HEAD 2>/dev/null || echo "未知") 镜像文件: MySQL镜像: ${MYSQL_IMAGE_FILE}$([ -f "${MYSQL_IMAGE_FILE}.gz" ] && echo ".gz") 后端镜像: ${SERV_IMAGE_FILE}$([ -f "${SERV_IMAGE_FILE}.gz" ] && echo ".gz") 前端镜像: ${WEB_IMAGE_FILE}$([ -f "${WEB_IMAGE_FILE}.gz" ] && echo ".gz") ======================================== 部署步骤: ======================================== 1. 将镜像文件传输到目标服务器 2. 解压镜像文件(如果已压缩): gunzip ${SERV_IMAGE_FILE}.gz gunzip ${WEB_IMAGE_FILE}.gz 3. 加载Docker镜像: docker load -i ${MYSQL_IMAGE_FILE} docker load -i ${SERV_IMAGE_FILE} docker load -i ${WEB_IMAGE_FILE} 4. 验证镜像: docker images | grep school-news 5. 启动服务: cd docker docker-compose up -d 6. 查看服务状态: docker-compose ps docker-compose logs -f ======================================== 访问地址: ======================================== 前端: http://localhost:8080/schoolNewsWeb/ 后端: http://localhost:8081/schoolNewsServ ======================================== 注意事项: ======================================== 1. 确保目标服务器已安装Docker和Docker Compose 2. 确保端口8080、8081、3306、6379未被占用 3. 首次部署需要准备数据库初始化脚本 4. 生产环境请修改默认密码(.env文件) ======================================== EOF log_info "✅ 部署说明已生成: ${DEPLOY_INFO_FILE}" echo "" # ================================================ # 构建摘要 # ================================================ echo "==========================================" echo "构建完成!" echo "==========================================" log_info "构建版本: ${IMAGE_VERSION}" echo "" log_info "Docker镜像:" echo " - school-news-mysql:${IMAGE_VERSION}" echo " - school-news-serv:${IMAGE_VERSION}" echo " - school-news-web:${IMAGE_VERSION}" echo "" log_info "镜像文件保存在: ${BUILD_OUTPUT}/" ls -lh "${BUILD_OUTPUT}/" | grep -E "(tar|gz|txt)" | awk '{print " - "$9" ("$5")"}' echo "" log_info "下一步操作:" echo " 1. 查看部署说明: cat ${DEPLOY_INFO_FILE}" echo " 2. 传输镜像文件到目标服务器" echo " 3. 在目标服务器加载镜像: docker load -i <镜像文件>" echo " 4. 启动服务: cd docker && docker-compose up -d" echo "=========================================="