96 lines
4.4 KiB
Bash
Executable File
96 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ═══════════════════════════════════════════════════════
|
|
# deploy.sh — Jool International · déploiement production
|
|
# Usage : ./deploy.sh
|
|
# Prérequis : docker, docker compose, git, accès sudo
|
|
# ═══════════════════════════════════════════════════════
|
|
set -euo pipefail
|
|
|
|
# ── Couleurs pour la lisibilité ────────────────────────
|
|
RESET="\033[0m"
|
|
BOLD="\033[1m"
|
|
GREEN="\033[32m"
|
|
YELLOW="\033[33m"
|
|
RED="\033[31m"
|
|
CYAN="\033[36m"
|
|
|
|
log() { echo -e "${CYAN}[DEPLOY]${RESET} $*"; }
|
|
ok() { echo -e "${GREEN}[OK]${RESET} $*"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; }
|
|
error() { echo -e "${RED}[ERROR]${RESET} $*" >&2; exit 1; }
|
|
title() { echo -e "\n${BOLD}━━━ $* ━━━${RESET}"; }
|
|
|
|
# ── Variables ──────────────────────────────────────────
|
|
COMPOSE_FILE="docker-compose.prod.yml"
|
|
ENV_FILE=".env.prod"
|
|
APP_SERVICE="web"
|
|
BRANCH="${DEPLOY_BRANCH:-main}"
|
|
|
|
# ── Vérifications préalables ───────────────────────────
|
|
title "Vérifications"
|
|
|
|
command -v docker >/dev/null 2>&1 || error "docker non trouvé"
|
|
command -v git >/dev/null 2>&1 || error "git non trouvé"
|
|
[[ -f "$ENV_FILE" ]] || error "Fichier $ENV_FILE introuvable — créer d'abord .env.prod"
|
|
[[ -f "$COMPOSE_FILE" ]] || error "Fichier $COMPOSE_FILE introuvable"
|
|
[[ -f "Caddyfile" ]] || error "Fichier Caddyfile introuvable"
|
|
ok "Docker, git, .env.prod et Caddyfile présents"
|
|
|
|
# ── Pull du code ───────────────────────────────────────
|
|
title "Récupération du code"
|
|
git fetch origin "$BRANCH"
|
|
LOCAL=$(git rev-parse HEAD)
|
|
REMOTE=$(git rev-parse "origin/$BRANCH")
|
|
|
|
if [[ "$LOCAL" == "$REMOTE" ]]; then
|
|
warn "Déjà à jour ($(git rev-parse --short HEAD)) — rebuild quand même"
|
|
else
|
|
log "Mise à jour : $(git rev-parse --short HEAD) → $(git rev-parse --short "origin/$BRANCH")"
|
|
git pull --ff-only origin "$BRANCH"
|
|
fi
|
|
ok "Code à jour : $(git rev-parse --short HEAD)"
|
|
|
|
# ── Build de l'image ───────────────────────────────────
|
|
title "Build Docker"
|
|
docker compose -f "$COMPOSE_FILE" build --no-cache "$APP_SERVICE"
|
|
ok "Image $APP_SERVICE construite"
|
|
|
|
# ── Vérification de la config Caddy ────────────────────
|
|
title "Validation Caddyfile"
|
|
docker run --rm -v "$(pwd)/Caddyfile:/etc/caddy/Caddyfile:ro" \
|
|
caddy:2-alpine caddy validate --config /etc/caddy/Caddyfile \
|
|
&& ok "Caddyfile valide" \
|
|
|| error "Caddyfile invalide — déploiement annulé"
|
|
|
|
# ── Déploiement sans interruption ─────────────────────
|
|
title "Déploiement"
|
|
docker compose -f "$COMPOSE_FILE" up -d --remove-orphans
|
|
ok "Conteneurs démarrés"
|
|
|
|
# ── Attente de la santé du service web ─────────────────
|
|
title "Healthcheck"
|
|
MAX_WAIT=60
|
|
ELAPSED=0
|
|
log "En attente que '$APP_SERVICE' soit healthy (max ${MAX_WAIT}s)…"
|
|
until docker compose -f "$COMPOSE_FILE" ps "$APP_SERVICE" | grep -q "healthy"; do
|
|
if [[ $ELAPSED -ge $MAX_WAIT ]]; then
|
|
warn "Healthcheck timeout — vérifier : docker compose logs $APP_SERVICE"
|
|
break
|
|
fi
|
|
sleep 3
|
|
ELAPSED=$((ELAPSED + 3))
|
|
done
|
|
ok "$APP_SERVICE opérationnel (${ELAPSED}s)"
|
|
|
|
# ── Nettoyage des images orphelines ────────────────────
|
|
title "Nettoyage"
|
|
docker image prune -f --filter "until=24h" >/dev/null 2>&1 || true
|
|
ok "Images inutilisées supprimées"
|
|
|
|
# ── Résumé ─────────────────────────────────────────────
|
|
title "Déploiement terminé"
|
|
echo -e " Commit : ${BOLD}$(git rev-parse --short HEAD)${RESET}"
|
|
echo -e " Site : ${BOLD}https://jool-international.com/${RESET}"
|
|
echo -e " Logs : docker compose logs -f"
|
|
echo -e " Rollback : git checkout <commit-précédent> && ./deploy.sh"
|