staging deploy
All checks were successful
Build & Deploy KLZ Cables / build-and-deploy (push) Successful in 3m54s

This commit is contained in:
2026-01-31 18:07:28 +01:00
parent 9c54322654
commit c89bd8e80f
2 changed files with 69 additions and 41 deletions

View File

@@ -2,7 +2,7 @@ name: Build & Deploy KLZ Cables
on: on:
push: push:
branches: [main] branches: [main, staging]
jobs: jobs:
build-and-deploy: build-and-deploy:
@@ -15,6 +15,7 @@ jobs:
- name: 📋 Log Workflow Start - name: 📋 Log Workflow Start
run: | run: |
echo "🚀 Starting deployment for ${{ github.repository }} (${{ github.ref }})" echo "🚀 Starting deployment for ${{ github.repository }} (${{ github.ref }})"
echo " • Branch: ${{ github.ref_name }}"
echo " • Commit: ${{ github.sha }}" echo " • Commit: ${{ github.sha }}"
echo " • Timestamp: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" echo " • Timestamp: $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
@@ -33,23 +34,48 @@ jobs:
# LOGGING: Build Phase # LOGGING: Build Phase
# ═══════════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════════
- name: 🏗️ Build Docker image - name: 🏗️ Build Docker image
env:
NEXT_PUBLIC_BASE_URL: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_BASE_URL || (secrets.STAGING_NEXT_PUBLIC_BASE_URL || secrets.NEXT_PUBLIC_BASE_URL) }}
NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID || (secrets.STAGING_NEXT_PUBLIC_UMAMI_WEBSITE_ID || secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID) }}
NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL || (secrets.STAGING_NEXT_PUBLIC_UMAMI_SCRIPT_URL || secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL) }}
run: | run: |
echo "🏗️ Building Docker image (linux/arm64)..." echo "🏗️ Building Docker image (linux/arm64) for branch ${{ github.ref_name }}..."
docker buildx build \ docker buildx build \
--pull \ --pull \
--platform linux/arm64 \ --platform linux/arm64 \
--build-arg NEXT_PUBLIC_BASE_URL="${{ secrets.NEXT_PUBLIC_BASE_URL }}" \ --build-arg NEXT_PUBLIC_BASE_URL="$NEXT_PUBLIC_BASE_URL" \
--build-arg NEXT_PUBLIC_UMAMI_WEBSITE_ID="${{ secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID }}" \ --build-arg NEXT_PUBLIC_UMAMI_WEBSITE_ID="$NEXT_PUBLIC_UMAMI_WEBSITE_ID" \
--build-arg NEXT_PUBLIC_UMAMI_SCRIPT_URL="${{ secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL }}" \ --build-arg NEXT_PUBLIC_UMAMI_SCRIPT_URL="$NEXT_PUBLIC_UMAMI_SCRIPT_URL" \
-t registry.infra.mintel.me/mintel/klz-cables.com:${{ github.sha }} \
-t registry.infra.mintel.me/mintel/klz-cables.com:latest \ -t registry.infra.mintel.me/mintel/klz-cables.com:latest \
--push . --push .
# ═══════════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════════
# LOGGING: Deployment Phase # LOGGING: Deployment Phase
# ═══════════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════════
- name: 🚀 Deploy to production server - name: 🚀 Deploy to server
env:
NEXT_PUBLIC_BASE_URL: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_BASE_URL || (secrets.STAGING_NEXT_PUBLIC_BASE_URL || secrets.NEXT_PUBLIC_BASE_URL) }}
NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID || (secrets.STAGING_NEXT_PUBLIC_UMAMI_WEBSITE_ID || secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID) }}
NEXT_PUBLIC_UMAMI_SCRIPT_URL: ${{ github.ref_name == 'main' && secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL || (secrets.STAGING_NEXT_PUBLIC_UMAMI_SCRIPT_URL || secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL) }}
SENTRY_DSN: ${{ github.ref_name == 'main' && secrets.SENTRY_DSN || (secrets.STAGING_SENTRY_DSN || secrets.SENTRY_DSN) }}
MAIL_HOST: ${{ github.ref_name == 'main' && secrets.MAIL_HOST || (secrets.STAGING_MAIL_HOST || secrets.MAIL_HOST) }}
MAIL_PORT: ${{ github.ref_name == 'main' && secrets.MAIL_PORT || (secrets.STAGING_MAIL_PORT || secrets.MAIL_PORT) }}
MAIL_USERNAME: ${{ github.ref_name == 'main' && secrets.MAIL_USERNAME || (secrets.STAGING_MAIL_USERNAME || secrets.MAIL_USERNAME) }}
MAIL_PASSWORD: ${{ github.ref_name == 'main' && secrets.MAIL_PASSWORD || (secrets.STAGING_MAIL_PASSWORD || secrets.MAIL_PASSWORD) }}
MAIL_FROM: ${{ github.ref_name == 'main' && secrets.MAIL_FROM || (secrets.STAGING_MAIL_FROM || secrets.MAIL_FROM) }}
MAIL_RECIPIENTS: ${{ github.ref_name == 'main' && secrets.MAIL_RECIPIENTS || (secrets.STAGING_MAIL_RECIPIENTS || secrets.MAIL_RECIPIENTS) }}
run: | run: |
echo "🚀 Deploying to alpha.mintel.me..." BRANCH=${{ github.ref_name }}
if [ "$BRANCH" = "main" ]; then
ENV_FILE=.env.prod
TRAEFIK_HOST="klz-cables.com, www.klz-cables.com"
else
ENV_FILE=.env.staging
TRAEFIK_HOST="staging.klz-cables.com"
fi
echo "🚀 Deploying branch $BRANCH to $ENV_FILE..."
# Setup SSH # Setup SSH
mkdir -p ~/.ssh mkdir -p ~/.ssh
@@ -60,60 +86,61 @@ jobs:
# Create .env file content # Create .env file content
cat > /tmp/klz-cables.env << EOF cat > /tmp/klz-cables.env << EOF
# ============================================================================ # ============================================================================
# KLZ Cables - Production Environment Configuration # KLZ Cables - Environment Configuration ($BRANCH)
# ============================================================================ # ============================================================================
# Auto-generated by CI/CD workflow # Auto-generated by CI/CD workflow
# DO NOT EDIT MANUALLY - Changes will be overwritten on next deployment # DO NOT EDIT MANUALLY - Changes will be overwritten on next deployment
# ============================================================================ # ============================================================================
# Application
NODE_ENV=production NODE_ENV=production
NEXT_PUBLIC_BASE_URL=${{ secrets.NEXT_PUBLIC_BASE_URL }} NEXT_PUBLIC_BASE_URL=$NEXT_PUBLIC_BASE_URL
NEXT_PUBLIC_UMAMI_WEBSITE_ID=$NEXT_PUBLIC_UMAMI_WEBSITE_ID
# Analytics (Umami) NEXT_PUBLIC_UMAMI_SCRIPT_URL=$NEXT_PUBLIC_UMAMI_SCRIPT_URL
NEXT_PUBLIC_UMAMI_WEBSITE_ID=${{ secrets.NEXT_PUBLIC_UMAMI_WEBSITE_ID }} SENTRY_DSN=$SENTRY_DSN
NEXT_PUBLIC_UMAMI_SCRIPT_URL=${{ secrets.NEXT_PUBLIC_UMAMI_SCRIPT_URL }} MAIL_HOST=$MAIL_HOST
MAIL_PORT=$MAIL_PORT
# Error Tracking (GlitchTip/Sentry) MAIL_USERNAME=$MAIL_USERNAME
SENTRY_DSN=${{ secrets.SENTRY_DSN }} MAIL_PASSWORD=$MAIL_PASSWORD
MAIL_FROM=$MAIL_FROM
# Email Configuration (Mailgun) MAIL_RECIPIENTS=$MAIL_RECIPIENTS
MAIL_HOST=${{ secrets.MAIL_HOST }}
MAIL_PORT=${{ secrets.MAIL_PORT }}
MAIL_USERNAME=${{ secrets.MAIL_USERNAME }}
MAIL_PASSWORD=${{ secrets.MAIL_PASSWORD }}
MAIL_FROM=${{ secrets.MAIL_FROM }}
MAIL_RECIPIENTS=${{ secrets.MAIL_RECIPIENTS }}
# Deployment variables for docker-compose
IMAGE_TAG=${{ github.sha }}
TRAEFIK_HOST=$TRAEFIK_HOST
ENV_FILE=$ENV_FILE
EOF EOF
# Upload .env and deploy # Upload .env and docker-compose.yml
scp -o StrictHostKeyChecking=accept-new /tmp/klz-cables.env root@alpha.mintel.me:/home/deploy/sites/klz-cables.com/.env scp -o StrictHostKeyChecking=accept-new /tmp/klz-cables.env root@alpha.mintel.me:/home/deploy/sites/klz-cables.com/$ENV_FILE
scp -o StrictHostKeyChecking=accept-new docker-compose.yml root@alpha.mintel.me:/home/deploy/sites/klz-cables.com/docker-compose.yml
ssh -o StrictHostKeyChecking=accept-new root@alpha.mintel.me bash << EOF ssh -o StrictHostKeyChecking=accept-new root@alpha.mintel.me bash << EOF
set -e set -e
cd /home/deploy/sites/klz-cables.com cd /home/deploy/sites/klz-cables.com
chmod 600 .env chmod 600 $ENV_FILE
chown deploy:deploy .env chown deploy:deploy $ENV_FILE
echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin
docker pull registry.infra.mintel.me/mintel/klz-cables.com:latest
docker-compose down echo "📥 Pulling images..."
IMAGE_TAG=${{ github.sha }} ENV_FILE=$ENV_FILE TRAEFIK_HOST="$TRAEFIK_HOST" docker compose --env-file $ENV_FILE pull
echo "🚀 Starting containers..." echo "🚀 Starting containers..."
docker-compose up -d IMAGE_TAG=${{ github.sha }} ENV_FILE=$ENV_FILE TRAEFIK_HOST="$TRAEFIK_HOST" docker compose --env-file $ENV_FILE up -d
echo "🧹 Cleaning up old images..."
docker system prune -f
echo "⏳ Giving the app a few seconds to warm up..." echo "⏳ Giving the app a few seconds to warm up..."
sleep 10 sleep 10
echo "🔍 Checking container status..." echo "🔍 Checking container status..."
docker-compose ps docker compose --env-file $ENV_FILE ps
if ! docker-compose ps | grep -q "Up"; then if ! docker compose --env-file $ENV_FILE ps | grep -q "Up"; then
echo "❌ Container failed to start" echo "❌ Container failed to start"
docker-compose logs --tail=100 docker compose --env-file $ENV_FILE logs --tail=100
exit 1 exit 1
fi fi
@@ -130,6 +157,7 @@ jobs:
run: | run: |
echo "📊 Status: ${{ job.status }}" echo "📊 Status: ${{ job.status }}"
echo "🎯 Target: alpha.mintel.me" echo "🎯 Target: alpha.mintel.me"
echo "🌿 Branch: ${{ github.ref_name }}"
# ═══════════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════════
# NOTIFICATION: Gotify # NOTIFICATION: Gotify
@@ -140,7 +168,7 @@ jobs:
echo "Sending success notification to Gotify..." echo "Sending success notification to Gotify..."
RESPONSE=$(curl -k -s -w "\n%{http_code}" -X POST "${{ secrets.GOTIFY_URL }}/message?token=${{ secrets.GOTIFY_TOKEN }}" \ RESPONSE=$(curl -k -s -w "\n%{http_code}" -X POST "${{ secrets.GOTIFY_URL }}/message?token=${{ secrets.GOTIFY_TOKEN }}" \
-F "title=✅ Deployment Success: ${{ github.repository }}" \ -F "title=✅ Deployment Success: ${{ github.repository }}" \
-F "message=The deployment of ${{ github.repository }} (branch: ${{ github.ref }}) was successful. -F "message=The deployment of ${{ github.repository }} (branch: ${{ github.ref_name }}) was successful.
Commit: ${{ github.sha }} Commit: ${{ github.sha }}
Actor: ${{ github.actor }} Actor: ${{ github.actor }}
@@ -164,7 +192,7 @@ jobs:
echo "Sending failure notification to Gotify..." echo "Sending failure notification to Gotify..."
RESPONSE=$(curl -k -s -w "\n%{http_code}" -X POST "${{ secrets.GOTIFY_URL }}/message?token=${{ secrets.GOTIFY_TOKEN }}" \ RESPONSE=$(curl -k -s -w "\n%{http_code}" -X POST "${{ secrets.GOTIFY_URL }}/message?token=${{ secrets.GOTIFY_TOKEN }}" \
-F "title=❌ Deployment Failed: ${{ github.repository }}" \ -F "title=❌ Deployment Failed: ${{ github.repository }}" \
-F "message=The deployment of ${{ github.repository }} (branch: ${{ github.ref }}) failed! -F "message=The deployment of ${{ github.repository }} (branch: ${{ github.ref_name }}) failed!
Commit: ${{ github.sha }} Commit: ${{ github.sha }}
Actor: ${{ github.actor }} Actor: ${{ github.actor }}

View File

@@ -1,21 +1,21 @@
services: services:
app: app:
image: registry.infra.mintel.me/mintel/klz-cables.com:latest image: registry.infra.mintel.me/mintel/klz-cables.com:${IMAGE_TAG:-latest}
restart: always restart: always
networks: networks:
- infra - infra
ports: ports:
- "3000:3000" - "3000:3000"
env_file: env_file:
- .env - ${ENV_FILE:-.env}
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
# HTTP ⇒ HTTPS redirect # HTTP ⇒ HTTPS redirect
- "traefik.http.routers.klz-cables-web.rule=(Host(`klz-cables.com`) || Host(`www.klz-cables.com`) || Host(`staging.klz-cables.com`)) && !PathPrefix(`/.well-known/acme-challenge/`)" - "traefik.http.routers.klz-cables-web.rule=Host(`${TRAEFIK_HOST}`) && !PathPrefix(`/.well-known/acme-challenge/`)"
- "traefik.http.routers.klz-cables-web.entrypoints=web" - "traefik.http.routers.klz-cables-web.entrypoints=web"
- "traefik.http.routers.klz-cables-web.middlewares=redirect-https" - "traefik.http.routers.klz-cables-web.middlewares=redirect-https"
# HTTPS router # HTTPS router
- "traefik.http.routers.klz-cables.rule=Host(`klz-cables.com`) || Host(`www.klz-cables.com`) || Host(`staging.klz-cables.com`)" - "traefik.http.routers.klz-cables.rule=Host(`${TRAEFIK_HOST}`)"
- "traefik.http.routers.klz-cables.entrypoints=websecure" - "traefik.http.routers.klz-cables.entrypoints=websecure"
- "traefik.http.routers.klz-cables.tls.certresolver=le" - "traefik.http.routers.klz-cables.tls.certresolver=le"
- "traefik.http.routers.klz-cables.tls=true" - "traefik.http.routers.klz-cables.tls=true"