Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Failing after 7m46s
- Updated deployment script to check for existing containers and free ports before starting a new container. - Added a new script to check the status of the Gitea runner, including service checks, running processes, Docker containers, common directories, and network connections.
183 lines
7.0 KiB
YAML
183 lines
7.0 KiB
YAML
name: Dev Deployment (Zero Downtime)
|
|
|
|
on:
|
|
push:
|
|
branches: [ dev ]
|
|
|
|
env:
|
|
NODE_VERSION: '20'
|
|
DOCKER_IMAGE: portfolio-app
|
|
IMAGE_TAG: dev
|
|
|
|
jobs:
|
|
deploy-dev:
|
|
runs-on: ubuntu-latest # Gitea Actions: Use runner with ubuntu-latest label
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v3
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Run linting
|
|
run: npm run lint
|
|
continue-on-error: true # Don't block dev deployments on lint errors
|
|
|
|
- name: Run tests
|
|
run: npm run test
|
|
continue-on-error: true # Don't block dev deployments on test failures
|
|
|
|
- name: Build application
|
|
run: npm run build
|
|
|
|
- name: Build Docker image
|
|
run: |
|
|
echo "🏗️ Building dev Docker image with BuildKit cache..."
|
|
DOCKER_BUILDKIT=1 docker build \
|
|
--cache-from ${{ env.DOCKER_IMAGE }}:${{ env.IMAGE_TAG }} \
|
|
--cache-from ${{ env.DOCKER_IMAGE }}:latest \
|
|
-t ${{ env.DOCKER_IMAGE }}:${{ env.IMAGE_TAG }} \
|
|
.
|
|
echo "✅ Docker image built successfully"
|
|
|
|
- name: Zero-Downtime Dev Deployment
|
|
run: |
|
|
echo "🚀 Starting zero-downtime dev deployment..."
|
|
|
|
CONTAINER_NAME="portfolio-app-dev"
|
|
HEALTH_PORT="3001"
|
|
IMAGE_NAME="${{ env.DOCKER_IMAGE }}:${{ env.IMAGE_TAG }}"
|
|
|
|
# Check for existing container (running or stopped)
|
|
EXISTING_CONTAINER=$(docker ps -aq -f name=$CONTAINER_NAME || echo "")
|
|
|
|
# Export environment variables
|
|
export NODE_ENV=production
|
|
export LOG_LEVEL=${LOG_LEVEL:-debug}
|
|
export NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL_DEV:-https://dev.dk0.dev}
|
|
export MY_EMAIL=${MY_EMAIL}
|
|
export MY_INFO_EMAIL=${MY_INFO_EMAIL}
|
|
export MY_PASSWORD=${MY_PASSWORD}
|
|
export MY_INFO_PASSWORD=${MY_INFO_PASSWORD}
|
|
export ADMIN_BASIC_AUTH=${ADMIN_BASIC_AUTH}
|
|
export ADMIN_SESSION_SECRET=${ADMIN_SESSION_SECRET}
|
|
export N8N_WEBHOOK_URL=${N8N_WEBHOOK_URL:-''}
|
|
export N8N_SECRET_TOKEN=${N8N_SECRET_TOKEN:-''}
|
|
export PORT=${HEALTH_PORT}
|
|
|
|
# Stop and remove existing container if it exists (running or stopped)
|
|
if [ ! -z "$EXISTING_CONTAINER" ]; then
|
|
echo "🛑 Stopping and removing existing container..."
|
|
docker stop $EXISTING_CONTAINER 2>/dev/null || true
|
|
docker rm $EXISTING_CONTAINER 2>/dev/null || true
|
|
echo "✅ Old container removed"
|
|
fi
|
|
|
|
# Also check if port is in use by another process and free it
|
|
PORT_IN_USE=$(lsof -ti:${HEALTH_PORT} 2>/dev/null || echo "")
|
|
if [ ! -z "$PORT_IN_USE" ]; then
|
|
echo "⚠️ Port ${HEALTH_PORT} is in use by process $PORT_IN_USE"
|
|
echo "Attempting to free the port..."
|
|
kill -9 $PORT_IN_USE 2>/dev/null || true
|
|
sleep 2
|
|
fi
|
|
|
|
# Start new container with updated image
|
|
echo "🆕 Starting new dev container..."
|
|
docker run -d \
|
|
--name $CONTAINER_NAME \
|
|
--restart unless-stopped \
|
|
-p ${HEALTH_PORT}:3000 \
|
|
-e NODE_ENV=production \
|
|
-e LOG_LEVEL=${LOG_LEVEL:-debug} \
|
|
-e NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL_DEV:-https://dev.dk0.dev} \
|
|
-e MY_EMAIL=${MY_EMAIL} \
|
|
-e MY_INFO_EMAIL=${MY_INFO_EMAIL} \
|
|
-e MY_PASSWORD=${MY_PASSWORD} \
|
|
-e MY_INFO_PASSWORD=${MY_INFO_PASSWORD} \
|
|
-e ADMIN_BASIC_AUTH=${ADMIN_BASIC_AUTH} \
|
|
-e ADMIN_SESSION_SECRET=${ADMIN_SESSION_SECRET} \
|
|
-e N8N_WEBHOOK_URL=${N8N_WEBHOOK_URL:-''} \
|
|
-e N8N_SECRET_TOKEN=${N8N_SECRET_TOKEN:-''} \
|
|
$IMAGE_NAME
|
|
|
|
# Wait for new container to be healthy
|
|
echo "⏳ Waiting for new container to be healthy..."
|
|
HEALTH_CHECK_PASSED=false
|
|
for i in {1..60}; do
|
|
NEW_CONTAINER=$(docker ps -q -f name=$CONTAINER_NAME)
|
|
if [ ! -z "$NEW_CONTAINER" ]; then
|
|
# Check Docker health status
|
|
HEALTH=$(docker inspect $NEW_CONTAINER --format='{{.State.Health.Status}}' 2>/dev/null || echo "starting")
|
|
if [ "$HEALTH" == "healthy" ]; then
|
|
echo "✅ New container is healthy!"
|
|
HEALTH_CHECK_PASSED=true
|
|
break
|
|
fi
|
|
# Also check HTTP health endpoint
|
|
if curl -f http://localhost:$HEALTH_PORT/api/health > /dev/null 2>&1; then
|
|
echo "✅ New container is responding!"
|
|
HEALTH_CHECK_PASSED=true
|
|
break
|
|
fi
|
|
fi
|
|
echo "⏳ Waiting... ($i/60)"
|
|
sleep 2
|
|
done
|
|
|
|
# Verify new container is working
|
|
if [ "$HEALTH_CHECK_PASSED" != "true" ]; then
|
|
echo "⚠️ New dev container health check failed, but continuing (non-blocking)..."
|
|
docker logs $CONTAINER_NAME --tail=50
|
|
fi
|
|
|
|
# Remove old container if it exists and is different
|
|
if [ ! -z "$OLD_CONTAINER" ]; then
|
|
NEW_CONTAINER=$(docker ps -q -f name=$CONTAINER_NAME)
|
|
if [ "$OLD_CONTAINER" != "$NEW_CONTAINER" ]; then
|
|
echo "🧹 Removing old container..."
|
|
docker stop $OLD_CONTAINER 2>/dev/null || true
|
|
docker rm $OLD_CONTAINER 2>/dev/null || true
|
|
fi
|
|
fi
|
|
|
|
echo "✅ Dev deployment completed!"
|
|
env:
|
|
NODE_ENV: production
|
|
LOG_LEVEL: ${{ vars.LOG_LEVEL || 'debug' }}
|
|
NEXT_PUBLIC_BASE_URL_DEV: ${{ vars.NEXT_PUBLIC_BASE_URL_DEV || 'https://dev.dk0.dev' }}
|
|
MY_EMAIL: ${{ vars.MY_EMAIL }}
|
|
MY_INFO_EMAIL: ${{ vars.MY_INFO_EMAIL }}
|
|
MY_PASSWORD: ${{ secrets.MY_PASSWORD }}
|
|
MY_INFO_PASSWORD: ${{ secrets.MY_INFO_PASSWORD }}
|
|
ADMIN_BASIC_AUTH: ${{ secrets.ADMIN_BASIC_AUTH }}
|
|
ADMIN_SESSION_SECRET: ${{ secrets.ADMIN_SESSION_SECRET }}
|
|
N8N_WEBHOOK_URL: ${{ vars.N8N_WEBHOOK_URL || '' }}
|
|
N8N_SECRET_TOKEN: ${{ secrets.N8N_SECRET_TOKEN || '' }}
|
|
|
|
- name: Dev Health Check
|
|
run: |
|
|
echo "🔍 Running dev health checks..."
|
|
for i in {1..20}; do
|
|
if curl -f http://localhost:3001/api/health && curl -f http://localhost:3001/ > /dev/null; then
|
|
echo "✅ Dev is fully operational!"
|
|
exit 0
|
|
fi
|
|
echo "⏳ Waiting for dev... ($i/20)"
|
|
sleep 3
|
|
done
|
|
echo "⚠️ Dev health check failed, but continuing (non-blocking)..."
|
|
docker logs portfolio-app-dev --tail=50
|
|
|
|
- name: Cleanup
|
|
run: |
|
|
echo "🧹 Cleaning up old images..."
|
|
docker image prune -f
|
|
echo "✅ Cleanup completed"
|