77 lines
2.5 KiB
Bash
Executable File
77 lines
2.5 KiB
Bash
Executable File
#!/bin/bash
|
||
# Gravl deployment script
|
||
# Prevents stale containers by always building fresh with --no-cache
|
||
#
|
||
# Usage:
|
||
# ./scripts/deploy.sh
|
||
#
|
||
# What it does:
|
||
# 1. Pulls latest code from git
|
||
# 2. Captures build metadata (commit SHA, timestamp)
|
||
# 3. Builds fresh Docker images with --no-cache (no layer caching)
|
||
# 4. Restarts containers to use new images
|
||
# 5. Polls /api/health endpoint until backend is ready
|
||
# 6. Logs all steps to logs/deploy.log
|
||
#
|
||
# Rationale for --no-cache:
|
||
# Docker caching can hide stale assets (JS, CSS, images) when source files change.
|
||
# Using --no-cache ensures all layers rebuild fresh, guaranteeing new code is deployed.
|
||
# Trade-off: Slightly slower builds (30-60s vs 10-20s with cache), but safer.
|
||
#
|
||
# See: /docs/DEPLOYMENT.md for troubleshooting
|
||
|
||
set -euo pipefail
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
REPO_DIR="$(dirname "$SCRIPT_DIR")"
|
||
LOG_FILE="$REPO_DIR/logs/deploy.log"
|
||
BACKEND_HEALTH="http://localhost:3001/api/health"
|
||
|
||
log() {
|
||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
|
||
}
|
||
|
||
mkdir -p "$REPO_DIR/logs"
|
||
cd "$REPO_DIR"
|
||
|
||
log "=== Deploy started ==="
|
||
|
||
# Pull latest code from remote
|
||
# Fails if there are local changes or merge conflicts
|
||
log "Pulling latest code..."
|
||
git pull
|
||
|
||
# Capture build metadata to embed in Docker image labels
|
||
# These labels allow build-check.sh to verify deployed containers match local code
|
||
GIT_COMMIT=$(git rev-parse HEAD)
|
||
BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||
log "Commit: $(git rev-parse --short HEAD) | Date: $BUILD_DATE"
|
||
|
||
# Build fresh images — no-cache prevents Docker layer caching
|
||
# This is critical for frontend deployments where CSS/JS changes might not be obvious
|
||
# to Docker's layer detection algorithm
|
||
log "Building images (--no-cache)..."
|
||
export GIT_COMMIT BUILD_DATE
|
||
docker compose build --no-cache
|
||
|
||
# Restart containers with new images
|
||
# --force-recreate stops old containers and removes them before starting new ones
|
||
log "Starting containers..."
|
||
docker compose up -d --force-recreate
|
||
|
||
# Health check: poll /api/health endpoint until it responds with 200 OK
|
||
# Timeout: 60 seconds (12 retries × 5 seconds each)
|
||
# This prevents deployment from completing if the backend is broken
|
||
log "Health check..."
|
||
for i in $(seq 1 12); do
|
||
if curl -sf "$BACKEND_HEALTH" >/dev/null 2>&1; then
|
||
log "Backend healthy"
|
||
break
|
||
fi
|
||
[ "$i" -eq 12 ] && { log "ERROR: Health check failed after 60s"; exit 1; }
|
||
log "Waiting... ($i/12)"
|
||
sleep 5
|
||
done
|
||
|
||
log "=== Deploy complete: ${GIT_COMMIT:0:7} ==="
|