82a379e536
Deploy to Production / deploy (push) Failing after 47s
Internal maintainer dashboard: global stats, sandbox list with
tier-filter and pagination, sandbox drill-down with D3 world map,
tier-promotion form. API-key auth via HttpOnly cookie. Port 8084,
rolling a/b deploy alongside the existing service pairs.
- apix-common: AdminSandboxSummary, AdminSandboxListResponse, AdminStatsResponse DTOs
- apix-registry: AdminResource (4 endpoints), SandboxService.listAllSandboxes + getGlobalStats
- apix-registry: SandboxResource GET /{uuid}/dashboard endpoint (was missing — fixes portal 500)
- apix-portal: RegistryClient path corrected to /dashboard
- apix-admin: new Quarkus module — auth filter, registry REST client, 3 resources, 6 Qute templates, admin.js
- infra: Dockerfile.admin, docker-compose admin-a/b services, Caddyfile admin.api-index.org block
- scripts: deploy-bluegreen.sh extended for admin-a/b
Co-Authored-By: Mira Rehfeld <noreply@anthropic.com>
93 lines
3.9 KiB
Bash
93 lines
3.9 KiB
Bash
#!/bin/bash
|
|
# Rolling zero-downtime deploy for APIX.
|
|
# Triggered by Gitea Actions (act_runner, host process) on push to main.
|
|
# Requires: Docker on the runner host. Maven runs inside a container.
|
|
#
|
|
# Strategy: a/b container pairs per service. Caddy health-routes between them.
|
|
# Deploy restarts a-stack then b-stack sequentially — one instance always healthy.
|
|
|
|
set -euo pipefail
|
|
|
|
INFRA_DIR="/opt/apix/infra"
|
|
ENV_FILE="/opt/apix/.env"
|
|
COMPOSE="docker compose -f $INFRA_DIR/docker-compose.yml --env-file $ENV_FILE"
|
|
|
|
log() { echo "[deploy $(date -u +%H:%M:%S)] $*"; }
|
|
|
|
wait_healthy() {
|
|
local service=$1
|
|
local container="infra-${service}-1"
|
|
local max=90
|
|
local elapsed=0
|
|
log "Waiting for $service to become healthy..."
|
|
while [ $elapsed -lt $max ]; do
|
|
status=$(docker inspect "$container" \
|
|
--format '{{.State.Health.Status}}' 2>/dev/null || echo "missing")
|
|
if [ "$status" = "healthy" ]; then
|
|
log "$service is healthy."
|
|
return 0
|
|
fi
|
|
sleep 5
|
|
elapsed=$((elapsed + 5))
|
|
done
|
|
log "ERROR: $service did not become healthy after ${max}s (last status: $status)"
|
|
docker logs "$container" --tail 20 2>&1 || true
|
|
return 1
|
|
}
|
|
|
|
# ── 1. Sync infra config to /opt/apix/infra ──────────────────────────────────
|
|
log "Syncing infra config..."
|
|
cp infra/Caddyfile "$INFRA_DIR/Caddyfile"
|
|
cp infra/docker-compose.yml "$INFRA_DIR/docker-compose.yml"
|
|
cp infra/Dockerfile.* "$INFRA_DIR/"
|
|
[ -f infra/prometheus.yml ] && cp infra/prometheus.yml "$INFRA_DIR/"
|
|
|
|
# ── 2. Build JARs (Maven runs in Docker — no JDK/Maven required on host) ──────
|
|
log "Building JARs..."
|
|
# GITHUB_WORKSPACE is set by act_runner; work dir is mounted at the same host path.
|
|
BUILD_ROOT="${GITHUB_WORKSPACE:-$(pwd)}"
|
|
docker run --rm \
|
|
-v "${BUILD_ROOT}:/workspace" \
|
|
-v "/home/deploy/gitea-runner/.m2:/root/.m2" \
|
|
-w /workspace \
|
|
maven:3.9-eclipse-temurin-21 \
|
|
mvn clean package -DskipTests -q
|
|
|
|
# ── 3. Build Docker images ────────────────────────────────────────────────────
|
|
log "Building Docker images..."
|
|
docker build -f infra/Dockerfile.registry -t apix-registry:latest . -q
|
|
docker build -f infra/Dockerfile.portal -t apix-portal:latest . -q
|
|
docker build -f infra/Dockerfile.demo -t apix-demo:latest . -q
|
|
docker build -f infra/Dockerfile.spider -t apix-spider:latest . -q
|
|
docker build -f infra/Dockerfile.admin -t apix-admin:latest . -q
|
|
|
|
# ── 4. Rolling restart: a-stack (registry-a → portal-a + demo-a) ─────────────
|
|
log "Rolling restart: a-stack..."
|
|
$COMPOSE up -d --no-deps --force-recreate registry-a
|
|
wait_healthy "registry-a"
|
|
|
|
$COMPOSE up -d --no-deps --force-recreate portal-a demo-a admin-a
|
|
wait_healthy "portal-a"
|
|
wait_healthy "demo-a"
|
|
wait_healthy "admin-a"
|
|
|
|
# ── 5. Rolling restart: b-stack ───────────────────────────────────────────────
|
|
log "Rolling restart: b-stack..."
|
|
$COMPOSE up -d --no-deps --force-recreate registry-b
|
|
wait_healthy "registry-b"
|
|
|
|
$COMPOSE up -d --no-deps --force-recreate portal-b demo-b admin-b
|
|
wait_healthy "portal-b"
|
|
wait_healthy "demo-b"
|
|
wait_healthy "admin-b"
|
|
|
|
# ── 6. Spider (cron job — restart acceptable) ─────────────────────────────────
|
|
log "Restarting spider..."
|
|
$COMPOSE up -d --no-deps --force-recreate spider
|
|
|
|
# ── 7. Reload Caddy ───────────────────────────────────────────────────────────
|
|
log "Reloading Caddy..."
|
|
docker exec infra-caddy-1 caddy reload --config /etc/caddy/Caddyfile
|
|
|
|
log "Deploy complete. All services updated with zero downtime."
|