نشر وإدارة تطبيقات Laravel: دليل DevOps الشامل
نشر وإدارة تطبيقات Laravel: دليل DevOps الشامل
دليل تخصصي من علاء عامر – مطور ومصمم مواقع وتطبيقات محترف
نشر تطبيقات Laravel يتطلب استراتيجية شاملة تشمل الأمان والأداء والموثوقية. تعلم أحدث ممارسات DevOps للنشر الاحترافي.
4️⃣ Monitoring & Logging المتقدم
Application Monitoring Setup:
<?php
// app/Services/MonitoringService.php
namespace App\Services;
use Illuminate\Support\Facades\{Log, Redis, Http};
use Throwable;
class MonitoringService
{
private array $metrics = [];
public function trackPerformance(string $operation, callable $callback): mixed
{
$startTime = microtime(true);
$startMemory = memory_get_usage(true);
try {
$result = $callback();
$this->recordMetric($operation, [
'status' => 'success',
'execution_time' => microtime(true) - $startTime,
'memory_usage' => memory_get_usage(true) - $startMemory,
'timestamp' => now()->toISOString()
]);
return $result;
} catch (Throwable $e) {
$this->recordMetric($operation, [
'status' => 'error',
'execution_time' => microtime(true) - $startTime,
'memory_usage' => memory_get_usage(true) - $startMemory,
'error' => $e->getMessage(),
'timestamp' => now()->toISOString()
]);
throw $e;
}
}
public function recordMetric(string $name, array $data): void
{
$metric = [
'name' => $name,
'data' => $data,
'server' => gethostname(),
'environment' => app()->environment()
];
// Store in Redis for real-time monitoring
Redis::lpush('metrics:' . date('Y-m-d'), json_encode($metric));
Redis::expire('metrics:' . date('Y-m-d'), 86400 * 7); // Keep for 7 days
// Send to external monitoring service
if (config('monitoring.enabled')) {
$this->sendToExternalService($metric);
}
// Log critical metrics
if ($this->isCritical($metric)) {
Log::warning('Critical metric detected', $metric);
$this->sendAlert($metric);
}
}
public function getHealthStatus(): array
{
return [
'app' => $this->checkAppHealth(),
'database' => $this->checkDatabaseHealth(),
'redis' => $this->checkRedisHealth(),
'queue' => $this->checkQueueHealth(),
'storage' => $this->checkStorageHealth(),
'external_services' => $this->checkExternalServices()
];
}
private function checkAppHealth(): array
{
return [
'status' => 'healthy',
'version' => config('app.version'),
'environment' => app()->environment(),
'uptime' => $this->getUptime(),
'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2) . ' MB',
'load_average' => sys_getloadavg()
];
}
private function checkDatabaseHealth(): array
{
try {
\DB::connection()->getPdo();
$connectionTime = $this->measureExecutionTime(function() {
\DB::select('SELECT 1');
});
return [
'status' => 'healthy',
'connection_time' => $connectionTime . 'ms',
'active_connections' => \DB::select('SHOW PROCESSLIST') ? count(\DB::select('SHOW PROCESSLIST')) : 0
];
} catch (Throwable $e) {
return [
'status' => 'unhealthy',
'error' => $e->getMessage()
];
}
}
private function checkRedisHealth(): array
{
try {
$connectionTime = $this->measureExecutionTime(function() {
Redis::ping();
});
return [
'status' => 'healthy',
'connection_time' => $connectionTime . 'ms',
'used_memory' => Redis::info()['used_memory_human'] ?? 'unknown'
];
} catch (Throwable $e) {
return [
'status' => 'unhealthy',
'error' => $e->getMessage()
];
}
}
private function checkQueueHealth(): array
{
try {
$queueSizes = [];
$queues = ['default', 'high_priority', 'low_priority'];
foreach ($queues as $queue) {
$queueSizes[$queue] = \Queue::size($queue);
}
$failedJobs = \DB::table('failed_jobs')->count();
return [
'status' => $failedJobs > 100 ? 'warning' : 'healthy',
'queue_sizes' => $queueSizes,
'failed_jobs' => $failedJobs
];
} catch (Throwable $e) {
return [
'status' => 'unhealthy',
'error' => $e->getMessage()
];
}
}
private function checkStorageHealth(): array
{
try {
$diskSpace = disk_total_space('/');
$freeSpace = disk_free_space('/');
$usedPercentage = round((($diskSpace - $freeSpace) / $diskSpace) * 100, 2);
return [
'status' => $usedPercentage > 90 ? 'warning' : 'healthy',
'total_space' => $this->formatBytes($diskSpace),
'free_space' => $this->formatBytes($freeSpace),
'used_percentage' => $usedPercentage . '%'
];
} catch (Throwable $e) {
return [
'status' => 'unhealthy',
'error' => $e->getMessage()
];
}
}
private function checkExternalServices(): array
{
$services = [];
// Check payment gateway
if (config('services.stripe.enabled')) {
$services['stripe'] = $this->checkServiceEndpoint('https://api.stripe.com/v1/charges', [
'Authorization' => 'Bearer ' . config('services.stripe.secret')
]);
}
// Check email service
if (config('mail.mailers.smtp.host')) {
$services['email'] = $this->checkEmailService();
}
return $services;
}
private function checkServiceEndpoint(string $url, array $headers = []): array
{
try {
$startTime = microtime(true);
$response = Http::withHeaders($headers)->timeout(5)->get($url);
$responseTime = round((microtime(true) - $startTime) * 1000, 2);
return [
'status' => $response->successful() ? 'healthy' : 'unhealthy',
'response_time' => $responseTime . 'ms',
'status_code' => $response->status()
];
} catch (Throwable $e) {
return [
'status' => 'unhealthy',
'error' => $e->getMessage()
];
}
}
private function measureExecutionTime(callable $callback): float
{
$start = microtime(true);
$callback();
return round((microtime(true) - $start) * 1000, 2);
}
private function formatBytes(int $size, int $precision = 2): string
{
$units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
for ($i = 0; $size > 1024 && $i < count($units) - 1; $i++) {
$size /= 1024;
}
return round($size, $precision) . ' ' . $units[$i];
}
private function getUptime(): string
{
if (PHP_OS_FAMILY === 'Linux') {
$uptime = file_get_contents('/proc/uptime');
$uptimeSeconds = floatval(explode(' ', $uptime)[0]);
$days = floor($uptimeSeconds / 86400);
$hours = floor(($uptimeSeconds % 86400) / 3600);
$minutes = floor(($uptimeSeconds % 3600) / 60);
return "{$days}d {$hours}h {$minutes}m";
}
return 'Unknown';
}
private function isCritical(array $metric): bool
{
$data = $metric['data'];
// Check execution time
if (isset($data['execution_time']) && $data['execution_time'] > 5) {
return true;
}
// Check memory usage
if (isset($data['memory_usage']) && $data['memory_usage'] > 100 * 1024 * 1024) { // 100MB
return true;
}
// Check error status
if (isset($data['status']) && $data['status'] === 'error') {
return true;
}
return false;
}
private function sendToExternalService(array $metric): void
{
// Send to services like New Relic, DataDog, etc.
}
private function sendAlert(array $metric): void
{
// Send alert via Slack, email, SMS, etc.
}
}
// routes/web.php - Health check endpoint
Route::get('/health', function () {
$monitoringService = app(\App\Services\MonitoringService::class);
$healthStatus = $monitoringService->getHealthStatus();
$overallStatus = collect($healthStatus)->every(function ($service) {
return $service['status'] === 'healthy';
}) ? 'healthy' : 'unhealthy';
return response()->json([
'status' => $overallStatus,
'timestamp' => now()->toISOString(),
'services' => $healthStatus
], $overallStatus === 'healthy' ? 200 : 503);
});
Log Management Configuration:
<?php
// config/logging.php - إعدادات محسنة للـ logging
return [
'default' => env('LOG_CHANNEL', 'stack'),
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['daily', 'slack'],
'ignore_exceptions' => false,
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => 14,
'replace_placeholders' => true,
],
'performance' => [
'driver' => 'daily',
'path' => storage_path('logs/performance.log'),
'level' => 'info',
'days' => 7,
],
'security' => [
'driver' => 'daily',
'path' => storage_path('logs/security.log'),
'level' => 'warning',
'days' => 30,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Laravel Log',
'emoji' => ':boom:',
'level' => env('LOG_LEVEL', 'critical'),
],
'papertrail' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
],
],
'stderr' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => [
'stream' => 'php://stderr',
],
],
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
],
'errorlog' => [
'driver' => 'errorlog',
'level' => env('LOG_LEVEL', 'debug'),
],
],
];
💡 Security & Backup Strategies
Automated Backup Script:
#!/bin/bash
# backup.sh - سكريبت النسخ الاحتياطي المتقدم
# Configuration
BACKUP_DIR="/backups"
RETENTION_DAYS=30
DB_NAME="${DB_DATABASE}"
DB_USER="${DB_USERNAME}"
DB_PASS="${DB_PASSWORD}"
APP_DIR="/var/www/laravel-app"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_NAME="laravel_backup_${TIMESTAMP}"
# Create backup directory
mkdir -p "${BACKUP_DIR}/${BACKUP_NAME}"
# Database backup
echo "🔄 Creating database backup..."
mysqldump --single-transaction --routines --triggers \
-u "${DB_USER}" -p"${DB_PASS}" "${DB_NAME}" \
| gzip > "${BACKUP_DIR}/${BACKUP_NAME}/database.sql.gz"
# Application files backup
echo "🔄 Creating application backup..."
tar --exclude='node_modules' \
--exclude='vendor' \
--exclude='storage/logs' \
--exclude='storage/framework/cache' \
--exclude='storage/framework/sessions' \
--exclude='storage/framework/views' \
-czf "${BACKUP_DIR}/${BACKUP_NAME}/application.tar.gz" \
-C "$(dirname ${APP_DIR})" "$(basename ${APP_DIR})"
# Storage files backup
echo "🔄 Creating storage backup..."
tar -czf "${BACKUP_DIR}/${BACKUP_NAME}/storage.tar.gz" \
"${APP_DIR}/storage/app"
# Create backup manifest
echo "🔄 Creating backup manifest..."
cat > "${BACKUP_DIR}/${BACKUP_NAME}/manifest.json" << EOF
{
"timestamp": "${TIMESTAMP}",
"backup_name": "${BACKUP_NAME}",
"database": "${DB_NAME}",
"application_path": "${APP_DIR}",
"files": [
"database.sql.gz",
"application.tar.gz",
"storage.tar.gz"
],
"checksums": {
"database.sql.gz": "$(md5sum ${BACKUP_DIR}/${BACKUP_NAME}/database.sql.gz | cut -d' ' -f1)",
"application.tar.gz": "$(md5sum ${BACKUP_DIR}/${BACKUP_NAME}/application.tar.gz | cut -d' ' -f1)",
"storage.tar.gz": "$(md5sum ${BACKUP_DIR}/${BACKUP_NAME}/storage.tar.gz | cut -d' ' -f1)"
}
}
EOF
# Upload to cloud storage (optional)
if [ ! -z "${AWS_S3_BUCKET}" ]; then
echo "🔄 Uploading to S3..."
aws s3 sync "${BACKUP_DIR}/${BACKUP_NAME}" \
"s3://${AWS_S3_BUCKET}/backups/${BACKUP_NAME}/" \
--storage-class STANDARD_IA
fi
# Cleanup old backups
echo "🔄 Cleaning up old backups..."
find "${BACKUP_DIR}" -type d -name "laravel_backup_*" \
-mtime +${RETENTION_DAYS} -exec rm -rf {} \;
echo "✅ Backup completed: ${BACKUP_NAME}"
# Send notification
curl -X POST "${SLACK_WEBHOOK_URL}" \
-H 'Content-type: application/json' \
--data "{\"text\":\"✅ Laravel backup completed: ${BACKUP_NAME}\"}"
الخطوة النهائية
تهانينا! لقد أكملت دليل Laravel الشامل. الآن لديك المعرفة الكاملة لبناء وإدارة تطبيقات Laravel احترافية.
المراجع والموارد الإضافية
📩 هل تحتاج استشارة متقدمة في Laravel؟
قسم المقالة
نشر وإدارة تطبيقات Laravel: دليل DevOps الشامل
دليل متكامل لنشر تطبيقات Laravel على الخوادم، من الإعداد الأساسي إلى استراتيجيات CI/CD المتقدمة والمراقبة المستمرة.
التواصل والاستشارة
تواصل مباشر عبر الواتساب أو الهاتف لفهم احتياجات مشروعك بدقة.
التخطيط والجدولة
وضع خطة عمل واضحة مع جدول زمني محدد لكل مرحلة من المشروع.
البرمجة والتطوير
تطوير المشروع بأحدث التقنيات لضمان الأداء والأمان العاليين.
المراجعة والتسليم
ختبار شامل ومراجعة دقيقة قبل التسليم النهائي للمشروع.