Kotlin: شرح نشر مشروع كوتلن

آخر تحديث: 2026-08-26

الكود مكتوب — الآن المحطة الأخيرة. يقوم تشارلي بتحويل OrderProcessor إلى حاويات، وينسق خط أنابيب CI/CD، ويضبط المراقبة والتنبيهات، مما يجعل النشر من git push إلى الإنتاج مؤتمتًا بالكامل.

1. ما ستتعلمه


2. قصة حقيقية لمهندس معماري

(1) المشكلة: خط نشر يدوي

كان فريق تشارلي ينشر يدويًا: SSH إلى الخادم → git pullgradle buildjava -jarsystemctl restart. كانت عملية النشر الواحدة تستغرق 30 دقيقة، مع حدوث 2-3 أخطاء بشرية شهريًا.

(2) حل CI/CD مؤتمت بالكامل

TEXT 📖 للعرض فقط
Before: git push → SSH → build → deploy (30 min, error-prone)
After:  git push → GitHub Actions → Docker build → deploy (5 min, zero-touch)

التحويل إلى حاويات + CI/CD = يتحول النشر من 30 دقيقة من الجهد اليدوي إلى خط أنابيب مؤتمت بالكامل في 5 دقائق.


3. البناء متعدد المراحل في Docker

(1) Dockerfile

DOCKERFILE
# المرحلة 1: البناء
FROM gradle:8.5-jdk17 AS builder
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
COPY src ./src
RUN gradle bootJar --no-daemon -x test

# المرحلة 2: التشغيل (JRE خفيف)
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar

# مستخدم غير جذر للأمان
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "-jar", "app.jar"]

(2) مقارنة بين البناء متعدد المراحل والمرحلة الواحدة

البُعد مرحلة واحدة متعدد المراحل
حجم الصورة ~800 ميجابايت (JDK + المصدر) ~150 ميجابايت (JRE فقط)
الأمان المصدر موجود في الصورة المصدر غير موجود في صورة التشغيل
تخزين البناء المؤقت بدون طبقات تخزين مؤقت مستقل لكل مرحلة
وقت البناء إعادة بناء كاملة كل مرة إعادة استخدام طبقة التبعيات المخزنة مؤقتًا

4. تنسيق Docker Compose

(1) docker-compose.yml

YAML
version: '3.8'

services:
  order-processor:
    build: .
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=r2dbc:postgresql://postgres:5432/orderdb
      - SPRING_DATASOURCE_USERNAME=order_user
      - SPRING_DATASOURCE_PASSWORD=order_pass
      - SPRING_REDIS_HOST=redis
      - MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE=health,info,prometheus
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - order-net

  postgres:
    image: postgres:16-alpine
    environment:
      - POSTGRES_DB=orderdb
      - POSTGRES_USER=order_user
      - POSTGRES_PASSWORD=order_pass
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U order_user -d orderdb"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - order-net

  redis:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
    networks:
      - order-net

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"
    networks:
      - order-net

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    depends_on:
      - prometheus
    networks:
      - order-net

volumes:
  pgdata:

networks:
  order-net:
    driver: bridge

(2) نشر بنقرة واحدة

BASH
# بدء جميع الخدمات
docker-compose up -d

# التحقق من الحالة
docker-compose ps

# عرض السجلات
docker-compose logs -f order-processor

# إيقاف الكل
docker-compose down

5. خط أنابيب CI/CD

(1) GitHub Actions

YAML
# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Cache Gradle
        uses: actions/cache@v3
        with:
          path: ~/.gradle/caches
          key: gradle-${{ hashFiles('**/*.gradle.kts') }}

      - name: Run tests
        run: ./gradlew test

      - name: Build JAR
        run: ./gradlew bootJar

      - name: Build Docker image
        run: docker build -t order-processor:${{ github.sha }} .

      - name: Push to registry
        if: github.ref == 'refs/heads/main'
        run: |
          docker tag order-processor:${{ github.sha }} registry.example.com/order-processor:latest
          docker push registry.example.com/order-processor:latest

      - name: Deploy
        if: github.ref == 'refs/heads/main'
        run: |
          ssh deploy@prod-server "docker pull registry.example.com/order-processor:latest && docker-compose up -d"

(2) مخطط خط أنابيب CI/CD

100%
flowchart TD
    A[git push] --> B[GitHub Actions]
    B --> C[Checkout Code]
    C --> D[Setup JDK 17]
    D --> E[Cache Gradle]
    E --> F[Run Tests]
    F --> G{Tests Pass?}
    G -->|Yes| H[Build JAR]
    G -->|No| I[Notify Team]
    H --> J[Build Docker Image]
    J --> K{Main Branch?}
    K -->|Yes| L[Push to Registry]
    K -->|No| M[Stop]
    L --> N[Deploy to Production]
    N --> O[Health Check]
    O --> P{Healthy?}
    P -->|Yes| Q[Live]
    P -->|No| R[Rollback]

6. المراقبة

(1) إعدادات Spring Boot Actuator

KOTLIN
// application.yml
// management:
//   endpoints:
//     web:
//       exposure:
//         include: health,info,prometheus,metrics
//   metrics:
//     export:
//       prometheus:
//         enabled: true
//   endpoint:
//     health:
//       show-details: always

(2) مقاييس مخصصة باستخدام Micrometer

KOTLIN
import io.micrometer.core.instrument.Counter
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Timer

class OrderMetrics(registry: MeterRegistry) {
    private val ordersCreated = Counter.builder("orders.created.total")
        .description("Total orders created")
        .register(registry)

    private val orderProcessingTime = Timer.builder("orders.processing.time")
        .description("Order processing time")
        .register(registry)

    fun recordOrderCreated() { ordersCreated.increment() }

    fun <T> recordProcessingTime(block: () -> T): T {
        return orderProcessingTime.recordCallable { block() } ?: block()
    }
}

(3) مقاييس المراقبة

المقياس النوع حد التنبيه
orders_created_total عداد
orders_processing_time مؤقت P99 > 2 ثانية
jvm_memory_used_bytes مقياس > 80%
db_connection_pool_active مقياس > 90%
http_server_requests_seconds مؤقت P99 > 5 ثوانٍ
disk_free_bytes / disk_total_bytes مقياس المساحة الحرة < 10%

7. فحوصات الصحة وجاهزية الإنتاج

(1) نقطة نهاية فحص الصحة

KOTLIN
// نقطة نهاية فحص صحة Spring Boot Actuator
// GET /actuator/health
// {
//   "status": "UP",
//   "components": {
//     "db": { "status": "UP" },
//     "redis": { "status": "UP" },
//     "diskSpace": { "status": "UP" }
//   }
// }

(2) قائمة جاهزية الإنتاج

الفئة عنصر الفحص الحالة
الأمان تشغيل بمستخدم غير جذر
الأمان لا أسرار مشفرة في الكود
الأمان HTTPS مُعد
الموثوقية نقطة نهاية فحص الصحة
الموثوقية إيقاف سلس (SIGTERM)
الموثوقية تجمع اتصالات قاعدة البيانات مُعد
القابلية للرصد مخرجات تسجيل مهيكلة
القابلية للرصد مقاييس Prometheus مكشوفة
القابلية للرصد قواعد التنبيه مُعدة
الأداء حجم كومة JVM مُعد
الأداء استراتيجية GC محددة
النشر صورة Docker < 200 ميجابايت
النشر خط أنابيب CI/CD
النشر استراتيجية التراجع

8. مثال كامل: عرض نشر بنقرة واحدة

KOTLIN
// ============================================
// OrderProcessor - محاكاة النشر
// الميزة: عرض Docker + CI/CD + فحص الصحة
// ============================================

import kotlin.system.measureTimeMillis

data class DeployResult(val service: String, val status: String, val time: Long)

class DeploySimulator {
    private val services = mutableListOf<DeployResult>()
    private var deployed = false

    fun build(): DeploySimulator {
        print("  Building Docker image...")
        val time = measureTimeMillis { Thread.sleep(800) }
        println(" Done (${time}ms)")
        return this
    }

    fun test(): DeploySimulator {
        print("  Running tests...")
        val time = measureTimeMillis { Thread.sleep(300) }
        println(" Passed (${time}ms)")
        return this
    }

    fun push(): DeploySimulator {
        print("  Pushing to registry...")
        val time = measureTimeMillis { Thread.sleep(500) }
        println(" Done (${time}ms)")
        return this
    }

    fun deploy(service: String, port: Int): DeploySimulator {
        print("  Deploying $service on port $port...")
        val time = measureTimeMillis { Thread.sleep(400) }
        services.add(DeployResult(service, "RUNNING", time))
        println(" Running (${time}ms)")
        return this
    }

    fun healthCheck(): DeploySimulator {
        print("  Health check...")
        val time = measureTimeMillis { Thread.sleep(200) }
        val allHealthy = services.all { it.status == "RUNNING" }
        println(if (allHealthy) " ALL HEALTHY" else " UNHEALTHY DETECTED")
        return this
    }

    fun summary() {
        println("\n=== Deployment Summary ===")
        services.forEach { s ->
            println("  ${s.service}: ${s.status} (${s.time}ms)")
        }
        println("\n  Total services: ${services.size}")
        println("  Health: ${if (services.all { it.status == "RUNNING" }) "ALL GREEN" else "ISSUES DETECTED"}")
        deployed = true
    }

    fun isDeployed() = deployed
}

fun main() {
    println("=== OrderProcessor CI/CD Pipeline ===\n")

    println("[1/6] Build Stage:")
    DeploySimulator()
        .build()
        .test()

    println("\n[2/6] Push Stage:")
    DeploySimulator().push()

    println("\n[3/6] Deploy Stage:")
    val deployer = DeploySimulator()
        .deploy("postgres", 5432)
        .deploy("redis", 6379)
        .deploy("order-processor", 8080)
        .deploy("prometheus", 9090)
        .deploy("grafana", 3000)

    println("\n[4/6] Health Check:")
    deployer.healthCheck()

    println("\n[5/6] Smoke Test:")
    println("  GET /actuator/health -> 200 OK")
    println("  GET /api/v1/orders -> 200 OK")

    println("\n[6/6] Production Ready Checklist:")
    val checks = listOf(
        "Non-root user" to true,
        "No hardcoded secrets" to true,
        "Health endpoint exposed" to true,
        "Prometheus metrics enabled" to true,
        "Graceful shutdown configured" to true,
        "Docker image < 200MB" to true,
        "CI/CD pipeline active" to true,
        "Rollback strategy defined" to true
    )
    checks.forEach { (item, passed) ->
        println("  ${if (passed) "✅" else "❌"} $item")
    }

    val passCount = checks.count { it.second }
    println("\n  Result: $passCount/${checks.size} checks passed")

    if (passCount == checks.size) {
        println("\n  🚀 OrderProcessor is LIVE!")
    }
}

المخرجات:

TEXT 📖 للعرض فقط
=== OrderProcessor CI/CD Pipeline ===

[1/6] Build Stage:
  Building Docker image... Done (804ms)
  Running tests... Passed (301ms)

[2/6] Push Stage:
  Pushing to registry... Done (502ms)

[3/6] Deploy Stage:
  Deploying postgres on port 5432... Running (401ms)
  Deploying redis on port 6379... Running (401ms)
  Deploying order-processor on port 8080... Running (401ms)
  Deploying prometheus on port 9090... Running (401ms)
  Deploying grafana on port 3000... Running (401ms)

[4/6] Health Check:
  Health check... ALL HEALTHY

[5/6] Smoke Test:
  GET /actuator/health -> 200 OK
  GET /api/v1/orders -> 200 OK

[6/6] Production Ready Checklist:
  ✅ Non-root user
  ✅ No hardcoded secrets
  ✅ Health endpoint exposed
  ✅ Prometheus metrics enabled
  ✅ Graceful shutdown configured
  ✅ Docker image < 200MB
  ✅ CI/CD pipeline active
  ✅ Rollback strategy defined

  Result: 8/8 checks passed

  🚀 OrderProcessor is LIVE!

9. أمثلة عملية سريعة

▶ مثال: Dockerfile بسيط

DOCKERFILE
# Stage 1: بناء
FROM gradle:8.5-jdk17-alpine AS builder
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
RUN gradle dependencies --no-daemon

COPY src ./src
RUN gradle build -x test --no-daemon

# Stage 2: تشغيل
FROM eclipse-temurin:17-jre-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar

EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -q --spider http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "-jar", "/app/app.jar"]
BASH
# بناء الصورة
docker build -t order-processor:1.0.0 .

# تشغيل محلي
docker run -d -p 8080:8080 \
  -e SPRING_DATASOURCE_URL=jdbc:postgresql://host:5432/orders \
  -e SPRING_DATASOURCE_PASSWORD=secret \
  --name order-processor \
  order-processor:1.0.0

**الإخراج:

TEXT 📖 للعرض فقط
Successfully built and tagged order-processor:1.0.0
Container order-processor started

▶ مثال: Docker Compose متعدد الخدمات

YAML
# docker-compose.yml
version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: orders
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme}
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s

  order-processor:
    build: .
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      SPRING_PROFILES_ACTIVE: docker
      SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/orders
      SPRING_DATASOURCE_USERNAME: app
      SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD:-changeme}
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
    ports:
      - "8080:8080"

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

volumes:
  postgres-data:
BASH
# تشغيل كل الخدمات
docker-compose up -d

# عرض السجلات
docker-compose logs -f order-processor

# إيقاف وحذف
docker-compose down -v

**الإخراج:

TEXT 📖 للعرض فقط
order-processor  | Started OrderProcessorApplication
postgres        | database system is ready to accept connections

▶ مثال: GitHub Actions CI/CD

YAML
# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'

      - name: Run tests
        run: ./gradlew test

      - name: Build
        run: ./gradlew build

  build-and-push:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
    steps:
      - uses: actions/checkout@v4

      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ secrets.REGISTRY }}
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_PASSWORD }}

      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ${{ secrets.REGISTRY }}/order-processor:${{ github.sha }}
            ${{ secrets.REGISTRY }}/order-processor:latest

  deploy:
    needs: build-and-push
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Production
        run: |
          echo "Deploying ${{ github.ref_name }} to production"
          kubectl set image deployment/order-processor \
            order-processor=${{ secrets.REGISTRY }}/order-processor:${{ github.sha }}
          kubectl rollout status deployment/order-processor

**الإخراج:

TEXT 📖 للعرض فقط
✓ Tests passed
✓ Image built and pushed: registry.example.com/order-processor:abc123
✓ Deployment updated

▶ مثال: Kubernetes Deployment

YAML
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-processor
  labels:
    app: order-processor
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-processor
  template:
    metadata:
      labels:
        app: order-processor
    spec:
      containers:
        - name: order-processor
          image: registry.example.com/order-processor:1.0.0
          ports:
            - containerPort: 8080
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: production
            - name: SPRING_DATASOURCE_URL
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: url
            - name: SPRING_DATASOURCE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: password
          resources:
            requests:
              cpu: "500m"
              memory: "512Mi"
            limits:
              cpu: "1000m"
              memory: "1Gi"
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: order-processor
spec:
  selector:
    app: order-processor
  ports:
    - port: 80
      targetPort: 8080
  type: LoadBalancer
BASH
kubectl apply -f k8s/deployment.yaml
kubectl get pods -l app=order-processor
kubectl logs -f deployment/order-processor

**الإخراج:

TEXT 📖 للعرض فقط
NAME                              READY   STATUS    RESTARTS   AGE
order-processor-7d8f9c5b6-abc12   1/1     Running   0          2m
order-processor-7d8f9c5b6-def34   1/1     Running   0          2m
order-processor-7d8f9c5b6-ghi56   1/1     Running   0          2m

▶ مثال: Health Checks و Metrics

KOTLIN
import org.springframework.boot.actuate.health.Health
import org.springframework.boot.actuate.health.HealthIndicator
import org.springframework.stereotype.Component
import org.springframework.web.bind.annotation.*

@Component
class DatabaseHealthIndicator(
    private val dataSource: javax.sql.DataSource
) : HealthIndicator {
    override fun health(): Health {
        return try {
            dataSource.connection.use { conn ->
                if (conn.isValid(1)) Health.up().build()
                else Health.down().withDetail("reason", "Connection invalid").build()
            }
        } catch (e: Exception) {
            Health.down(e).build()
        }
    }
}

@Component
class OrderProcessorHealthIndicator {
    var ordersProcessed: Long = 0
    var lastProcessedAt: Long = 0

    fun health(): Health =
        if (ordersProcessed > 0 && (System.currentTimeMillis() - lastProcessedAt) < 60_000) {
            Health.up()
                .withDetail("ordersProcessed", ordersProcessed)
                .withDetail("lastProcessedAt", lastProcessedAt)
                .build()
        } else {
            Health.down().withDetail("reason", "No recent activity").build()
        }
}

// Prometheus metrics
import io.micrometer.core.instrument.*

@Component
class OrderMetrics(private val registry: MeterRegistry) {
    private val ordersCounter: Counter = Counter.builder("orders.processed.total")
        .description("Total orders processed")
        .register(registry)

    private val processingTimer: Timer = Timer.builder("orders.processing.duration")
        .description("Order processing duration")
        .register(registry)

    fun recordOrder() = ordersCounter.increment()

    fun recordProcessing(durationNanos: Long) = processingTimer.record(durationNanos, java.util.concurrent.TimeUnit.NANOSECONDS)
}

**الإخراج:

TEXT 📖 للعرض فقط
GET /actuator/health
{
    "status": "UP",
    "components": {
        "db": {"status": "UP"},
        "orderProcessor": {"status": "UP", "details": {...}}
    }
}

▶ مثال: Blue-Green Deployment

BASH
#!/bin/bash
# blue-green-deploy.sh

set -e

# الإعدادات
NEW_VERSION=${1:-1.0.0}
CURRENT=$(kubectl get service order-processor -o jsonpath='{.spec.selector.version}')

echo "Current version: $CURRENT"
echo "Deploying version: $NEW_VERSION"

# قرر: الانتشار إلى Blue أو Green
if [ "$CURRENT" == "blue" ]; then
    TARGET="green"
else
    TARGET="blue"
fi

echo "Deploying to $TARGET environment"

# 1. نشر النسخة الجديدة إلى البيئة المستهدفة
kubectl apply -f k8s/deployment-$TARGET.yaml
kubectl set image deployment/order-processor-$TARGET \
    order-processor=registry/order-processor:$NEW_VERSION

# 2. انتظار الجاهزية
echo "Waiting for $TARGET to be ready..."
kubectl rollout status deployment/order-processor-$TARGET --timeout=5m

# 3. فحص الصحة
sleep 30  # انتظار للاستقرار
if ! curl -sf http://order-processor-$TARGET:8080/actuator/health > /dev/null; then
    echo "Health check failed! Rolling back..."
    kubectl delete deployment order-processor-$TARGET
    exit 1
fi

# 4. تبديل Service إلى البيئة الجديدة
kubectl patch service order-processor \
    -p "{\"spec\":{\"selector\":{\"version\":\"$TARGET\"}}}"

echo "Successfully switched to $TARGET (v$NEW_VERSION)"

# 5. حذف البيئة القديمة بعد فترة سماح
sleep 300
kubectl delete deployment order-processor-$CURRENT

**الإخراج:

TEXT 📖 للعرض فقط
Current version: blue
Deploying version: 1.0.1
Deploying to green environment
Waiting for green to be ready...
deployment "order-processor-green" successfully rolled out
Successfully switched to green (v1.0.1)

▶ مثال: إدارة الأسرار

BASH
# ❌ سيء: أسرار في نص عادي
# .env
DB_PASSWORD=mysecretpassword123
API_KEY=sk-abc123def456

# ✅ جيد: استخدام Kubernetes Secrets
kubectl create secret generic db-credentials \
    --from-literal=url=jdbc:postgresql://db:5432/orders \
    --from-literal=username=app \
    --from-literal=password=mysecretpassword123
YAML
# في deployment.yaml - مرجع السر
env:
  - name: SPRING_DATASOURCE_PASSWORD
    valueFrom:
      secretKeyRef:
        name: db-credentials
        key: password
KOTLIN
// في الكود - قراءة من متغير البيئة
@Configuration
class SecurityConfig {
    @Value("\${SPRING_DATASOURCE_PASSWORD}")
    lateinit var dbPassword: String
}

**الإخراج:

TEXT 📖 للعرض فقط
Secret db-credentials created
Deployment using secret via valueFrom

❓ أسئلة شائعة

س ما فوائد البناء متعدد المراحل في Docker؟
ج الصورة النهائية تحتوي فقط على تبعيات التشغيل (JRE) — بدون كود مصدر أو أدوات بناء. يتقلص حجم الصورة من 800 ميجابايت إلى 150 ميجابايت، مع سطح هجوم أصغر وبدء تشغيل أسرع.
س كيف يمكن تحقيق نشر بدون توقف؟
ج النشر الأزرق-الأخضر أو التحديثات المتدرجة. النشر الأزرق-الأخضر يحافظ على بيئتين وبدل بينهما. التحديثات المتدرجة تستبدل النسخ واحدة تلو الأخرى. Kubernetes يدعم التحديثات المتدرجة بشكل أصلي.
س كيف يمكن التراجع عن نشر فاشل؟
ج ضع علامة على كل بناء صورة Docker بـ Git SHA، ثم تراجع ببساطة عبر docker run registry.example.com/order-processor:<previous-sha>. التراجع المؤتمت عبر CI/CD أفضل حتى.
س كيف تُدار الأسرار؟
ج لا تخزن الأسرار أبدًا في متغيرات البيئة أو ملفات الإعدادات. استخدم Vault أو AWS Secrets Manager أو Kubernetes Secrets. يقوم CI/CD بحقنها من مدير الأسرار.
س كيف تُراقب تطبيقات JVM؟
ج Spring Boot Actuator + Micrometer + Prometheus + Grafana هو المزيج القياسي. مقاييس JVM المحددة: ذاكرة الكومة، عدد/وقت GC، عدد الخيوط.
س كيف تُعد معاملات JVM للإنتاج؟
ج عيّن -Xms و -Xmx لنفس القيمة (تجنب عبء تغيير حجم الكومة). استخدم G1GC (-XX:+UseG1GC). في الحاويات، أضف -XX:+UseContainerSupport.

📖 ملخص


📝 تمارين

  1. مبتدئ (⭐): اكتب Dockerfile لـ OrderProcessor (مرحلة واحدة تكفي)، مبني على eclipse-temurin:17-jre. تلميح: COPY build/libs/*.jar app.jar
  2. متوسط (⭐⭐): اكتب docker-compose.yml يحتوي على OrderProcessor + PostgreSQL مع فحوصات الصحة مُعدة. تلميح: depends_on مع condition: service_healthy
  3. متقدم (⭐⭐⭐): اكتب خط أنابيب CI/CD كامل في GitHub Actions يتضمن خطوات البناء والاختبار ودفع Docker والنشر. تلميح: on: push: branches: [main]

← السابق | التالي →

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%