#!/usr/bin/env bash # package.sh — 在【有网络的开发机】上运行 # 构建所有镜像(支持跨平台),打包成可离线部署的压缩包 # # 用法: # bash package.sh [IMAGE_TAG] [PLATFORM] # # 示例: # bash package.sh latest linux/amd64 # M1/M2 Mac 打包给 x86 服务器(默认) # bash package.sh v1.0.0 linux/arm64 # 打包给 ARM 服务器(如树莓派、飞腾) # bash package.sh latest linux/amd64,linux/arm64 # 暂不支持(save 不支持 multi-arch) # # 产物: # geo-rankly-deploy--.tar.gz set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" DEPLOY_DIR="${REPO_ROOT}/deploy" IMAGE_TAG="${1:-latest}" PLATFORM="${2:-linux/amd64}" LOCAL_PREFIX="geo-rankly" DATE_TAG="$(date +%Y%m%d)" # 将 linux/amd64 → amd64,用于包名 ARCH_LABEL="${PLATFORM##*/}" PACKAGE_NAME="geo-rankly-deploy-${DATE_TAG}-${ARCH_LABEL}" WORK_DIR="/tmp/${PACKAGE_NAME}" echo "==> 目标平台: ${PLATFORM} | 镜像 tag: ${IMAGE_TAG}" echo "" # ─── 确保 buildx builder 支持目标平台 ──────────────────────────────────────── echo "==> [0/5] 检查 buildx builder" BUILDER_NAME="geo-cross-builder" if ! docker buildx inspect "${BUILDER_NAME}" &>/dev/null; then echo " 创建多平台 builder: ${BUILDER_NAME}" docker buildx create \ --name "${BUILDER_NAME}" \ --driver docker-container \ --driver-opt image=moby/buildkit:latest \ --use else docker buildx use "${BUILDER_NAME}" echo " 使用已有 builder: ${BUILDER_NAME}" fi # 确保 builder 已启动(首次使用时需要) docker buildx inspect --bootstrap "${BUILDER_NAME}" > /dev/null # ─── 构建自定义镜像 ──────────────────────────────────────────────────────────── echo "==> [1/5] 构建自定义镜像 (platform: ${PLATFORM}, tag: ${IMAGE_TAG})" cd "${REPO_ROOT}" # 注意:--load 仅支持单平台;交叉编译时 buildx 使用 QEMU 或 Go 交叉编译 _build() { local target="$1" tag_suffix="$2" shift 2 echo " building ${LOCAL_PREFIX}/${tag_suffix}:${IMAGE_TAG}" docker buildx build \ --platform "${PLATFORM}" \ --target "${target}" \ "$@" \ --tag "${LOCAL_PREFIX}/${tag_suffix}:${IMAGE_TAG}" \ --load \ -f server/Dockerfile \ server/ } _build runtime tenant-api --build-arg SERVICE=tenant-api _build runtime worker-generate --build-arg SERVICE=worker-generate _build runtime scheduler --build-arg SERVICE=scheduler _build migrate migrate # migrate stage 不需要 SERVICE arg echo " building ${LOCAL_PREFIX}/frontend:${IMAGE_TAG}" docker buildx build \ --platform "${PLATFORM}" \ --tag "${LOCAL_PREFIX}/frontend:${IMAGE_TAG}" \ --load \ -f Dockerfile.frontend \ . # ─── 拉取基础设施镜像(指定平台) ───────────────────────────────────────────── echo "==> [2/5] 拉取基础设施镜像 (platform: ${PLATFORM})" INFRA_IMAGES=( "postgres:16-alpine" "rabbitmq:3.13-management-alpine" "redis:7-alpine" "qdrant/qdrant:v1.13.2" "minio/minio:RELEASE.2025-03-12T18-04-18Z" "minio/mc:latest" ) for img in "${INFRA_IMAGES[@]}"; do echo " pulling ${img}" # --platform 确保拉取目标架构,覆盖本机可能已缓存的 arm64 版本 docker pull --platform "${PLATFORM}" "${img}" done # ─── 保存所有镜像 ─────────────────────────────────────────────────────────── echo "==> [3/5] 保存所有镜像到 images.tar" mkdir -p "${WORK_DIR}" ALL_IMAGES=( "${LOCAL_PREFIX}/tenant-api:${IMAGE_TAG}" "${LOCAL_PREFIX}/worker-generate:${IMAGE_TAG}" "${LOCAL_PREFIX}/scheduler:${IMAGE_TAG}" "${LOCAL_PREFIX}/migrate:${IMAGE_TAG}" "${LOCAL_PREFIX}/frontend:${IMAGE_TAG}" "postgres:16-alpine" "rabbitmq:3.13-management-alpine" "redis:7-alpine" "qdrant/qdrant:v1.13.2" "minio/minio:RELEASE.2025-03-12T18-04-18Z" "minio/mc:latest" ) docker save "${ALL_IMAGES[@]}" -o "${WORK_DIR}/images.tar" # 验证镜像架构 echo " 验证镜像架构:" for img in "${LOCAL_PREFIX}/tenant-api:${IMAGE_TAG}" "postgres:16-alpine"; do arch="$(docker inspect --format '{{.Architecture}}' "${img}" 2>/dev/null || echo unknown)" echo " ${img} → ${arch}" done echo " 镜像包大小: $(du -sh "${WORK_DIR}/images.tar" | cut -f1)" # ─── 打包部署文件 ─────────────────────────────────────────────────────────── echo "==> [4/5] 打包部署文件" cp "${DEPLOY_DIR}/docker-compose.yaml" "${WORK_DIR}/" cp "${DEPLOY_DIR}/docker-compose.offline.yaml" "${WORK_DIR}/" cp "${DEPLOY_DIR}/config.yaml" "${WORK_DIR}/" cp "${DEPLOY_DIR}/prompts.yml" "${WORK_DIR}/" cp "${DEPLOY_DIR}/.env.example" "${WORK_DIR}/" cp "${DEPLOY_DIR}/scripts/load-and-start.sh" "${WORK_DIR}/deploy.sh" chmod +x "${WORK_DIR}/deploy.sh" # 写入元数据,供 load 脚本读取 cat > "${WORK_DIR}/.package-meta" < [5/5] 压缩打包" cd /tmp tar -czf "${REPO_ROOT}/${PACKAGE_NAME}.tar.gz" "${PACKAGE_NAME}/" rm -rf "${WORK_DIR}" echo "" echo "✅ 打包完成: ${REPO_ROOT}/${PACKAGE_NAME}.tar.gz" echo " 平台: ${PLATFORM} | 大小: $(du -sh "${REPO_ROOT}/${PACKAGE_NAME}.tar.gz" | cut -f1)" echo "" echo "传输到目标服务器后执行:" echo " tar xzf ${PACKAGE_NAME}.tar.gz" echo " cd ${PACKAGE_NAME}" echo " cp .env.example .env && vi .env" echo " bash deploy.sh"