feat(deploy): add containerized deployment configuration and scripts

- Add Dockerfile for frontend and server services
- Add Docker Compose configs (standard and offline mode)
- Add nginx.conf for admin-web service
- Add deploy scripts: package.sh (packaging) and load-and-start.sh (startup)
- Add deploy/config.yaml, .env.example, and prompts.yml configurations
- Add image management design specification doc
This commit is contained in:
2026-04-15 21:27:15 +08:00
parent 1538a12042
commit 0a3558fc51
11 changed files with 1797 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# load-and-start.sh — 在【离线目标服务器】上运行
# 加载镜像并启动所有服务
#
# 用法(解压部署包后):
# bash deploy.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 读取打包时记录的元数据
if [[ -f "${SCRIPT_DIR}/.package-meta" ]]; then
source "${SCRIPT_DIR}/.package-meta"
fi
IMAGE_TAG="${IMAGE_TAG:-latest}"
LOCAL_PREFIX="${LOCAL_PREFIX:-geo-rankly}"
# ─── 检查 .env ────────────────────────────────────────────────────────────────
if [[ ! -f "${SCRIPT_DIR}/.env" ]]; then
echo "❌ 未找到 .env 文件,请先执行:"
echo " cp .env.example .env && vi .env"
exit 1
fi
# ─── Step 1: 加载镜像 ─────────────────────────────────────────────────────────
echo "==> [1/3] 加载 Docker 镜像(可能需要几分钟)..."
docker load -i "${SCRIPT_DIR}/images.tar"
echo " 镜像加载完成"
docker images | grep -E "geo-rankly|postgres|rabbitmq|redis|qdrant|minio" | head -20
# ─── Step 2: 设置 IMAGE_REGISTRY 为本地前缀 ──────────────────────────────────
echo "==> [2/3] 配置离线镜像引用..."
export IMAGE_REGISTRY="${LOCAL_PREFIX}"
export IMAGE_TAG="${IMAGE_TAG}"
# ─── Step 3: 启动服务 ─────────────────────────────────────────────────────────
echo "==> [3/3] 启动所有服务..."
cd "${SCRIPT_DIR}"
docker compose \
-f docker-compose.yaml \
-f docker-compose.offline.yaml \
--env-file .env \
up -d
echo ""
echo "✅ 部署完成!"
echo ""
echo "服务状态:"
docker compose -f docker-compose.yaml -f docker-compose.offline.yaml ps
echo ""
echo "查看日志: docker compose -f docker-compose.yaml logs -f tenant-api"
echo "停止服务: docker compose -f docker-compose.yaml down"
echo "管理界面:"
echo " RabbitMQ: http://<server-ip>:15672 (geo / geo_dev)"
echo " MinIO: http://<server-ip>:9001 (minioadmin / minioadmin)"
+160
View File
@@ -0,0 +1,160 @@
#!/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-<date>-<arch>.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" <<EOF
IMAGE_TAG=${IMAGE_TAG}
LOCAL_PREFIX=${LOCAL_PREFIX}
PLATFORM=${PLATFORM}
BUILT_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
BUILT_ON=$(uname -m)
EOF
# ─── 压缩 ──────────────────────────────────────────────────────────────────
echo "==> [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"