when: - branch: main event: push steps: # Etape 1 : Ecriture du .env.deploy depuis les secrets # NOTE: ne pas utiliser ${VAR} dans commands (bug Woodpecker next), utiliser env | grep # NOTE: from_secret et volumes incompatibles dans le meme step (bug Woodpecker next) - name: write-env image: alpine:3.20 environment: DTRACK_DOMAIN: from_secret: dtrack_domain commands: - env | grep -E "^(DTRACK_DOMAIN)=" > .env.deploy # COMPOSE_PROJECT_NAME : convention user-project-branch, genere depuis les vars CI - OWNER=$(echo "$CI_REPO_OWNER" | tr 'A-Z' 'a-z') && REPO=$(echo "$CI_REPO_NAME" | tr 'A-Z' 'a-z') && BRANCH=$(echo "$CI_COMMIT_BRANCH" | tr 'A-Z/' 'a-z-') && echo "COMPOSE_PROJECT_NAME=$OWNER-$REPO-$BRANCH" >> .env.deploy - echo "Fichier .env.deploy cree ($(wc -c < .env.deploy) octets)" # TEST write-env : valide le contenu du .env.deploy - name: test-env image: alpine:3.20 commands: - | if [ ! -f .env.deploy ]; then echo "FAIL: .env.deploy introuvable dans le workspace" exit 1 fi echo "PASS: .env.deploy present" - | VAL=$(grep '^COMPOSE_PROJECT_NAME=' .env.deploy | cut -d= -f2) [ -z "$VAL" ] && echo "FAIL: COMPOSE_PROJECT_NAME vide" && exit 1 echo "PASS: COMPOSE_PROJECT_NAME = $VAL" VAL=$(grep '^DTRACK_DOMAIN=' .env.deploy | cut -d= -f2) [ -z "$VAL" ] && echo "FAIL: DTRACK_DOMAIN vide" && exit 1 echo "PASS: DTRACK_DOMAIN = $VAL" # Etape 2 : Deploiement sur sonic via Docker socket # L'agent Woodpecker tourne sur sonic — pas de SSH requis - name: deploy image: docker:27-cli volumes: - /var/run/docker.sock:/var/run/docker.sock - /opt/dtrack:/opt/dtrack commands: - cp .env.deploy /opt/dtrack/.env - chmod 600 /opt/dtrack/.env - cp docker-compose.yml /opt/dtrack/docker-compose.yml - echo "=== config resolue ===" - cd /opt/dtrack && docker compose config - echo "=== pull ===" - cd /opt/dtrack && docker compose pull --no-parallel - echo "=== up ===" - cd /opt/dtrack && docker compose up -d --remove-orphans - cd /opt/dtrack && docker compose ps # TEST deploy : verifie que les conteneurs sont running # NOTE: pas de ${VAR} (substitue par Woodpecker) — utiliser $VAR sans accolades - name: test-deploy image: docker:27-cli volumes: - /var/run/docker.sock:/var/run/docker.sock - /opt/dtrack:/opt/dtrack commands: - | PROJECT=$(grep '^COMPOSE_PROJECT_NAME=' /opt/dtrack/.env | cut -d= -f2) STATUS=$(docker inspect --format '{{.State.Status}}' "$PROJECT-apiserver" 2>/dev/null || echo "absent") echo "$PROJECT-apiserver : $STATUS" [ "$STATUS" = "running" ] || { echo "FAIL: apiserver non running"; exit 1; } echo "PASS: apiserver running" STATUS=$(docker inspect --format '{{.State.Status}}' "$PROJECT-frontend" 2>/dev/null || echo "absent") echo "$PROJECT-frontend : $STATUS" [ "$STATUS" = "running" ] || { echo "FAIL: frontend non running"; exit 1; } echo "PASS: frontend running" # Etape 3 : Healthcheck via Docker — poll le statut interne du conteneur # Pas de requete HTTPS publique : Fabio/TLS ne sont pas encore configures ici - name: healthcheck image: docker:27-cli volumes: - /var/run/docker.sock:/var/run/docker.sock - /opt/dtrack:/opt/dtrack commands: - | PROJECT=$(grep '^COMPOSE_PROJECT_NAME=' /opt/dtrack/.env | cut -d= -f2) echo "Attente healthcheck Docker sur $PROJECT-apiserver (max 5 min)..." MAX=30 i=0 until [ $i -ge $MAX ]; do HEALTH=$(docker inspect --format '{{.State.Health.Status}}' "$PROJECT-apiserver" 2>/dev/null || echo "absent") echo "Tentative $((i+1))/$MAX — $PROJECT-apiserver : $HEALTH" [ "$HEALTH" = "healthy" ] && echo "PASS: apiserver healthy" && exit 0 [ "$HEALTH" = "absent" ] && echo "FAIL: conteneur introuvable" && exit 1 i=$((i+1)) sleep 10 done echo "FAIL: apiserver non healthy apres 5 minutes" exit 1 # Notification en cas d'echec - name: notify-failure image: alpine:3.20 commands: - 'echo "ECHEC pipeline #$CI_BUILD_NUMBER sur commit $CI_COMMIT_SHA"' - 'echo "Branche: $CI_COMMIT_BRANCH"' when: - status: failure