核心变更: - 完全移除 ops-web 容器(私有化部署无需运营后台) - nginx sub_filter 替换前端 JS bundle 中的公网 SDK URL - deploy.sh 写入正确的 SDK_IM_WS_URL / SDK_IM_API_URL / SDK_FILE_SERVICE_URL - 新增 scripts/update.sh:热更新脚本,修复配置 + 可选拉镜像 + 重启 + 验证 - 新增 upgrade.sh:一键升级入口,curl 下载后直接执行,流程同 install.sh - install.sh 检测已有部署(.env 存在),自动路由到 update.sh 而非重跑向导 - 关键配置文件(.env / secrets.env / xuqm.env)在 tarball 解压前备份后恢复 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
94 行
3.2 KiB
Bash
可执行文件
94 行
3.2 KiB
Bash
可执行文件
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
. "$ROOT_DIR/scripts/lib.sh"
|
|
load_env
|
|
|
|
OUT_DIR="${1:-$ROOT_DIR/dist}"
|
|
mkdir -p "$OUT_DIR"
|
|
|
|
BUNDLE_NAME="xuqm-private-$(cat "$ROOT_DIR/VERSION" | tr -d '[:space:]')-offline"
|
|
BUNDLE_DIR="$OUT_DIR/$BUNDLE_NAME"
|
|
BUNDLE_ARCHIVE="$OUT_DIR/${BUNDLE_NAME}.tar.gz"
|
|
|
|
audit "export-offline-bundle" "STARTED" "$OUT_DIR"
|
|
progress "export-offline-bundle" "STARTED" "$OUT_DIR"
|
|
|
|
mkdir -p "$BUNDLE_DIR"
|
|
|
|
# Copy deploy repo (exclude data, dist, git, secrets)
|
|
tar --exclude='data' --exclude='dist' --exclude='.git' \
|
|
--exclude='config/secrets.env' --exclude='logs/audit.log' \
|
|
-czf "$BUNDLE_DIR/deploy-repo.tar.gz" -C "$ROOT_DIR" .
|
|
|
|
# Pull and save Docker images
|
|
IMAGES_DIR="$BUNDLE_DIR/images"
|
|
mkdir -p "$IMAGES_DIR"
|
|
|
|
REGISTRY="${REGISTRY:-registry.example.com/xuqm}"
|
|
TAG="${IMAGE_TAG:-$(cat "$ROOT_DIR/VERSION" | tr -d '[:space:]')}"
|
|
PROFILES="${COMPOSE_PROFILES:-base}"
|
|
|
|
pull_and_save() {
|
|
local svc="$1"
|
|
local image="${REGISTRY}/${svc}:${TAG}"
|
|
local out_file="$IMAGES_DIR/${svc}.tar"
|
|
printf 'Pulling %s ...\n' "$image"
|
|
if docker pull "$image" 2>/dev/null; then
|
|
docker save "$image" -o "$out_file"
|
|
printf 'Saved %s → %s\n' "$image" "$out_file"
|
|
else
|
|
printf 'WARNING: could not pull %s (skip in offline bundle)\n' "$image"
|
|
fi
|
|
}
|
|
|
|
# Always include base images
|
|
for svc in tenant-service file-service tenant-web docs-site; do
|
|
pull_and_save "$svc"
|
|
done
|
|
|
|
# Optional services
|
|
profile_contains() { case ",${PROFILES}," in *","$1","*) return 0;; esac; return 1; }
|
|
profile_contains "im" && pull_and_save "im-service"
|
|
profile_contains "push" && pull_and_save "push-service"
|
|
profile_contains "update" && pull_and_save "update-service"
|
|
profile_contains "license" && pull_and_save "license-service"
|
|
|
|
# Infrastructure images (always include for managed mode)
|
|
docker pull nginx:1.27-alpine 2>/dev/null && docker save nginx:1.27-alpine -o "$IMAGES_DIR/nginx.tar" || true
|
|
docker pull mysql:8.4 2>/dev/null && docker save mysql:8.4 -o "$IMAGES_DIR/mysql.tar" || true
|
|
docker pull redis:7.4-alpine 2>/dev/null && docker save redis:7.4-alpine -o "$IMAGES_DIR/redis.tar" || true
|
|
|
|
# Generate image load script for offline use
|
|
cat > "$BUNDLE_DIR/load-images.sh" <<'SCRIPT'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
for img in "$SCRIPT_DIR/images/"*.tar; do
|
|
[ -f "$img" ] || continue
|
|
printf 'Loading %s...\n' "$img"
|
|
docker load -i "$img"
|
|
done
|
|
printf 'All images loaded.\n'
|
|
SCRIPT
|
|
chmod +x "$BUNDLE_DIR/load-images.sh"
|
|
|
|
# Copy manifest
|
|
cp "$ROOT_DIR/image-manifest.json" "$BUNDLE_DIR/" 2>/dev/null || true
|
|
|
|
# Checksums for all files in bundle
|
|
(cd "$OUT_DIR" && find "$BUNDLE_NAME" -type f -exec sha256sum {} \; > "$BUNDLE_DIR/sha256sums.txt")
|
|
|
|
# Package
|
|
tar -czf "$BUNDLE_ARCHIVE" -C "$OUT_DIR" "$BUNDLE_NAME"
|
|
rm -rf "$BUNDLE_DIR"
|
|
|
|
# Checksum of the final archive
|
|
sha256sum "$BUNDLE_ARCHIVE" > "${BUNDLE_ARCHIVE}.sha256"
|
|
|
|
audit "export-offline-bundle" "DONE" "archive=$BUNDLE_ARCHIVE"
|
|
progress "export-offline-bundle" "DONE" "archive=$BUNDLE_ARCHIVE"
|
|
printf 'Offline bundle: %s\n' "$BUNDLE_ARCHIVE"
|
|
printf 'SHA256: %s\n' "$(cat "${BUNDLE_ARCHIVE}.sha256")"
|