admin/scripts/deploy-on-vps.sh
alisaza bd8bc31ee0 fix: optimize Docker image management during deployment
Enhance the deployment scripts for Finland and Iran by refining Docker image pruning and transfer processes. Implement conditional transfer compression using zstd or gzip based on availability, and ensure only unused admin tags are removed without affecting build cache. This improves efficiency and reduces unnecessary image deletions during deployments.
2026-09-13 18:47:38 +03:30

105 lines
3.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Build and run admin on the VPS (idempotent).
# Expects app sources in APP_DIR (CI rsync) and a filled APP_DIR/.env.
set -euo pipefail
APP_DIR="${APP_DIR:-/opt/ghabilee-admin}"
SRC_DIR="${SRC_DIR:-$APP_DIR/src}"
IMAGE_TAG="${IMAGE_TAG:-ghabilee-admin:local}"
cd "$APP_DIR"
if [ ! -f "$APP_DIR/.env" ]; then
echo "Missing $APP_DIR/.env — copy from .env.example and fill production values." >&2
exit 2
fi
if [ ! -f "$SRC_DIR/Dockerfile" ]; then
echo "Missing $SRC_DIR/Dockerfile — rsync the repo before deploy." >&2
exit 2
fi
install -m 0644 "$SRC_DIR/deploy/docker-compose.production.yml" "$APP_DIR/docker-compose.yml"
if [ -f "$SRC_DIR/deploy/nginx/backoffice.conf" ]; then
install -m 0644 "$SRC_DIR/deploy/nginx/backoffice.conf" /etc/nginx/sites-available/backoffice
ln -sfn /etc/nginx/sites-available/backoffice /etc/nginx/sites-enabled/backoffice
nginx -t
systemctl reload nginx
fi
# shellcheck disable=SC1091
set -a
# shellcheck disable=SC1090
source "$APP_DIR/.env"
set +a
env_or_empty() {
local key="$1"
printf '%s' "${!key-}"
}
sanitize_api_proxy_target() {
local target
target="$(env_or_empty API_PROXY_TARGET)"
case "$target" in
*127.0.0.1*|*localhost*|*'::1'*)
echo "Warning: refusing loopback API_PROXY_TARGET for production image build" >&2
printf ''
;;
*)
printf '%s' "$target"
;;
esac
}
BUILD_ARGS=(
--build-arg "NEXT_PUBLIC_API_URL=$(env_or_empty NEXT_PUBLIC_API_URL)"
--build-arg "NEXT_PUBLIC_FILE_SERVER_URL=$(env_or_empty NEXT_PUBLIC_FILE_SERVER_URL)"
--build-arg "MAP_API_KEY=$(env_or_empty MAP_API_KEY)"
--build-arg "NEXT_PUBLIC_MAP_API_KEY=$(env_or_empty NEXT_PUBLIC_MAP_API_KEY)"
--build-arg "NEXT_PUBLIC_VAPID_PUBLIC_KEY=$(env_or_empty NEXT_PUBLIC_VAPID_PUBLIC_KEY)"
--build-arg "NEXT_PUBLIC_BASE_PATH=$(env_or_empty NEXT_PUBLIC_BASE_PATH)"
--build-arg "NEXT_PUBLIC_SITE_URL=$(env_or_empty NEXT_PUBLIC_SITE_URL)"
--build-arg "NEXT_PUBLIC_OBSERVABILITY_ENDPOINT=$(env_or_empty NEXT_PUBLIC_OBSERVABILITY_ENDPOINT)"
--build-arg "NEXT_PUBLIC_SENTRY_DSN=$(env_or_empty NEXT_PUBLIC_SENTRY_DSN)"
--build-arg "NEXT_PUBLIC_SENTRY_ENVIRONMENT=$(env_or_empty NEXT_PUBLIC_SENTRY_ENVIRONMENT)"
--build-arg "NEXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE=$(env_or_empty NEXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATE)"
--build-arg "NEXT_PUBLIC_ARCAPTCHA_SITE_KEY=$(env_or_empty NEXT_PUBLIC_ARCAPTCHA_SITE_KEY)"
--build-arg "SENTRY_AUTH_TOKEN=$(env_or_empty SENTRY_AUTH_TOKEN)"
--build-arg "SENTRY_ORG=$(env_or_empty SENTRY_ORG)"
--build-arg "SENTRY_PROJECT=$(env_or_empty SENTRY_PROJECT)"
--build-arg "API_PROXY_TARGET=$(sanitize_api_proxy_target)"
)
echo "Building ${IMAGE_TAG} on VPS (build arguments redacted)"
docker build \
--platform linux/amd64 \
-t "$IMAGE_TAG" \
"${BUILD_ARGS[@]}" \
"$SRC_DIR"
ADMIN_IMAGE="$IMAGE_TAG" docker compose -f "$APP_DIR/docker-compose.yml" up -d --no-deps ghabilee-admin
for attempt in $(seq 1 36); do
health="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' ghabilee-admin 2>/dev/null || echo missing)"
echo "Admin health ${attempt}/36: ${health}"
if [ "$health" = "healthy" ]; then
# فقط tagهای قدیمی admin؛ prune -af کش/لایه‌های قابل‌استفاده مجدد را پاک می‌کند
docker images --format '{{.Repository}}:{{.Tag}}' \
| awk -v keep="$IMAGE_TAG" '$0 ~ /^ghabilee-admin:/ && $0 != keep { print }' \
| while IFS= read -r old; do
docker rmi "$old" >/dev/null 2>&1 || true
done
docker image prune -f >/dev/null 2>&1 || true
echo "Deploy OK"
exit 0
fi
case "$health" in
unhealthy|exited|dead|missing) exit 1 ;;
esac
sleep 5
done
echo "Timed out waiting for healthy admin container" >&2
exit 1