نشر تطبيق Next.js باستخدام Docker و CI/CD في بيئة الإنتاج

يرشدك هذا الدرس خطوة بخطوة لحوسلة تطبيق Next.js باستخدام Docker، وإعداد خط أنابيب CI/CD مع GitHub Actions، والنشر التلقائي في بيئة الإنتاج على خادم VPS Linux. في النهاية، كل عملية دفع (push) إلى الفرع الرئيسي ستُطلق عملية نشر تلقائية.
أهداف التعلم
بنهاية هذا الدرس، ستكون قادراً على:
- كتابة Dockerfile مُحسّن متعدد المراحل لـ Next.js
- تكوين Docker Compose للتطوير المحلي والإنتاج
- إعداد خط أنابيب CI/CD كامل مع GitHub Actions
- النشر التلقائي على خادم VPS عبر SSH
- إدارة متغيرات البيئة بشكل آمن
- تكوين خادم وكيل عكسي Nginx مع SSL
المتطلبات الأساسية
قبل البدء، تأكد من توفر:
- Node.js 20+ مثبت محلياً
- Docker Desktop مثبت وعامل (تثبيت Docker)
- حساب GitHub مع مستودع يحتوي على تطبيق Next.js
- خادم VPS Linux (يُوصى بـ Ubuntu 22.04+) مع وصول SSH
- اسم نطاق يشير إلى خادم VPS الخاص بك (اختياري لكن مُوصى به)
- معرفة أساسية بـ Next.js و سطر الأوامر
ما ستبنيه
سنُعدّ بنية نشر كاملة:
- Dockerfile متعدد المراحل — صورة Docker مُحسّنة (~150 ميجابايت بدلاً من ~1 جيجابايت)
- Docker Compose — تنسيق الخدمات (التطبيق + قاعدة البيانات + التخزين المؤقت)
- خط أنابيب CI/CD — اختبارات تلقائية وبناء ونشر عبر GitHub Actions
- وكيل عكسي — Nginx مع شهادة SSL من Let's Encrypt
- مراقبة — فحوصات صحة وسجلات منظمة
الخطوة 1: تحضير مشروع Next.js
ابدأ بالتحقق من أن مشروع Next.js يعمل بشكل صحيح محلياً.
# Verifier la version de Node.js
node --version # v20.x.x requis
# Installer les dependances
npm install
# Tester le build de production
npm run build
# Verifier que le serveur demarre
npm startإذا لم يكن لديك مشروع Next.js بعد، أنشئ واحداً بسرعة باستخدام npx create-next-app@latest mon-app --typescript. هذا الدرس يعمل مع Next.js 14 و 15.
إضافة سكربت فحص الصحة
أنشئ ملف app/api/health/route.ts حتى يتمكن Docker من التحقق من حالة تطبيقك:
// app/api/health/route.ts
import { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({
status: "healthy",
timestamp: new Date().toISOString(),
uptime: process.uptime(),
});
}سيُستخدم هذا الـ endpoint من قبل Docker وخط أنابيب CI/CD للتحقق من أن التطبيق يعمل.
الخطوة 2: كتابة Dockerfile متعدد المراحل
سر صورة Docker عالية الأداء لـ Next.js هو البناء متعدد المراحل. يسمح هذا بفصل أدوات البناء (الثقيلة) عن الصورة النهائية (الخفيفة).
أنشئ ملف Dockerfile في جذر مشروعك:
# =============================================================================
# Etape 1 : Image de base avec les dependances
# =============================================================================
FROM node:20-alpine AS base
# Installer libc6-compat pour les modules natifs
RUN apk add --no-cache libc6-compat
WORKDIR /app
# =============================================================================
# Etape 2 : Installer les dependances
# =============================================================================
FROM base AS deps
# Copier les fichiers de dependances
COPY package.json package-lock.json* ./
# Installer toutes les dependances (y compris devDependencies pour le build)
RUN npm ci
# =============================================================================
# Etape 3 : Build de l'application
# =============================================================================
FROM base AS builder
WORKDIR /app
# Copier les dependances installees
COPY --from=deps /app/node_modules ./node_modules
# Copier le code source
COPY . .
# Desactiver la telemetrie Next.js pendant le build
ENV NEXT_TELEMETRY_DISABLED=1
# Build de production
RUN npm run build
# =============================================================================
# Etape 4 : Image de production (legere)
# =============================================================================
FROM node:20-alpine AS runner
WORKDIR /app
# Mode production
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Creer un utilisateur non-root pour la securite
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copier les fichiers publics
COPY --from=builder /app/public ./public
# Copier le build standalone de Next.js
# Le mode standalone copie uniquement les fichiers necessaires
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# Utiliser l'utilisateur non-root
USER nextjs
# Exposer le port
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Healthcheck Docker
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
# Demarrer l'application
CMD ["node", "server.js"]تكوين وضع standalone في Next.js
لكي يعمل Dockerfile، يجب عليك تفعيل standalone output في تكوين Next.js:
// next.config.js (ou next.config.mjs)
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
};
module.exports = nextConfig;وضع standalone ضروري لـ Docker. بدونه، ستحتاج الصورة النهائية لكامل مجلد node_modules، مما يزيد حجمها بشكل كبير. مع standalone، ينسخ Next.js فقط الملفات اللازمة للتشغيل.
إنشاء ملف .dockerignore
أنشئ ملف .dockerignore لتجنب نسخ ملفات غير ضرورية في الصورة:
# .dockerignore
node_modules
.next
.git
.gitignore
*.md
docker-compose*.yml
.env*.local
.vscode
.idea
coverage
.huskyاختبار بناء Docker محلياً
# Construire l'image
docker build -t mon-app-nextjs .
# Verifier la taille de l'image
docker images mon-app-nextjs
# REPOSITORY TAG SIZE
# mon-app-nextjs latest ~150MB
# Lancer le conteneur
docker run -p 3000:3000 mon-app-nextjs
# Tester dans un autre terminal
curl http://localhost:3000/api/healthإذا حصلت على {"status":"healthy"}، فإن صورة Docker تعمل بشكل صحيح. يجب أن يكون الحجم بين 130 و 200 ميجابايت حسب اعتمادياتك.
الخطوة 3: تكوين Docker Compose
يسمح Docker Compose بتنسيق عدة خدمات. سنُعدّ ملفين: واحد للتطوير وآخر للإنتاج.
Docker Compose للتطوير
أنشئ docker-compose.dev.yml:
# docker-compose.dev.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
target: deps # Utiliser seulement l'etape des dependances
command: npm run dev
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules # Exclure node_modules du volume
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:Docker Compose للإنتاج
أنشئ docker-compose.prod.yml:
# docker-compose.prod.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
ports:
- "3000:3000"
env_file:
- .env.production
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
start_period: 40s
retries: 3
deploy:
resources:
limits:
memory: 512M
cpus: "0.5"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
db:
image: postgres:16-alpine
restart: unless-stopped
env_file:
- .env.production
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
memory: 256M
cache:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
deploy:
resources:
limits:
memory: 128M
volumes:
postgres_data:
redis_data:تشغيل بيئة التطوير
# Demarrer tous les services
docker compose -f docker-compose.dev.yml up -d
# Voir les logs
docker compose -f docker-compose.dev.yml logs -f app
# Arreter les services
docker compose -f docker-compose.dev.yml downالخطوة 4: تكوين خط أنابيب CI/CD مع GitHub Actions
هذا هو الجزء الأهم. سننشئ خط أنابيب يقوم بـ:
- اختبار الكود عند كل طلب سحب (pull request)
- بناء صورة Docker
- نشر تلقائي على خادم VPS عند كل دمج في فرع
main
إنشاء سير العمل الرئيسي
أنشئ ملف .github/workflows/deploy.yml:
# .github/workflows/deploy.yml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# =====================================================
# Job 1 : Linting et tests
# =====================================================
test:
name: Tests et qualite
runs-on: ubuntu-latest
steps:
- name: Checkout du code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Installer les dependances
run: npm ci
- name: Linting
run: npm run lint
- name: Tests unitaires
run: npm test -- --passWithNoTests
- name: Build de verification
run: npm run build
# =====================================================
# Job 2 : Build et push de l'image Docker
# =====================================================
build:
name: Build Docker
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout du code
uses: actions/checkout@v4
- name: Connexion au registre GitHub
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extraire les metadonnees Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=
type=raw,value=latest
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build et push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# =====================================================
# Job 3 : Deploiement sur le VPS
# =====================================================
deploy:
name: Deploiement production
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
environment:
name: production
url: https://${{ vars.DOMAIN_NAME }}
steps:
- name: Checkout du code
uses: actions/checkout@v4
- name: Deployer via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
# Se placer dans le repertoire du projet
cd /opt/apps/mon-app
# Se connecter au registre GitHub
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
# Telecharger la derniere image
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Mettre a jour le service avec zero downtime
docker compose -f docker-compose.prod.yml up -d --no-deps --wait app
# Nettoyer les anciennes images
docker image prune -f
# Verifier le healthcheck
sleep 10
curl -f http://localhost:3000/api/health || exit 1
- name: Notification de succes
if: success()
run: echo "Deploiement reussi sur ${{ vars.DOMAIN_NAME }}"
- name: Notification d'echec
if: failure()
run: echo "Echec du deploiement - verifier les logs"تكوين أسرار GitHub
انتقل إلى Settings > Secrets and variables > Actions في مستودع GitHub الخاص بك وأضف:
| السر | الوصف | مثال |
|---|---|---|
VPS_HOST | عنوان IP أو نطاق خادم VPS | 203.0.113.50 |
VPS_USER | مستخدم SSH | deploy |
VPS_SSH_KEY | المفتاح الخاص لـ SSH | محتوى ~/.ssh/id_ed25519 |
وفي المتغيرات:
| المتغير | الوصف | مثال |
|---|---|---|
DOMAIN_NAME | اسم النطاق | monapp.example.com |
لا تخزّن أبداً مفاتيح SSH أو التوكنات في الكود المصدري. استخدم أسرار GitHub حصرياً للمعلومات الحساسة. أنشئ مفتاح SSH مخصصاً للنشر باستخدام ssh-keygen -t ed25519 -C "deploy@github-actions".
الخطوة 5: تحضير خادم VPS
اتصل بخادم VPS وحضّر البيئة.
تثبيت Docker على خادم VPS
# Mise a jour du systeme
sudo apt update && sudo apt upgrade -y
# Installer Docker via le script officiel
curl -fsSL https://get.docker.com | sudo sh
# Ajouter l'utilisateur au groupe docker
sudo usermod -aG docker $USER
# Installer Docker Compose (inclus dans Docker Engine moderne)
docker compose version
# Redemarrer la session pour appliquer les permissions
exit
# Reconnectez-vousإنشاء هيكل المشروع
# Creer le repertoire de l'application
sudo mkdir -p /opt/apps/mon-app
sudo chown $USER:$USER /opt/apps/mon-app
cd /opt/apps/mon-app
# Creer le fichier d'environnement production
cat > .env.production << 'EOF'
NODE_ENV=production
DATABASE_URL=postgresql://postgres:VOTRE_MOT_DE_PASSE_FORT@db:5432/myapp
REDIS_URL=redis://cache:6379
POSTGRES_USER=postgres
POSTGRES_PASSWORD=VOTRE_MOT_DE_PASSE_FORT
POSTGRES_DB=myapp
EOF
# Proteger le fichier
chmod 600 .env.productionنسخ ملف Docker Compose
# Copier docker-compose.prod.yml sur le serveur depuis votre machine locale
scp docker-compose.prod.yml deploy@VOTRE_VPS:/opt/apps/mon-app/إنشاء مستخدم مخصص للنشر
# Creer l'utilisateur deploy
sudo adduser --disabled-password deploy
sudo usermod -aG docker deploy
# Configurer la cle SSH pour le deploiement
sudo mkdir -p /home/deploy/.ssh
sudo cp ~/.ssh/authorized_keys /home/deploy/.ssh/
# Ajoutez la cle publique generee pour GitHub Actions
echo "VOTRE_CLE_PUBLIQUE_ED25519" | sudo tee -a /home/deploy/.ssh/authorized_keys
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keysالخطوة 6: تكوين Nginx كوكيل عكسي
يوضع Nginx أمام تطبيق Next.js لإدارة SSL والتخزين المؤقت والضغط.
تثبيت Nginx و Certbot
# Installer Nginx
sudo apt install -y nginx
# Installer Certbot pour Let's Encrypt
sudo apt install -y certbot python3-certbot-nginxتكوين المضيف الافتراضي
أنشئ ملف تكوين Nginx:
# /etc/nginx/sites-available/mon-app
upstream nextjs_upstream {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 80;
server_name monapp.example.com;
# Redirection vers HTTPS (sera configure par Certbot)
location / {
return 301 https://$server_name$request_uri;
}
}
server {
listen 443 ssl http2;
server_name monapp.example.com;
# Les certificats SSL seront ajoutes par Certbot
# ssl_certificate /etc/letsencrypt/live/monapp.example.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/monapp.example.com/privkey.pem;
# En-tetes de securite
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
# Compression gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript
application/xml+rss application/atom+xml image/svg+xml;
# Cache des fichiers statiques de Next.js
location /_next/static {
proxy_pass http://nextjs_upstream;
proxy_cache_valid 60m;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Fichiers publics statiques
location /images {
proxy_pass http://nextjs_upstream;
proxy_cache_valid 60m;
add_header Cache-Control "public, max-age=86400";
}
# Proxy vers Next.js
location / {
proxy_pass http://nextjs_upstream;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}تفعيل الموقع و SSL
# Activer le site
sudo ln -s /etc/nginx/sites-available/mon-app /etc/nginx/sites-enabled/
# Verifier la configuration
sudo nginx -t
# Recharger Nginx
sudo systemctl reload nginx
# Obtenir le certificat SSL avec Certbot
sudo certbot --nginx -d monapp.example.com --non-interactive --agree-tos -m votre@email.com
# Verifier le renouvellement automatique
sudo certbot renew --dry-runسيعدّل Certbot تلقائياً تكوين Nginx لإضافة شهادات SSL. التجديد تلقائي عبر مؤقت systemd.
الخطوة 7: النشر بدون توقف
لتجنب الانقطاعات أثناء التحديثات، سنُعدّ نشراً تدريجياً.
سكربت نشر متقدم
أنشئ scripts/deploy.sh على خادم VPS:
#!/bin/bash
# scripts/deploy.sh - Deploiement avec zero downtime
set -euo pipefail
APP_DIR="/opt/apps/mon-app"
HEALTH_URL="http://localhost:3000/api/health"
MAX_RETRIES=30
RETRY_INTERVAL=2
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
check_health() {
curl -sf "$HEALTH_URL" > /dev/null 2>&1
}
cd "$APP_DIR"
log "Demarrage du deploiement..."
# Telecharger la nouvelle image
log "Telechargement de la nouvelle image..."
docker compose -f docker-compose.prod.yml pull app
# Demarrer le nouveau conteneur
log "Demarrage du nouveau conteneur..."
docker compose -f docker-compose.prod.yml up -d --no-deps app
# Attendre que le healthcheck passe
log "Verification du healthcheck..."
retries=0
until check_health; do
retries=$((retries + 1))
if [ "$retries" -ge "$MAX_RETRIES" ]; then
log "ERREUR: Le healthcheck a echoue apres $MAX_RETRIES tentatives"
log "Rollback en cours..."
docker compose -f docker-compose.prod.yml rollback app 2>/dev/null || true
exit 1
fi
log "En attente du healthcheck... ($retries/$MAX_RETRIES)"
sleep "$RETRY_INTERVAL"
done
log "Healthcheck OK"
# Nettoyer les anciennes images
docker image prune -f
log "Deploiement termine avec succes"# Rendre le script executable
chmod +x /opt/apps/mon-app/scripts/deploy.shالخطوة 8: المراقبة والسجلات
تكوين السجلات المنظمة
أضف تكوين التسجيل في تطبيق Next.js:
// lib/logger.ts
type LogLevel = "info" | "warn" | "error" | "debug";
interface LogEntry {
level: LogLevel;
message: string;
timestamp: string;
[key: string]: unknown;
}
function log(level: LogLevel, message: string, meta?: Record<string, unknown>) {
const entry: LogEntry = {
level,
message,
timestamp: new Date().toISOString(),
...meta,
};
const output = JSON.stringify(entry);
if (level === "error") {
console.error(output);
} else if (level === "warn") {
console.warn(output);
} else {
console.log(output);
}
}
export const logger = {
info: (msg: string, meta?: Record<string, unknown>) => log("info", msg, meta),
warn: (msg: string, meta?: Record<string, unknown>) => log("warn", msg, meta),
error: (msg: string, meta?: Record<string, unknown>) => log("error", msg, meta),
debug: (msg: string, meta?: Record<string, unknown>) => log("debug", msg, meta),
};أوامر مفيدة للمراقبة
# Voir les logs en temps reel
docker compose -f docker-compose.prod.yml logs -f app
# Voir les statistiques des conteneurs
docker stats
# Verifier l'etat des conteneurs
docker compose -f docker-compose.prod.yml ps
# Verifier l'utilisation disque de Docker
docker system df
# Nettoyer les ressources inutilisees
docker system prune -fإضافة فحص صحة متقدم
أثرِ endpoint الـ /api/health ليشمل مزيداً من المعلومات:
// app/api/health/route.ts
import { NextResponse } from "next/server";
export async function GET() {
const healthData = {
status: "healthy",
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: {
used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
unit: "MB",
},
version: process.env.npm_package_version || "unknown",
node: process.version,
};
return NextResponse.json(healthData);
}الخطوة 9: تأمين كل شيء
متغيرات البيئة
أنشئ ملف .env.example لتوثيق المتغيرات المطلوبة دون كشف القيم:
# .env.example - Variables d'environnement requises
NODE_ENV=production
DATABASE_URL=postgresql://user:password@db:5432/dbname
REDIS_URL=redis://cache:6379
# Base de donnees
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changez_moi
POSTGRES_DB=myapp
# Application
NEXTAUTH_SECRET=generez_un_secret_fort
NEXTAUTH_URL=https://monapp.example.comأفضل ممارسات الأمان
إليك النقاط الأساسية الواجب اتباعها:
- مستخدم غير root في الحاوية (مُعدّ مسبقاً في Dockerfile)
- أسرار GitHub لجميع المعلومات الحساسة
- شهادة SSL عبر Let's Encrypt (تجديد تلقائي)
- رؤوس أمان في Nginx (HSTS، X-Frame-Options، إلخ.)
- حدود الموارد في Docker Compose (الذاكرة، المعالج)
- سجلات منظمة لكشف الحالات الشاذة
غيّر دائماً كلمات المرور الافتراضية. استخدم openssl rand -base64 32 لتوليد أسرار قوية. لا تدفع أبداً ملفات .env إلى مستودع Git.
اختبار خط الأنابيب الكامل
إليك كيف تتحقق أن كل شيء يعمل من البداية إلى النهاية:
1. اختبار محلي مع Docker
# Build et demarrage
docker compose -f docker-compose.dev.yml up --build -d
# Verifier les logs
docker compose -f docker-compose.dev.yml logs -f
# Tester le healthcheck
curl http://localhost:3000/api/health2. اختبار خط أنابيب CI/CD
# Creer une branche de test
git checkout -b test/cicd-pipeline
# Faire un changement mineur
echo "// test" >> lib/logger.ts
# Commit et push
git add . && git commit -m "test: verify CI/CD pipeline"
git push -u origin test/cicd-pipeline
# Creer une pull request sur GitHub
gh pr create --title "Test CI/CD pipeline" --body "Verification du pipeline"3. التحقق من النشر
# Apres le merge sur main, verifier le deploiement
curl https://monapp.example.com/api/health
# Reponse attendue :
# {"status":"healthy","timestamp":"...","uptime":42,"memory":{"used":85,"total":128,"unit":"MB"}}استكشاف الأخطاء وحلها
فشل بناء Docker
| المشكلة | الحل |
|---|---|
COPY failed: file not found | تحقق أن .dockerignore لا يستبعد الملفات الضرورية |
فشل npm ci | تأكد أن package-lock.json موجود ومُحدّث |
| نفاد الذاكرة أثناء البناء | زِد ذاكرة Docker Desktop أو أضف --max-old-space-size=4096 |
فشل خط أنابيب GitHub Actions
| المشكلة | الحل |
|---|---|
| Permission denied (SSH) | تحقق أن مفتاح SSH مُعدّ بشكل صحيح في الأسرار |
| رفض دفع الصورة | تحقق من صلاحيات packages: write في سير العمل |
| انتهاء مهلة فحص الصحة | زِد start-period وتحقق من سجلات التطبيق |
النشر لا يعمل
# Verifier les logs du conteneur
docker compose -f docker-compose.prod.yml logs app --tail 50
# Verifier que les ports ne sont pas utilises
sudo ss -tulnp | grep 3000
# Redemarrer les services
docker compose -f docker-compose.prod.yml restart
# Reconstruire completement
docker compose -f docker-compose.prod.yml up -d --build --force-recreateالخطوات التالية
الآن بعد أن أصبح خط الأنابيب جاهزاً، إليك كيف تُحسّنه:
- إضافة اختبارات E2E مع Playwright في خط أنابيب CI
- تكوين إشعارات Slack أو Discord للنشر
- إعداد CDN (Cloudflare) أمام Nginx للتخزين المؤقت العالمي
- إضافة مراقبة تطبيقية مع Sentry أو Datadog
- تطبيق نشر blue/green لضمان عدم التوقف
- تكوين نسخ احتياطية تلقائية لقاعدة بيانات PostgreSQL
الخلاصة
لديك الآن بنية نشر كاملة ومهنية لتطبيق Next.js:
- Docker متعدد المراحل لصور خفيفة وآمنة
- Docker Compose لتنسيق الخدمات
- GitHub Actions للتكامل والنشر المستمر
- Nginx + SSL لوكيل عكسي آمن
- مراقبة مع فحوصات صحة وسجلات منظمة
هذه البنية مُستخدمة في الإنتاج من قبل العديد من الشركات والشركات الناشئة. إنها موثوقة وقابلة لإعادة الإنتاج وسهلة الصيانة. كل عملية دفع إلى فرع main تُطلق تلقائياً عملية نشر مُتحقق منها بفحوصات الصحة.
الأهم هو أن تبدأ بشكل بسيط وتتطور تدريجياً. انشر نسخة أساسية أولاً، ثم أضف تدريجياً طبقات المراقبة والأمان والتحسين.
ناقش مشروعك معنا
نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.
دعنا نجد أفضل الحلول لاحتياجاتك.
مقالات ذات صلة

بناء وكيل ذكاء اصطناعي مستقل باستخدام Agentic RAG و Next.js
تعلم كيف تبني وكيل ذكاء اصطناعي يقرر بشكل مستقل متى وكيف يسترجع المعلومات من قواعد البيانات المتجهية. دليل عملي شامل باستخدام Vercel AI SDK و Next.js مع أمثلة قابلة للتنفيذ.

دليل دمج روبوت الدردشة الذكي: بناء واجهات محادثة ذكية
دليل شامل لدمج روبوتات الدردشة الذكية في تطبيقاتك باستخدام OpenAI وAnthropic Claude وElevenLabs. تعلم بناء روبوتات دردشة نصية وصوتية مع Next.js.

بناء روبوت محادثة RAG باستخدام Supabase pgvector و Next.js
تعلم بناء روبوت محادثة ذكاء اصطناعي يجيب على الأسئلة باستخدام بياناتك الخاصة. يغطي هذا الدليل تضمينات المتجهات والبحث الدلالي و RAG مع Supabase و Next.js.