#!/bin/bash ############################################## # Urban Lifeline - 构建和打包脚本 # # 功能: # 1. 编译后端/前端项目 # 2. 构建 Docker 镜像 # 3. 导出镜像到 tar 文件 # # 使用方法: # ./build.sh [target] [options] # # 目标(target): # base - 构建基础镜像 # serv - 构建所有后端服务镜像 # web - 构建前端镜像 # all - 构建所有镜像(默认) # gateway - 构建单个后端服务 # system/auth/file/ai/workcase - 同上 # # 选项(options): # compile - 先编译代码再构建镜像 # save - 构建后导出镜像到 tar 文件 # save=VERSION - 导出指定版本的镜像 # # 示例: # ./build.sh all compile save # 编译+构建+导出所有 # ./build.sh gateway compile # 编译+构建 gateway # ./build.sh serv save # 构建+导出所有后端 # ./build.sh web compile save # 编译+构建+导出前端 ############################################## set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' 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"; } # 项目路径 SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) PROJECT_ROOT=$(cd "${SCRIPT_DIR}/.." && pwd) DOCKER_DIR="${SCRIPT_DIR}" BUILD_OUTPUT="${DOCKER_DIR}/output" IMAGE_VERSION=$(date +%Y%m%d_%H%M%S) # 服务列表 SERV_SERVICES="gateway system auth file ai workcase" # 服务端口映射 declare -A SERVICE_PORTS=( ["gateway"]=8080 ["system"]=8082 ["auth"]=8081 ["file"]=8084 ["ai"]=8090 ["workcase"]=8088 ) # 解析参数 BUILD_TARGET="${1:-all}" shift || true DO_COMPILE=false DO_SAVE=false SAVE_VERSION="" for arg in "$@"; do case $arg in compile) DO_COMPILE=true ;; save) DO_SAVE=true ;; save=*) DO_SAVE=true SAVE_VERSION="${arg#save=}" ;; esac done # 确定保存版本 if [ "${DO_SAVE}" = true ] && [ -z "${SAVE_VERSION}" ]; then SAVE_VERSION="${IMAGE_VERSION}" fi echo "==========================================" echo "Urban Lifeline - 构建脚本" echo "==========================================" log_info "构建目标: ${BUILD_TARGET}" log_info "构建版本: ${IMAGE_VERSION}" log_info "编译代码: ${DO_COMPILE}" log_info "保存镜像: ${DO_SAVE}" [ "${DO_SAVE}" = true ] && log_info "保存版本: ${SAVE_VERSION}" echo "==========================================" echo "" mkdir -p "${BUILD_OUTPUT}" # ================================================ # 编译函数 # ================================================ compile_serv_all() { log_step "编译所有后端服务" cd "${PROJECT_ROOT}/urbanLifelineServ" mvn clean package -DskipTests log_info "✅ 后端服务编译完成" } compile_serv_single() { local service=$1 log_step "编译 ${service} 服务" cd "${PROJECT_ROOT}/urbanLifelineServ" mvn clean package -DskipTests -pl ${service} -am log_info "✅ ${service} 服务编译完成" } compile_web() { log_step "编译前端项目" cd "${PROJECT_ROOT}/urbanLifelineWeb" # 检查 pnpm if command -v pnpm &> /dev/null; then pnpm install pnpm run build:all 2>/dev/null || { # 如果没有 build:all 脚本,分别构建 log_info "分别构建各前端项目..." cd packages/shared && pnpm run build && cd ../.. cd packages/platform && pnpm run build && cd ../.. cd packages/workcase && pnpm run build && cd ../.. } else npm install npm run build:all 2>/dev/null || { cd packages/shared && npm run build && cd ../.. cd packages/platform && npm run build && cd ../.. cd packages/workcase && npm run build && cd ../.. } fi log_info "✅ 前端项目编译完成" } # ================================================ # 构建函数 # ================================================ build_base() { log_step "构建基础镜像" cd "${PROJECT_ROOT}" docker build \ -t urban-lifeline-base-serv:${IMAGE_VERSION} \ -t urban-lifeline-base-serv:latest \ -f docker/urbanLifeline/serv/Dockerfile.base . log_info "✅ 基础镜像构建完成: urban-lifeline-base-serv:${IMAGE_VERSION}" } build_serv_single() { local service=$1 local port=${SERVICE_PORTS[$service]} log_step "构建 ${service} 服务镜像" # 检查 JAR 包 local jar_file=$(find "${PROJECT_ROOT}/urbanLifelineServ/${service}/target" -name "*.jar" -type f 2>/dev/null | head -1) if [ -z "$jar_file" ]; then log_error "JAR 包不存在,请先编译: ./build.sh ${service} compile" exit 1 fi cd "${PROJECT_ROOT}" docker build \ --build-arg SERVICE_NAME=${service} \ --build-arg SERVICE_PORT=${port} \ -t urban-lifeline-${service}:${IMAGE_VERSION} \ -t urban-lifeline-${service}:latest \ -f docker/urbanLifeline/serv/Dockerfile.template . log_info "✅ ${service} 镜像构建完成: urban-lifeline-${service}:${IMAGE_VERSION}" } build_serv_all() { for service in ${SERV_SERVICES}; do build_serv_single ${service} done log_info "✅ 所有后端服务镜像构建完成" } build_web() { build_platform build_workcase_web log_info "✅ 所有前端镜像构建完成" } build_platform() { log_step "构建 platform 镜像" if [ ! -d "${PROJECT_ROOT}/urbanLifelineWeb/packages/platform/dist" ]; then log_error "platform dist 不存在,请先编译: ./build.sh platform compile" exit 1 fi cd "${PROJECT_ROOT}" docker build \ --build-arg WEB_NAME=platform \ -t urban-lifeline-platform:${IMAGE_VERSION} \ -t urban-lifeline-platform:latest \ -f docker/urbanLifeline/web/Dockerfile . log_info "✅ platform 镜像构建完成: urban-lifeline-platform:${IMAGE_VERSION}" } build_workcase_web() { log_step "构建 workcase-web 镜像" if [ ! -d "${PROJECT_ROOT}/urbanLifelineWeb/packages/workcase/dist" ]; then log_error "workcase dist 不存在,请先编译: ./build.sh workcase-web compile" exit 1 fi cd "${PROJECT_ROOT}" docker build \ --build-arg WEB_NAME=workcase \ -t urban-lifeline-workcase-web:${IMAGE_VERSION} \ -t urban-lifeline-workcase-web:latest \ -f docker/urbanLifeline/web/Dockerfile . log_info "✅ workcase-web 镜像构建完成: urban-lifeline-workcase-web:${IMAGE_VERSION}" } # ================================================ # 导出函数 # ================================================ save_image() { local image_name=$1 local version=${SAVE_VERSION} local output_file="${BUILD_OUTPUT}/${image_name}_${version}.tar" log_info "导出镜像: ${image_name}:${version}" if ! docker images | grep -q "${image_name}.*${version}"; then log_error "镜像不存在: ${image_name}:${version}" return 1 fi docker save -o "${output_file}" ${image_name}:${version} local size=$(du -h "${output_file}" | cut -f1) log_info "✅ 镜像已导出: ${output_file} (${size})" } save_serv_all() { for service in ${SERV_SERVICES}; do save_image "urban-lifeline-${service}" done } # ================================================ # 主流程 # ================================================ main() { # 编译 if [ "${DO_COMPILE}" = true ]; then case ${BUILD_TARGET} in base) # 基础镜像不需要编译 ;; serv) compile_serv_all ;; web) compile_web ;; all) compile_serv_all compile_web ;; gateway|system|auth|file|ai|workcase) compile_serv_single ${BUILD_TARGET} ;; *) log_error "未知目标: ${BUILD_TARGET}" exit 1 ;; esac fi # 构建镜像 case ${BUILD_TARGET} in base) build_base ;; serv) build_serv_all ;; web) build_web ;; platform) build_platform ;; workcase-web) build_workcase_web ;; all) # 检查基础镜像 if ! docker images | grep -q "urban-lifeline-base-serv.*latest"; then log_warn "基础镜像不存在,先构建基础镜像" build_base fi build_serv_all build_web ;; gateway|system|auth|file|ai|workcase) build_serv_single ${BUILD_TARGET} ;; *) log_error "未知目标: ${BUILD_TARGET}" echo "" echo "可用目标: base, serv, web, all, gateway, system, auth, file, ai, workcase, platform, workcase-web" exit 1 ;; esac # 导出镜像 if [ "${DO_SAVE}" = true ]; then case ${BUILD_TARGET} in base) save_image "urban-lifeline-base-serv" ;; serv) save_serv_all ;; web) save_image "urban-lifeline-platform" save_image "urban-lifeline-workcase-web" ;; platform) save_image "urban-lifeline-platform" ;; workcase-web) save_image "urban-lifeline-workcase-web" ;; all) save_image "urban-lifeline-base-serv" save_serv_all save_image "urban-lifeline-platform" save_image "urban-lifeline-workcase-web" ;; gateway|system|auth|file|ai|workcase) save_image "urban-lifeline-${BUILD_TARGET}" ;; esac echo "" log_info "导出文件列表:" ls -lh "${BUILD_OUTPUT}"/*.tar 2>/dev/null || true fi # 显示镜像列表 echo "" log_info "Docker 镜像列表:" docker images | grep "urban-lifeline" | head -20 echo "" echo "==========================================" log_info "✅ 构建完成!" echo "==========================================" } main