diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 008d428..6abfbef 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -62,11 +62,35 @@ jobs: # DEPLOY # ========================= deploy: - name: Deploy via Portainer + name: Deploy Blue/Green needs: build runs-on: ubuntu-latest steps: - - name: Trigger Portainer webhook - run: | - curl -X POST "${{ secrets.PORTAINER_WEBHOOK_URL }}" + - name: Deploy via SSH (Blue/Green) + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.SSH_HOST }} + username: ${{ secrets.SSH_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + script: | + set -e + + echo "📦 Pull latest image" + docker pull gitea.leonmorival.com/daily_meal/bemeal-api:latest + + echo "🟢 Start GREEN container" + docker compose up -d bemeal-api-green + + echo "⏳ Wait for healthcheck" + sleep 10 + + curl -f http://localhost/api/health || exit 1 + + echo "🔁 Switch traffic (MANUAL STEP OR NPM API)" + sed -i 's/blue/green/g' /etc/nginx/conf.d/bemeal.conf + nginx -s reload + + echo "🧹 Stop BLUE container" + docker stop bemeal-api-blue || true + docker rm bemeal-api-blue || true diff --git a/compose.yaml b/compose.yaml index abc97d0..ff30759 100644 --- a/compose.yaml +++ b/compose.yaml @@ -67,7 +67,7 @@ services: meilisearch: image: 'getmeili/meilisearch:latest' ports: - - '${FORWARD_MEILISEARCH_PORT:-7700}:7700' + - '${FORWARD_MEILISEARCH_PORT:-7600}:7700' environment: MEILI_NO_ANALYTICS: '${MEILISEARCH_NO_ANALYTICS:-false}' volumes: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index be130b0..dca22f9 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -1,45 +1,101 @@ services: - bemeal-api: - image: gitea.leonmorival.com/daily_meal/bemeal-api:latest - container_name: bemeal-api - restart: unless-stopped - depends_on: - pgsql: - condition: service_healthy - redis: - condition: service_started - meilisearch: - condition: service_started - # ports: <--- Supprimé pour la sécurité, NPM s'en occupe - # - "8002:80" - environment: - APP_LOCALE: "fr" - APP_ENV: "production" - APP_KEY: "${APP_KEY}" - APP_URL: "${APP_URL}" - SERVER_NAME: ":80" - APP_RUNTIME: "Laravel\\FrankenPHP\\Runtime" # <-- AJOUTÉ pour FrankenPHP - APP_DEBUG: "${APP_DEBUG}" - FILESYSTEM_DISK: "public" - DB_CONNECTION: "pgsql" - DB_HOST: "pgsql" - DB_PORT: 5432 - DB_DATABASE: "${DB_DATABASE:?DB_DATABASE is required}" - DB_USERNAME: "${DB_USERNAME:?DB_USERNAME is required}" - DB_PASSWORD: "${DB_PASSWORD:?DB_PASSWORD is required}" - GEMINI_API_KEY: "${GEMINI_API_KEY:?GEMINI_API_KEY is required}" - REDIS_HOST: "redis" - REDIS_CLIENT: "predis" - QUEUE_CONNECTION: "redis" - SCOUT_DRIVER: "meilisearch" - MEILISEARCH_HOST: "http://meilisearch:7700" - MEILISEARCH_KEY: "${MEILISEARCH_KEY}" - volumes: - - storage-data:/var/www/html/storage/app - - storage-public-data:/var/www/html/storage/app/public - networks: - - nginx - - internal +bemeal-api-blue: + image: gitea.leonmorival.com/daily_meal/bemeal-api:latest + container_name: bemeal-api-blue + restart: unless-stopped + + depends_on: + pgsql: + condition: service_healthy + redis: + condition: service_started + meilisearch: + condition: service_started + + environment: + APP_LOCALE: "fr" + APP_ENV: "production" + APP_KEY: "${APP_KEY}" + APP_URL: "${APP_URL}" + SERVER_NAME: ":80" + APP_RUNTIME: "Laravel\\FrankenPHP\\Runtime" + APP_DEBUG: "${APP_DEBUG}" + + FILESYSTEM_DISK: "public" + + DB_CONNECTION: "pgsql" + DB_HOST: "pgsql" + DB_PORT: 5432 + DB_DATABASE: "${DB_DATABASE:?DB_DATABASE is required}" + DB_USERNAME: "${DB_USERNAME:?DB_USERNAME is required}" + DB_PASSWORD: "${DB_PASSWORD:?DB_PASSWORD is required}" + + GEMINI_API_KEY: "${GEMINI_API_KEY:?GEMINI_API_KEY is required}" + + REDIS_HOST: "redis" + REDIS_CLIENT: "predis" + QUEUE_CONNECTION: "redis" + + SCOUT_DRIVER: "meilisearch" + MEILISEARCH_HOST: "http://meilisearch:7700" + MEILISEARCH_KEY: "${MEILISEARCH_KEY}" + + volumes: + - storage-data:/var/www/html/storage/app + - storage-public-data:/var/www/html/storage/app/public + + networks: + - nginx + - internal + +bemeal-api-green: + image: gitea.leonmorival.com/daily_meal/bemeal-api:latest + container_name: bemeal-api-green + restart: unless-stopped + + depends_on: + pgsql: + condition: service_healthy + redis: + condition: service_started + meilisearch: + condition: service_started + + environment: + APP_LOCALE: "fr" + APP_ENV: "production" + APP_KEY: "${APP_KEY}" + APP_URL: "${APP_URL}" + SERVER_NAME: ":80" + APP_RUNTIME: "Laravel\\FrankenPHP\\Runtime" + APP_DEBUG: "${APP_DEBUG}" + + FILESYSTEM_DISK: "public" + + DB_CONNECTION: "pgsql" + DB_HOST: "pgsql" + DB_PORT: 5432 + DB_DATABASE: "${DB_DATABASE:?DB_DATABASE is required}" + DB_USERNAME: "${DB_USERNAME:?DB_USERNAME is required}" + DB_PASSWORD: "${DB_PASSWORD:?DB_PASSWORD is required}" + + GEMINI_API_KEY: "${GEMINI_API_KEY:?GEMINI_API_KEY is required}" + + REDIS_HOST: "redis" + REDIS_CLIENT: "predis" + QUEUE_CONNECTION: "redis" + + SCOUT_DRIVER: "meilisearch" + MEILISEARCH_HOST: "http://meilisearch:7700" + MEILISEARCH_KEY: "${MEILISEARCH_KEY}" + + volumes: + - storage-data:/var/www/html/storage/app + - storage-public-data:/var/www/html/storage/app/public + + networks: + - nginx + - internal pgsql: image: postgres:15-alpine diff --git a/routes/api.php b/routes/api.php index 37e6787..ac0cee8 100644 --- a/routes/api.php +++ b/routes/api.php @@ -19,7 +19,9 @@ Route::prefix('auth')->group(function (): void { }); }); - +Route::get('/health', function () { + return response()->json(['status' => 'ok']); +}); Route::middleware('auth:sanctum')->group(function (): void { Route::post('device-tokens', [DeviceTokenController::class, 'store']); Route::delete('device-tokens', [DeviceTokenController::class, 'destroy']);