XuqmGroup-PrivateDeploy/scripts/export-offline-bundle.sh
徐勤民 9eabe0d699 feat: implement complete private deployment scripts (P1-P4)
- upgrade.sh/rollback.sh: backup→pull→rolling restart→healthcheck→auto-rollback
- backup.sh/restore.sh: mysqldump+redis BGSAVE+config tar, SHA256 manifest, restore with checksum verification
- healthcheck.sh: Docker/container/MySQL/Redis/HTTP/disk checks, JSON output to .deploy-state/
- doctor.sh: sanitized diagnostics archive, vendor API TCP connectivity, cert expiry
- export-offline-bundle.sh: docker pull+save for all profile images, load-images.sh, SHA256
- configure.sh: interactive/non-interactive mode, MySQL/Redis mode selection, domain prompts
- enable-service.sh: domain validation, docker pull + compose up, healthcheck
- disable-service.sh: compose stop+rm, profile removal, render-config
- renew-cert.sh: acme.sh/certbot, --dry-run, backup old cert, nginx reload on success
- alert-webhook.sh: WeCom/DingTalk/Feishu webhook, message sanitization
- bench.sh: ab/wrk/curl benchmark, JSON report with docker stats
- rotate-secrets.sh: JWT and internal token rotation
- vendor credential templates: push.env and store-submit.env with full credential comments
- render-config.sh: auto-sync SDK URL env vars (SDK_FILE_SERVICE_URL, SDK_IM_API_URL, SDK_IM_WS_URL)
- All scripts pass bash -n syntax check

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 20:49:25 +08:00

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 ops-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")"