Files
schoolNews/build.sh

457 lines
13 KiB
Bash
Raw Normal View History

2025-11-24 11:50:15 +08:00
#!/bin/bash
##############################################
# 校园新闻管理系统 - 构建和打包脚本
# 功能:
# 1. 从git拉取最新代码
# 2. 编译后端jar包
# 3. 构建前端dist
2025-11-24 13:36:03 +08:00
# 4. 制作Docker镜像支持基础镜像和应用镜像
2025-11-24 11:50:15 +08:00
# 5. 保存镜像到文件(用于离线部署)
2025-11-24 13:36:03 +08:00
#
# 使用方法:
# ./build.sh [target] [options] [version]
#
# 目标(target)
# base-serv - 构建后端基础镜像包含Python依赖
2025-11-24 14:33:02 +08:00
# base-web - 构建前端基础镜像Node
2025-11-24 13:36:03 +08:00
# base-all - 构建所有基础镜像
# serv - 构建后端服务镜像
2025-11-24 14:33:02 +08:00
# web - 构建前端服务镜像Node + Vite Preview
2025-11-24 13:36:03 +08:00
# mysql - 构建MySQL镜像
# all - 构建所有应用镜像(默认)
#
2025-11-24 14:33:02 +08:00
#
2025-11-24 13:36:03 +08:00
# 选项(options)
2025-11-24 13:50:17 +08:00
# build - 编译代码serv和web需要
# save - 保存镜像到tar文件配合build自动保存构建版本
# save=YYYYMMDD_HHMMSS - 保存指定版本的镜像
2025-11-24 13:36:03 +08:00
#
2025-11-24 13:50:17 +08:00
# 保存规则:
# - build save → 自动保存刚构建的版本(推荐)
# - save=20251124_xxx → 保存指定版本(必须已存在)
# - 只使用save → 报错,必须指定版本
2025-11-24 13:36:03 +08:00
#
# 示例:
2025-11-24 13:50:17 +08:00
# ./build.sh base-all # 构建所有基础镜像
# ./build.sh serv build save # 编译+构建+保存(自动使用构建版本)✅
# ./build.sh all build save # 完整构建流程
# ./build.sh serv save=20251124_143025 # 保存已存在的指定版本
# ./build.sh serv save # ❌ 错误:必须指定版本
2025-11-24 11:50:15 +08:00
##############################################
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"
2025-11-24 14:01:17 +08:00
BUILD_OUTPUT="${PROJECT_ROOT}/build_output"
2025-11-24 11:50:15 +08:00
IMAGE_VERSION=$(date +%Y%m%d_%H%M%S)
2025-11-24 13:36:03 +08:00
# 解析命令行参数
BUILD_TARGET="${1:-all}" # 默认构建所有应用镜像
shift || true
DO_BUILD=false
DO_SAVE=false
SAVE_VERSION="" # 要保存的版本号
# 解析选项
for arg in "$@"; do
case $arg in
build)
DO_BUILD=true
;;
save)
DO_SAVE=true
# 如果不指定版本,使用当前构建的版本
;;
save=*)
DO_SAVE=true
SAVE_VERSION="${arg#save=}"
;;
*)
log_warn "未知选项: $arg"
;;
esac
done
2025-11-24 13:50:17 +08:00
# 确定保存版本
if [ "${DO_SAVE}" = true ]; then
if [ -z "${SAVE_VERSION}" ]; then
if [ "${DO_BUILD}" = true ]; then
# 如果有build参数保存刚构建的版本
SAVE_VERSION="${IMAGE_VERSION}"
else
# 如果没有build参数且未指定版本提示错误
echo ""
log_error "❌ 错误只使用save时必须指定版本"
echo ""
echo "正确用法:"
echo " 1. 保存指定版本: ./build.sh ${BUILD_TARGET} save=20251124_143025"
echo " 2. 构建并保存: ./build.sh ${BUILD_TARGET} build save"
echo ""
echo "查看可用版本:"
echo " docker images | grep school-news"
echo ""
exit 1
fi
fi
2025-11-24 13:36:03 +08:00
fi
2025-11-24 11:50:15 +08:00
echo "=========================================="
echo "校园新闻管理系统 - 构建脚本"
echo "=========================================="
2025-11-24 13:36:03 +08:00
log_info "构建目标: ${BUILD_TARGET}"
2025-11-24 11:50:15 +08:00
log_info "构建版本: ${IMAGE_VERSION}"
2025-11-24 13:36:03 +08:00
log_info "编译代码: ${DO_BUILD}"
log_info "保存镜像: ${DO_SAVE}"
if [ "${DO_SAVE}" = true ]; then
2025-11-24 13:50:17 +08:00
if [ "${DO_BUILD}" = true ]; then
log_info "保存版本: ${SAVE_VERSION} (自动使用构建版本)"
else
log_info "保存版本: ${SAVE_VERSION} (指定版本)"
fi
2025-11-24 13:36:03 +08:00
fi
2025-11-24 11:50:15 +08:00
log_info "项目路径: ${PROJECT_ROOT}"
echo "=========================================="
echo ""
# 创建输出目录
mkdir -p "${BUILD_OUTPUT}"
# ================================================
2025-11-24 13:36:03 +08:00
# 构建函数
2025-11-24 11:50:15 +08:00
# ================================================
2025-11-24 13:36:03 +08:00
# 构建后端基础镜像
build_base_serv() {
log_step "构建后端基础镜像Base Serv"
cd "${PROJECT_ROOT}"
2025-11-26 16:03:06 +08:00
log_info "执行: docker build -t school-news-base-serv:${IMAGE_VERSION} -f docker/schoolNews/Dockerfile.base-serv ."
if docker build -t school-news-base-serv:${IMAGE_VERSION} -f docker/schoolNews/Dockerfile.base-serv .; then
2025-11-24 13:36:03 +08:00
docker tag school-news-base-serv:${IMAGE_VERSION} school-news-base-serv:latest
log_info "✅ 后端基础镜像构建成功"
log_info " 镜像标签: school-news-base-serv:${IMAGE_VERSION}"
log_info " 镜像标签: school-news-base-serv:latest"
else
log_error "❌ 后端基础镜像构建失败"
2025-11-24 11:50:15 +08:00
exit 1
fi
2025-11-24 13:36:03 +08:00
echo ""
}
2025-11-24 11:50:15 +08:00
2025-11-24 13:36:03 +08:00
# 构建MySQL镜像
build_mysql() {
log_step "构建MySQL镜像"
cd "${PROJECT_ROOT}"
2025-11-26 16:03:06 +08:00
log_info "执行: docker build -t school-news-mysql:${IMAGE_VERSION} -f docker/schoolNews/Dockerfile.mysql ."
if docker build -t school-news-mysql:${IMAGE_VERSION} -f docker/schoolNews/Dockerfile.mysql .; then
2025-11-24 13:36:03 +08:00
docker tag school-news-mysql:${IMAGE_VERSION} school-news-mysql:latest
log_info "✅ MySQL镜像构建成功"
log_info " 镜像标签: school-news-mysql:${IMAGE_VERSION}"
log_info " 镜像标签: school-news-mysql:latest"
else
log_error "❌ MySQL镜像构建失败"
exit 1
fi
echo ""
}
2025-11-24 11:50:15 +08:00
2025-11-24 13:36:03 +08:00
# 构建后端服务镜像
build_serv() {
log_step "构建后端服务镜像Serv"
cd "${PROJECT_ROOT}"
# 检查基础镜像
if ! docker images | grep -q "school-news-base-serv.*latest"; then
log_error "基础镜像不存在: school-news-base-serv:latest"
log_error "请先构建基础镜像:./build.sh base-serv"
exit 1
fi
# 检查jar包
if [ ! -f "${SERV_PATH}/admin/target/admin-1.0.0.jar" ]; then
log_error "jar包不存在: ${SERV_PATH}/admin/target/admin-1.0.0.jar"
log_error "请先编译后端项目:./build.sh serv build"
exit 1
fi
2025-11-26 16:03:06 +08:00
log_info "执行: docker build -t school-news-serv:${IMAGE_VERSION} -f docker/schoolNews/Dockerfile.serv ."
if docker build -t school-news-serv:${IMAGE_VERSION} -f docker/schoolNews/Dockerfile.serv .; then
2025-11-24 13:36:03 +08:00
docker tag school-news-serv:${IMAGE_VERSION} school-news-serv:latest
log_info "✅ 后端服务镜像构建成功"
log_info " 镜像标签: school-news-serv:${IMAGE_VERSION}"
log_info " 镜像标签: school-news-serv:latest"
else
log_error "❌ 后端服务镜像构建失败"
exit 1
fi
echo ""
}
2025-11-24 11:50:15 +08:00
2025-11-24 13:36:03 +08:00
# 构建前端服务镜像
build_web() {
log_step "构建前端服务镜像Web"
cd "${PROJECT_ROOT}"
# 检查dist目录
if [ ! -d "${WEB_PATH}/dist" ]; then
log_error "dist目录不存在: ${WEB_PATH}/dist"
log_error "请先构建前端项目:./build.sh web build"
exit 1
fi
2025-11-26 16:03:06 +08:00
log_info "执行: docker build -t school-news-web:${IMAGE_VERSION} -f docker/schoolNews/Dockerfile.web ."
if docker build -t school-news-web:${IMAGE_VERSION} -f docker/schoolNews/Dockerfile.web .; then
2025-11-24 13:36:03 +08:00
docker tag school-news-web:${IMAGE_VERSION} school-news-web:latest
log_info "✅ 前端服务镜像构建成功"
log_info " 镜像标签: school-news-web:${IMAGE_VERSION}"
log_info " 镜像标签: school-news-web:latest"
else
log_error "❌ 前端服务镜像构建失败"
exit 1
fi
echo ""
}
2025-11-24 11:50:15 +08:00
2025-11-24 13:36:03 +08:00
# 编译后端
compile_serv() {
log_step "编译后端jar包"
cd "${SERV_PATH}"
log_info "清理旧的构建..."
mvn clean -q
log_info "开始编译后端项目..."
if mvn package -DskipTests -pl admin -am; then
JAR_FILE="${SERV_PATH}/admin/target/admin-1.0.0.jar"
JAR_SIZE=$(du -h "${JAR_FILE}" | cut -f1)
log_info "✅ 后端编译成功: ${JAR_SIZE}"
else
log_error "❌ 后端编译失败"
exit 1
fi
echo ""
}
2025-11-24 11:50:15 +08:00
2025-11-24 13:36:03 +08:00
# 构建前端
compile_web() {
log_step "构建前端dist"
cd "${WEB_PATH}"
log_info "清理旧的构建..."
rm -rf dist
log_info "开始构建前端项目..."
if npm run build; then
FILE_COUNT=$(find dist -type f | wc -l)
DIST_SIZE=$(du -sh dist | cut -f1)
log_info "✅ 前端构建成功: ${FILE_COUNT}个文件, ${DIST_SIZE}"
else
log_error "❌ 前端构建失败"
exit 1
fi
echo ""
}
2025-11-24 11:50:15 +08:00
2025-11-24 13:36:03 +08:00
# 保存镜像
save_images() {
log_step "保存Docker镜像"
cd "${BUILD_OUTPUT}"
case ${BUILD_TARGET} in
base-serv)
save_image "school-news-base-serv"
;;
mysql)
save_image "school-news-mysql"
;;
serv)
save_image "school-news-serv"
;;
web)
save_image "school-news-web"
;;
all)
save_image "school-news-mysql"
save_image "school-news-serv"
save_image "school-news-web"
;;
esac
}
2025-11-24 11:50:15 +08:00
2025-11-24 13:36:03 +08:00
# 保存单个镜像(使用指定版本或当前构建版本)
save_image() {
local IMAGE_NAME=$1
local VERSION="${SAVE_VERSION}"
local IMAGE_FILE="${IMAGE_NAME}_${VERSION}.tar"
# 检查镜像是否存在
if ! docker images | grep -q "${IMAGE_NAME}.*${VERSION}"; then
log_error "❌ 镜像不存在: ${IMAGE_NAME}:${VERSION}"
log_error " 请先构建该版本的镜像,或使用 docker images 查看可用版本"
exit 1
fi
log_info "保存${IMAGE_NAME}:${VERSION}镜像..."
if docker save -o "${IMAGE_FILE}" ${IMAGE_NAME}:${VERSION}; then
IMAGE_SIZE=$(du -h "${IMAGE_FILE}" | cut -f1)
log_info "✅ 镜像已保存: ${IMAGE_SIZE}"
log_info " 版本: ${IMAGE_NAME}:${VERSION}"
log_info " 文件: ${BUILD_OUTPUT}/${IMAGE_FILE}"
else
log_error "❌ 镜像保存失败: ${IMAGE_NAME}:${VERSION}"
exit 1
fi
echo ""
}
2025-11-24 11:50:15 +08:00
# ================================================
2025-11-26 14:13:17 +08:00
# 主流程控制(函数化)
2025-11-24 11:50:15 +08:00
# ================================================
2025-11-26 14:13:17 +08:00
git_update_if_needed() {
# Git更新可选
if [ "${DO_BUILD}" != true ]; then
return
fi
2025-11-24 13:36:03 +08:00
log_step "Git Pull"
cd "${PROJECT_ROOT}"
2025-11-26 14:13:17 +08:00
2025-11-24 13:36:03 +08:00
if [[ $(git status --porcelain) ]]; then
log_warn "检测到未提交的更改"
read -p "是否继续拉取代码?(y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_warn "跳过git pull"
else
git pull origin main 2>/dev/null || git pull origin master 2>/dev/null || true
fi
else
git pull origin main 2>/dev/null || git pull origin master 2>/dev/null || true
fi
echo ""
2025-11-26 14:13:17 +08:00
}
run_compile() {
# 执行编译
if [ "${DO_BUILD}" != true ]; then
return
fi
2025-11-24 11:50:15 +08:00
2025-11-24 13:36:03 +08:00
case ${BUILD_TARGET} in
2025-11-26 14:13:17 +08:00
serv)
compile_serv
;;
web)
compile_web
;;
all)
2025-11-24 13:36:03 +08:00
compile_serv
compile_web
;;
esac
2025-11-26 14:13:17 +08:00
}
2025-11-24 11:50:15 +08:00
2025-11-26 14:13:17 +08:00
run_build_images() {
# 执行镜像构建
case ${BUILD_TARGET} in
base-serv)
build_base_serv
;;
mysql)
build_mysql
;;
serv)
build_serv
;;
web)
build_web
;;
all)
build_mysql
build_serv
build_web
;;
*)
log_error "未知的构建目标: ${BUILD_TARGET}"
echo ""
echo "可用的构建目标:"
echo " base-serv - 构建后端基础镜像包含Python依赖"
echo " mysql - 构建MySQL镜像"
echo " serv - 构建后端服务镜像"
echo " web - 构建前端服务镜像基于node:20-alpine"
echo " all - 构建所有应用镜像(默认)"
echo ""
echo "注意:"
echo " - Nginx使用官方镜像 nginx:alpine无需构建"
echo " - Web基于官方Node镜像 node:20-alpine无需base-web"
exit 1
;;
esac
}
2025-11-24 11:50:15 +08:00
2025-11-26 14:13:17 +08:00
show_images_info() {
# 查看镜像信息
log_info "Docker镜像列表:"
docker images | grep -E "school-news-" | head -15
echo ""
}
2025-11-24 11:50:15 +08:00
2025-11-26 14:13:17 +08:00
print_summary() {
# 构建完成
echo "=========================================="
log_info "✅ 构建完成!"
echo "=========================================="
log_info "构建目标: ${BUILD_TARGET}"
log_info "构建版本: ${IMAGE_VERSION}"
log_info "输出目录: ${BUILD_OUTPUT}"
echo "=========================================="
}
main() {
git_update_if_needed
run_compile
run_build_images
show_images_info
# 保存镜像(可选)
if [ "${DO_SAVE}" = true ]; then
save_images
fi
print_summary
}
main
2025-11-24 11:50:15 +08:00