367 lines
11 KiB
Bash
367 lines
11 KiB
Bash
#!/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 "==========================================" |