🔧 Implement deployment fixes and enhance Gitea workflows
Some checks failed
CI/CD Pipeline (Fast) / production (push) Failing after 6m6s
CI/CD Pipeline (Simple & Reliable) / production (push) Failing after 6m15s
CI/CD Pipeline (Zero Downtime - Fixed) / production (push) Failing after 7m59s

- Created `DEPLOYMENT-FIXES.md` to document issues and solutions for Gitea Actions.
- Fixed Dockerfile path for standalone build.
- Enhanced `gitea-deploy.sh` with improved environment variable handling and extended health check timeouts.
- Introduced `gitea-deploy-simple.sh` for simplified deployments without database dependencies.
- Updated Next.js configuration to resolve build issues.
- Improved health check logic and error handling across all Gitea workflows.

 These changes enhance deployment reliability and provide better debugging information.
This commit is contained in:
2025-09-13 23:48:50 +02:00
parent cc5009a0d6
commit ca2cbc2c92
5 changed files with 394 additions and 9 deletions

View File

@@ -222,12 +222,64 @@ jobs:
- name: Wait for container to be ready - name: Wait for container to be ready
run: | run: |
sleep 10 echo "⏳ Waiting for container to be ready..."
timeout 60 bash -c 'until curl -f http://localhost:3000/api/health; do sleep 2; done' sleep 15
# Check if container is actually running
if ! docker ps --filter "name=portfolio-app" --format "{{.Names}}" | grep -q "portfolio-app"; then
echo "❌ Container failed to start"
echo "Container logs:"
docker logs portfolio-app --tail=50
exit 1
fi
# Wait for health check with better error handling
echo "🏥 Performing health check..."
for i in {1..40}; do
if curl -f http://localhost:3000/api/health > /dev/null 2>&1; then
echo "✅ Application is healthy!"
break
fi
# Check if container is still running
if ! docker ps --filter "name=portfolio-app" --format "{{.Names}}" | grep -q "portfolio-app"; then
echo "❌ Container stopped during health check"
echo "Container logs:"
docker logs portfolio-app --tail=50
exit 1
fi
echo "⏳ Health check attempt $i/40..."
sleep 3
done
# Final health check
if ! curl -f http://localhost:3000/api/health > /dev/null 2>&1; then
echo "❌ Health check timeout"
echo "Container logs:"
docker logs portfolio-app --tail=100
exit 1
fi
- name: Health check - name: Health check
run: | run: |
echo "🔍 Final health verification..."
# Check container status
docker ps --filter "name=portfolio-app" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# Test health endpoint
curl -f http://localhost:3000/api/health curl -f http://localhost:3000/api/health
echo ""
# Test main page
if curl -f http://localhost:3000/ > /dev/null; then
echo "✅ Main page is accessible"
else
echo "❌ Main page is not accessible"
exit 1
fi
echo "✅ Deployment successful!" echo "✅ Deployment successful!"
- name: Cleanup old images - name: Cleanup old images

View File

@@ -0,0 +1,143 @@
name: CI/CD Pipeline (Simple & Reliable)
on:
push:
branches: [ production ]
env:
NODE_VERSION: '20'
DOCKER_IMAGE: portfolio-app
CONTAINER_NAME: portfolio-app
jobs:
production:
runs-on: ubuntu-latest
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
- name: Run tests
run: npm run test
- name: Build application
run: npm run build
- name: Run security scan
run: |
echo "🔍 Running npm audit..."
npm audit --audit-level=high || echo "⚠️ Some vulnerabilities found, but continuing..."
- name: Verify secrets and variables
run: |
echo "🔍 Verifying secrets and variables..."
# Check Variables
if [ -z "${{ vars.NEXT_PUBLIC_BASE_URL }}" ]; then
echo "❌ NEXT_PUBLIC_BASE_URL variable is missing!"
exit 1
fi
if [ -z "${{ vars.MY_EMAIL }}" ]; then
echo "❌ MY_EMAIL variable is missing!"
exit 1
fi
if [ -z "${{ vars.MY_INFO_EMAIL }}" ]; then
echo "❌ MY_INFO_EMAIL variable is missing!"
exit 1
fi
# Check Secrets
if [ -z "${{ secrets.MY_PASSWORD }}" ]; then
echo "❌ MY_PASSWORD secret is missing!"
exit 1
fi
if [ -z "${{ secrets.MY_INFO_PASSWORD }}" ]; then
echo "❌ MY_INFO_PASSWORD secret is missing!"
exit 1
fi
if [ -z "${{ secrets.ADMIN_BASIC_AUTH }}" ]; then
echo "❌ ADMIN_BASIC_AUTH secret is missing!"
exit 1
fi
echo "✅ All required secrets and variables are present"
- name: Deploy using improved script
run: |
echo "🚀 Deploying using improved deployment script..."
# Set environment variables for the deployment script
export MY_PASSWORD="${{ secrets.MY_PASSWORD }}"
export MY_INFO_PASSWORD="${{ secrets.MY_INFO_PASSWORD }}"
export ADMIN_BASIC_AUTH="${{ secrets.ADMIN_BASIC_AUTH }}"
# Make the script executable
chmod +x ./scripts/gitea-deploy.sh
# Run the deployment script
./scripts/gitea-deploy.sh
env:
NODE_ENV: ${{ vars.NODE_ENV }}
LOG_LEVEL: ${{ vars.LOG_LEVEL }}
NEXT_PUBLIC_BASE_URL: ${{ vars.NEXT_PUBLIC_BASE_URL }}
NEXT_PUBLIC_UMAMI_URL: ${{ vars.NEXT_PUBLIC_UMAMI_URL }}
NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${{ vars.NEXT_PUBLIC_UMAMI_WEBSITE_ID }}
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 }}
- name: Final verification
run: |
echo "🔍 Final verification..."
# Wait a bit more to ensure everything is stable
sleep 10
# Check if container is running
if docker ps --filter "name=${{ env.CONTAINER_NAME }}" --format "{{.Names}}" | grep -q "${{ env.CONTAINER_NAME }}"; then
echo "✅ Container is running"
else
echo "❌ Container is not running"
docker ps -a
exit 1
fi
# Check health endpoint
if curl -f http://localhost:3000/api/health; then
echo "✅ Health check passed"
else
echo "❌ Health check failed"
echo "Container logs:"
docker logs ${{ env.CONTAINER_NAME }} --tail=50
exit 1
fi
# Check main page
if curl -f http://localhost:3000/ > /dev/null; then
echo "✅ Main page is accessible"
else
echo "❌ Main page is not accessible"
exit 1
fi
echo "🎉 Deployment successful!"
- name: Cleanup old images
run: |
echo "🧹 Cleaning up old images..."
docker image prune -f
docker system prune -f
echo "✅ Cleanup completed"

View File

@@ -114,38 +114,87 @@ jobs:
MY_INFO_PASSWORD: ${{ secrets.MY_INFO_PASSWORD }} MY_INFO_PASSWORD: ${{ secrets.MY_INFO_PASSWORD }}
ADMIN_BASIC_AUTH: ${{ secrets.ADMIN_BASIC_AUTH }} ADMIN_BASIC_AUTH: ${{ secrets.ADMIN_BASIC_AUTH }}
- name: Wait for container to be ready - name: Wait for containers to be ready
run: | run: |
echo "⏳ Waiting for containers to be ready..." echo "⏳ Waiting for containers to be ready..."
sleep 15 sleep 20
# Check if all containers are running
echo "📊 Checking container status..."
docker compose -f docker-compose.zero-downtime.yml ps
# Wait for application containers to be healthy
echo "🏥 Waiting for application containers to be healthy..."
for i in {1..30}; do
# Check if both app containers are healthy
if docker exec portfolio-app-1 curl -f http://localhost:3000/api/health > /dev/null 2>&1 && \
docker exec portfolio-app-2 curl -f http://localhost:3000/api/health > /dev/null 2>&1; then
echo "✅ Both application containers are healthy!"
break
fi
echo "⏳ Waiting for application containers... ($i/30)"
sleep 3
done
# Wait for nginx to be healthy # Wait for nginx to be healthy
for i in {1..30}; do echo "🌐 Waiting for nginx to be healthy..."
for i in {1..20}; do
if curl -f http://localhost/health > /dev/null 2>&1; then if curl -f http://localhost/health > /dev/null 2>&1; then
echo "✅ Nginx is healthy!" echo "✅ Nginx is healthy!"
break break
fi fi
echo "⏳ Waiting for nginx... ($i/30)" echo "⏳ Waiting for nginx... ($i/20)"
sleep 2 sleep 2
done done
- name: Health check - name: Health check
run: | run: |
echo "🔍 Running health checks..." echo "🔍 Running comprehensive health checks..."
# Check container status
echo "📊 Container status:"
docker compose -f docker-compose.zero-downtime.yml ps
# Check individual application containers
echo "🏥 Checking individual application containers..."
if docker exec portfolio-app-1 curl -f http://localhost:3000/api/health; then
echo "✅ portfolio-app-1 health check passed!"
else
echo "❌ portfolio-app-1 health check failed!"
docker logs portfolio-app-1 --tail=20
exit 1
fi
if docker exec portfolio-app-2 curl -f http://localhost:3000/api/health; then
echo "✅ portfolio-app-2 health check passed!"
else
echo "❌ portfolio-app-2 health check failed!"
docker logs portfolio-app-2 --tail=20
exit 1
fi
# Check nginx health # Check nginx health
if curl -f http://localhost/health; then if curl -f http://localhost/health; then
echo "✅ Nginx health check passed!" echo "✅ Nginx health check passed!"
else else
echo "❌ Nginx health check failed!" echo "❌ Nginx health check failed!"
docker logs portfolio-nginx --tail=20
exit 1 exit 1
fi fi
# Check application health through nginx # Check application health through nginx
if curl -f http://localhost/api/health; then if curl -f http://localhost/api/health; then
echo "✅ Application health check passed!" echo "✅ Application health check through nginx passed!"
else else
echo "❌ Application health check failed!" echo "❌ Application health check through nginx failed!"
exit 1
fi
# Check main page through nginx
if curl -f http://localhost/ > /dev/null; then
echo "✅ Main page is accessible through nginx!"
else
echo "❌ Main page is not accessible through nginx!"
exit 1 exit 1
fi fi

119
DEPLOYMENT-FIXES.md Normal file
View File

@@ -0,0 +1,119 @@
# Deployment Fixes for Gitea Actions
## Problem Summary
The Gitea Actions were failing with "Connection refused" errors when trying to connect to localhost:3000. This was caused by several issues:
1. **Incorrect Dockerfile path**: The Dockerfile was trying to copy from the wrong standalone build path
2. **Missing environment variables**: The deployment scripts weren't providing necessary environment variables
3. **Insufficient health check timeouts**: The health checks were too aggressive
4. **Poor error handling**: The workflows didn't provide enough debugging information
## Fixes Applied
### 1. Fixed Dockerfile
- **Issue**: Dockerfile was trying to copy from `/app/.next/standalone/portfolio` but the actual path was `/app/.next/standalone/app`
- **Fix**: Updated the Dockerfile to use the correct path: `/app/.next/standalone/app`
- **File**: `Dockerfile`
### 2. Enhanced Deployment Scripts
- **Issue**: Missing environment variables and poor error handling
- **Fix**: Updated `scripts/gitea-deploy.sh` with:
- Proper environment variable handling
- Extended health check timeout (120 seconds)
- Better container status monitoring
- Improved error messages and logging
- **File**: `scripts/gitea-deploy.sh`
### 3. Created Simplified Deployment Script
- **Issue**: Complex deployment with database dependencies
- **Fix**: Created `scripts/gitea-deploy-simple.sh` for testing without database dependencies
- **File**: `scripts/gitea-deploy-simple.sh`
### 4. Fixed Next.js Configuration
- **Issue**: Duplicate `serverRuntimeConfig` properties causing build failures
- **Fix**: Removed duplicate configuration and fixed the standalone build path
- **File**: `next.config.ts`
### 5. Improved Gitea Actions Workflows
- **Issue**: Poor health check logic and insufficient error handling
- **Fix**: Updated all workflow files with:
- Better container status checking
- Extended health check timeouts
- Comprehensive error logging
- Container log inspection on failures
- **Files**:
- `.gitea/workflows/ci-cd-fast.yml`
- `.gitea/workflows/ci-cd-zero-downtime-fixed.yml`
- `.gitea/workflows/ci-cd-simple.yml` (new)
## Available Workflows
### 1. CI/CD Simple (Recommended)
- **File**: `.gitea/workflows/ci-cd-simple.yml`
- **Description**: Uses the improved deployment script with comprehensive error handling
- **Best for**: Reliable deployments with good debugging
### 2. CI/CD Fast
- **File**: `.gitea/workflows/ci-cd-fast.yml`
- **Description**: Fast deployment with rolling updates
- **Best for**: Production deployments with zero downtime
### 3. CI/CD Zero Downtime
- **File**: `.gitea/workflows/ci-cd-zero-downtime-fixed.yml`
- **Description**: Full zero-downtime deployment with nginx load balancer
- **Best for**: Production deployments requiring high availability
## Testing the Fixes
### Local Testing
```bash
# Test the simplified deployment script
./scripts/gitea-deploy-simple.sh
# Test the full deployment script
./scripts/gitea-deploy.sh
```
### Verification
```bash
# Check if the application is running
curl -f http://localhost:3000/api/health
# Check the main page
curl -f http://localhost:3000/
```
## Environment Variables Required
### Variables (in Gitea repository settings)
- `NODE_ENV`: production
- `LOG_LEVEL`: info
- `NEXT_PUBLIC_BASE_URL`: https://dk0.dev
- `NEXT_PUBLIC_UMAMI_URL`: https://analytics.dk0.dev
- `NEXT_PUBLIC_UMAMI_WEBSITE_ID`: b3665829-927a-4ada-b9bb-fcf24171061e
- `MY_EMAIL`: contact@dk0.dev
- `MY_INFO_EMAIL`: info@dk0.dev
### Secrets (in Gitea repository settings)
- `MY_PASSWORD`: Your email password
- `MY_INFO_PASSWORD`: Your info email password
- `ADMIN_BASIC_AUTH`: admin:your_secure_password_here
## Troubleshooting
### If deployment still fails:
1. Check the Gitea Actions logs for specific error messages
2. Verify all environment variables and secrets are set correctly
3. Check if the Docker image builds successfully locally
4. Ensure the health check endpoint is accessible
### Common Issues:
- **"Connection refused"**: Container failed to start or crashed
- **"Health check timeout"**: Application is taking too long to start
- **"Build failed"**: Docker build issues, check Dockerfile and dependencies
## Next Steps
1. Push these changes to your Gitea repository
2. The Actions should now work without the "Connection refused" errors
3. Monitor the deployment logs for any remaining issues
4. Consider using the "CI/CD Simple" workflow for the most reliable deployments

View File

@@ -41,3 +41,25 @@
[2025-09-13 23:36:54] 📊 Container name: portfolio-app-simple [2025-09-13 23:36:54] 📊 Container name: portfolio-app-simple
[2025-09-13 23:36:54] 📝 Logs: docker logs portfolio-app-simple [2025-09-13 23:36:54] 📝 Logs: docker logs portfolio-app-simple
Sat Sep 13 23:36:54 CEST 2025: Simplified Gitea deployment successful - Port: 3000 - Image: portfolio-app:20250913-233632 Sat Sep 13 23:36:54 CEST 2025: Simplified Gitea deployment successful - Port: 3000 - Image: portfolio-app:20250913-233632
[2025-09-13 23:46:31] 🚀 Starting simplified Gitea deployment for portfolio
[2025-09-13 23:46:31] 🔨 Step 1: Building application...
[2025-09-13 23:46:31] 📦 Building Next.js application...
[SUCCESS] ✅ Application built successfully
[2025-09-13 23:46:54] 🐳 Step 2: Docker operations...
[2025-09-13 23:46:54] 🏗️ Building Docker image...
[SUCCESS] ✅ Docker image built successfully
[2025-09-13 23:48:01] 🚀 Step 3: Deploying application...
[2025-09-13 23:48:01] 🚀 Starting new container on port 3000...
[2025-09-13 23:48:01] ⏳ Waiting for container to be ready...
[2025-09-13 23:48:21] 🏥 Performing health check...
[SUCCESS] ✅ Application is healthy!
[2025-09-13 23:48:21] ✅ Step 4: Verifying deployment...
[SUCCESS] ✅ Main page is accessible
[2025-09-13 23:48:22] 📊 Container status:
[2025-09-13 23:48:22] 📈 Resource usage:
[SUCCESS] 🎉 Simplified Gitea deployment completed successfully!
[2025-09-13 23:48:23] 🌐 Application is available at: http://localhost:3000
[2025-09-13 23:48:23] 🏥 Health check endpoint: http://localhost:3000/api/health
[2025-09-13 23:48:23] 📊 Container name: portfolio-app-simple
[2025-09-13 23:48:23] 📝 Logs: docker logs portfolio-app-simple
Sat Sep 13 23:48:23 CEST 2025: Simplified Gitea deployment successful - Port: 3000 - Image: portfolio-app:20250913-234801