Refine Docker, docker-compose, and EC2 deploy

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
root 2026-02-09 20:17:26 +05:00
parent 284fb12576
commit dfebb51bd2
4 changed files with 89 additions and 21 deletions

View File

@ -37,6 +37,8 @@ jobs:
- name: Deploy to EC2 with rollback - name: Deploy to EC2 with rollback
uses: appleboy/ssh-action@v1.2.0 uses: appleboy/ssh-action@v1.2.0
env:
EC2_ENV: ${{ secrets.EC2_ENV }}
with: with:
host: ${{ secrets.EC2_HOST }} host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }} username: ${{ secrets.EC2_USER }}
@ -51,11 +53,7 @@ jobs:
mkdir -p "$APP_DIR" mkdir -p "$APP_DIR"
cd "$APP_DIR" cd "$APP_DIR"
echo "Writing .env file from EC2_ENV secret..." # Initialize git repo if needed
# Overwrite .env on the server with the contents of the EC2_ENV variable
# EC2_ENV is provided by GitHub as a multi-line secret matching your local .env
printf '%s\n' "$EC2_ENV" > .env
if [ ! -d ".git" ]; then if [ ! -d ".git" ]; then
echo "Cloning repository for the first time..." echo "Cloning repository for the first time..."
git clone ${{ github.repositoryUrl }} . git clone ${{ github.repositoryUrl }} .
@ -71,15 +69,33 @@ jobs:
git checkout ${{ github.ref_name }} git checkout ${{ github.ref_name }}
git reset --hard ${{ github.sha }} git reset --hard ${{ github.sha }}
echo "Pulling docker images and rebuilding containers..." echo "Writing .env file from EC2_ENV secret..."
if command -v docker-compose >/dev/null 2>&1; then # Write .env file AFTER pulling latest code so it's in the right location
DC="docker-compose" # EC2_ENV is provided by GitHub as a multi-line secret matching your local .env
else printf '%s\n' "$EC2_ENV" > .env
DC="docker compose"
echo "Checking Docker and Docker Compose..."
if ! command -v docker >/dev/null 2>&1; then
echo "Error: Docker is not installed"
exit 1
fi fi
$DC pull || true if command -v docker-compose >/dev/null 2>&1; then
DC="docker-compose"
elif docker compose version >/dev/null 2>&1; then
DC="docker compose"
else
echo "Error: Docker Compose is not installed"
exit 1
fi
echo "Using: $DC"
$DC version
echo "Stopping existing containers..."
$DC down || true
echo "Building and starting containers with docker-compose..."
set +e set +e
$DC up -d --build $DC up -d --build
DEPLOY_EXIT=$? DEPLOY_EXIT=$?
@ -89,26 +105,32 @@ jobs:
echo "Deployment failed, attempting rollback..." echo "Deployment failed, attempting rollback..."
if [ -n "$PREV_COMMIT" ]; then if [ -n "$PREV_COMMIT" ]; then
git reset --hard "$PREV_COMMIT" git reset --hard "$PREV_COMMIT"
printf '%s\n' "$EC2_ENV" > .env
$DC up -d --build || true $DC up -d --build || true
fi fi
exit 1 exit 1
fi fi
echo "Waiting for containers to be healthy..."
sleep 10
echo "Running health check..." echo "Running health check..."
HEALTH_URL="${HEALTH_URL:-http://localhost:3000/api/health}" HEALTH_URL="${HEALTH_URL:-http://localhost:3000/api/health}"
for i in {1..10}; do for i in {1..15}; do
if curl -fsS "$HEALTH_URL" >/dev/null 2>&1; then if curl -fsS "$HEALTH_URL" >/dev/null 2>&1; then
echo "Health check passed." echo "Health check passed on attempt $i."
echo "Deployment successful!"
exit 0 exit 0
fi fi
echo "Health check attempt $i failed, retrying..." echo "Health check attempt $i failed, retrying in 5 seconds..."
sleep 5 sleep 5
done done
echo "Health check failed after multiple attempts, rolling back..." echo "Health check failed after multiple attempts, rolling back..."
if [ -n "$PREV_COMMIT" ]; then if [ -n "$PREV_COMMIT" ]; then
git reset --hard "$PREV_COMMIT" git reset --hard "$PREV_COMMIT"
printf '%s\n' "$EC2_ENV" > .env
$DC up -d --build || true $DC up -d --build || true
fi fi
exit 1 exit 1

View File

@ -2,13 +2,20 @@ FROM node:20-alpine
WORKDIR /app WORKDIR /app
# Copy package files
COPY package*.json prisma.config.ts ./ COPY package*.json prisma.config.ts ./
COPY prisma ./prisma COPY prisma ./prisma
RUN npm install && npx prisma generate # Install dependencies and generate Prisma client
RUN npm install --only=production && npx prisma generate
# Copy application code
COPY . . COPY . .
# Build the Next.js application
RUN npm run build
EXPOSE 3000 EXPOSE 3000
CMD ["npm", "run", "dev"] # Use production start command
CMD ["npm", "start"]

View File

@ -11,21 +11,34 @@ services:
- "5444:5432" - "5444:5432"
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
interval: 10s
timeout: 5s
retries: 5
app: app:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
restart: always
ports: ports:
- "3000:3000" - "3000:3000"
env_file:
- .env
environment: environment:
# Override DATABASE_URL to use internal docker network hostname
DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-password}@db:5432/${POSTGRES_DB:-dropshipping}?schema=public DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-password}@db:5432/${POSTGRES_DB:-dropshipping}?schema=public
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET} NODE_ENV: production
NEXTAUTH_URL: ${NEXTAUTH_URL:-http://localhost:3000}
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET}
depends_on: depends_on:
- db db:
condition: service_healthy
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/api/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) }).on('error', () => process.exit(1))"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
volumes: volumes:
postgres_data: postgres_data:

View File

@ -0,0 +1,26 @@
import { NextResponse } from "next/server"
import { prisma } from "@/lib/prisma"
export async function GET() {
try {
// Simple database connectivity check
await prisma.$queryRaw`SELECT 1`
return NextResponse.json(
{
status: "ok",
timestamp: new Date().toISOString()
},
{ status: 200 }
)
} catch (error) {
console.error("Health check failed:", error)
return NextResponse.json(
{
status: "error",
message: "Database connection failed"
},
{ status: 503 }
)
}
}