#!/usr/bin/env bash # 构建 Docker 镜像脚本 # 用法: ./build-docker.sh [amd64|arm64] # 如果不指定架构,将使用本机架构 set -euo pipefail # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color echo -e "${GREEN}=== 开始构建 PeiPei 后端 Docker 镜像 ===${NC}" # 检测本机架构 NATIVE_ARCH=$(uname -m) if [[ "$NATIVE_ARCH" == "x86_64" ]]; then NATIVE_ARCH="amd64" elif [[ "$NATIVE_ARCH" == "arm64" ]] || [[ "$NATIVE_ARCH" == "aarch64" ]]; then NATIVE_ARCH="arm64" fi # 处理命令行参数(兼容未提供参数时的 set -u) ARG1="${1-}" if [[ "$ARG1" == "-h" || "$ARG1" == "--help" ]]; then echo -e "${GREEN}PeiPei 后端 Docker 镜像构建脚本${NC}" echo "" echo -e "${YELLOW}用法:${NC}" echo " ./build-docker.sh [选项] [架构]" echo "" echo -e "${YELLOW}选项:${NC}" echo " -h, --help 显示此帮助信息" echo "" echo -e "${YELLOW}架构:${NC}" echo " amd64 构建 Linux amd64 镜像 (适用于服务器)" echo " arm64 构建 Linux arm64 镜像 (适用于 Apple Silicon Mac)" echo " [空] 自动检测本机架构" echo "" echo -e "${YELLOW}示例:${NC}" echo " ./build-docker.sh # 自动检测架构构建" echo " ./build-docker.sh amd64 # 构建服务器镜像" echo " ./build-docker.sh arm64 # 构建 Mac 镜像" echo " ./build-docker.sh -h # 显示帮助" echo "" echo -e "${YELLOW}说明:${NC}" echo " - 本机架构: ${NATIVE_ARCH}" echo " - 使用 Docker Buildx 进行构建" echo " - 镜像将带有架构后缀标签 (如: latest-amd64)" echo " - 构建缓存存储在: .buildx-cache/" echo " - 确保 Dockerfile 使用: FROM --platform=\$TARGETPLATFORM" exit 0 fi TARGET_ARCH="${ARG1:-$NATIVE_ARCH}" # 验证架构参数 if [[ "$TARGET_ARCH" != "amd64" && "$TARGET_ARCH" != "arm64" ]]; then echo -e "${RED}错误: 不支持的架构 '$TARGET_ARCH'${NC}" echo -e "${YELLOW}支持的架构: amd64, arm64${NC}" echo -e "${YELLOW}用法: ./build-docker.sh [amd64|arm64]${NC}" exit 1 fi echo -e "${YELLOW}目标架构: ${TARGET_ARCH}${NC}" echo -e "${YELLOW}本机架构: ${NATIVE_ARCH}${NC}" # 检查是否在正确的目录 if [ ! -f "docker/Dockerfile" ]; then echo -e "${RED}错误: 请在项目根目录执行此脚本${NC}" echo -e "${YELLOW}当前目录: $(pwd)${NC}" echo -e "${YELLOW}期望目录应包含: docker/Dockerfile${NC}" exit 1 fi # 获取 UTC+8 时间戳 TIMESTAMP=$(TZ='Asia/Shanghai' date +"%Y-%m-%d-%Hh-%Mm") echo -e "${YELLOW}构建时间戳 (UTC+8): ${TIMESTAMP}${NC}" # 镜像名称和标签 IMAGE_NAME="peipei-backend" VERSION_TAG="${TIMESTAMP}-${TARGET_ARCH}" LATEST_TAG="latest-${TARGET_ARCH}" echo -e "${YELLOW}镜像名称: ${IMAGE_NAME}${NC}" echo -e "${YELLOW}版本标签: ${VERSION_TAG}${NC}" # 构建 Docker 镜像 echo -e "${GREEN}开始构建镜像...${NC}" # 确保 buildx 可用 if ! docker buildx version >/dev/null 2>&1; then echo -e "${RED}错误: 需要 Docker Buildx 支持${NC}" exit 1 fi # 创建并使用 builder(如果不存在) if ! docker buildx inspect peipei-builder >/dev/null 2>&1; then echo -e "${YELLOW}创建 buildx builder...${NC}" docker buildx create --name peipei-builder --use else docker buildx use peipei-builder fi # 启动 builder 和 QEMU(用于跨架构支持) echo -e "${YELLOW}初始化 buildx builder...${NC}" docker buildx inspect --bootstrap >/dev/null # 显示构建类型 if [[ "$TARGET_ARCH" != "$NATIVE_ARCH" ]]; then echo -e "${YELLOW}跨平台构建: ${NATIVE_ARCH} -> ${TARGET_ARCH}${NC}" else echo -e "${YELLOW}本机架构构建: ${TARGET_ARCH}${NC}" fi # 创建缓存目录(可选优化) CACHE_DIR=".buildx-cache" mkdir -p "$CACHE_DIR" # 始终使用 buildx 以保持行为一致 echo -e "${GREEN}执行构建...${NC}" if docker buildx build \ --platform "linux/${TARGET_ARCH}" \ --load \ --cache-from="type=local,src=${CACHE_DIR}" \ --cache-to="type=local,dest=${CACHE_DIR}" \ -f docker/Dockerfile \ -t "${IMAGE_NAME}:${VERSION_TAG}" \ -t "${IMAGE_NAME}:${LATEST_TAG}" \ .; then BUILD_SUCCESS=true else BUILD_SUCCESS=false fi # 检查构建结果 if [[ "$BUILD_SUCCESS" == "true" ]]; then echo -e "${GREEN}✅ Docker 镜像构建成功!${NC}" echo -e "${GREEN}镜像标签:${NC}" echo -e " - ${IMAGE_NAME}:${VERSION_TAG}" echo -e " - ${IMAGE_NAME}:${LATEST_TAG}" echo -e "\n${YELLOW}镜像信息:${NC}" docker images | grep -E "^${IMAGE_NAME}\s" echo -e "\n${GREEN}使用说明:${NC}" if [[ "$TARGET_ARCH" == "amd64" ]]; then echo -e " - 该镜像适用于 Linux amd64 服务器部署" echo -e " - 推送到服务器: ./push-docker.sh" elif [[ "$TARGET_ARCH" == "arm64" ]]; then echo -e " - 该镜像适用于 Apple Silicon Mac 本地运行" echo -e " - 本地测试: docker run ${IMAGE_NAME}:${LATEST_TAG}" fi echo -e "\n${YELLOW}构建其他架构:${NC}" echo -e " - 构建 amd64 (服务器): ./build-docker.sh amd64" echo -e " - 构建 arm64 (Mac): ./build-docker.sh arm64" echo -e " - 自动检测架构: ./build-docker.sh" else echo -e "${RED}❌ Docker 镜像构建失败!${NC}" exit 1 fi