← Kursa Dön
📄 Text · 30 min

CD Pipeline

Giriş — Kodun Yaşam Döngüsünün Son Durağı

CI pipeline'ın mükemmel çalışıyor: Her PR lint'ten geçiyor, testler yeşil, build başarılı. Harika. Ama kodun hâlâ GitHub'da duruyor. Kullanıcılar onu göremez, dokunamaz, kullanamaz. Deploy — yani kodun canlıya alınması — pipeline'ın en heyecanlı ve en riskli adımıdır.

"Deploy günü" bir zamanlar tüm ekibin stres yaşadığı, herkesin nefesini tuttuğu bir olaydı. CD (Continuous Deployment/Delivery) bu stresi ortadan kaldırır. Kodun main'e merge edildiği anda — veya bir butonla — otomatik olarak canlıya çıkar. Gece yarısı deploy'larına, "deploy freeze" dönemlerine, "şu an olmaz, cuma deploy yaparız" cümlelerine son.

Bu derste GitHub Actions ile deploy pipeline'ları kurmayı, environment'lar ile ortam yönetimini, approval gate'ler ile güvenli deploy akışını, rollback stratejileri ile geri alma senaryolarını ve popüler platformlara (Vercel, Netlify, AWS) deploy etmeyi öğreneceksin.


🎬 Analoji: Uzay Mekiği Fırlatma

Bir uzay mekiği fırlatılırken birden fazla aşama var:

  1. Montaj (CI): Roket parçaları kontrol edilir, testler yapılır

  2. Yakıt doldurma (Build): Roket fırlatmaya hazır hale getirilir

  3. Test fırlatması (Staging): Küçük bir roketle deneme yapılır

  4. Fırlatma onayı (Approval Gate): "Go / No-go" kararı verilir

  5. Fırlatma (Production Deploy): Roket uzaya fırlatılır

  6. Acil durum planı (Rollback): Sorun olursa inişe geç

CD Pipeline = Uzay Fırlatma Protokolü

  ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
  │ 🔧 CI    │───►│ 🚀 Stage │───►│ ✋ Onay   │───►│ 🌍 Prod  │
  │ (Kontrol)│    │ (Test    │    │ (Review  │    │ (Canlı)  │
  │          │    │  uçuşu)  │    │  Gate)   │    │          │
  └──────────┘    └──────────┘    └──────────┘    └──────────┘
                                                       │
                                                  ┌────▼─────┐
                                                  │ 🔄 Rollback│
                                                  │ (Acil     │
                                                  │  durum)   │
                                                  └──────────┘

CD Kavramı: Delivery vs Deployment

Önceki derste kısaca değinmiştik, şimdi pratiğe dökme zamanı:

Continuous Delivery

Kod → CI → Staging Deploy (otomatik) → Production Deploy (MANUEL)
                                            │
                                      [Deploy butonu]
                                      İnsan kararı gerekir

Ne zaman tercih edilir?

  • Finansal uygulamalar (düzenleyici uyumluluk)

  • Büyük kullanıcı tabanı olan ürünler

  • Deploy'un iş etkisi yüksek olan durumlar

Continuous Deployment

Kod → CI → Staging Deploy (otomatik) → Production Deploy (OTOMATİK)
                                            │
                                      Pipeline başarılıysa
                                      otomatik deploy olur

Ne zaman tercih edilir?

  • SaaS uygulamaları

  • Microservice mimarileri

  • Güçlü test süiti olan projeler

  • Günde 10+ deploy yapan ekipler

Şirket Örnekleri:
┌──────────────────┬────────────────────────┐
│ Şirket           │ Deploy Sıklığı         │
├──────────────────┼────────────────────────┤
│ Amazon           │ Her 11 saniyede 1      │
│ Netflix          │ Günde 100+             │
│ Etsy             │ Günde 50+              │
│ GitHub           │ Günde 20+              │
│ Facebook         │ Günde 2 (monorepo)     │
│ Geleneksel şirket│ Ayda 1 (şanslıysan)   │
└──────────────────┴────────────────────────┘

GitHub Environments — Ortam Yönetimi

GitHub Environments, deploy hedeflerini yönetmek için bir katman sağlar. Her environment'ın kendi secret'ları, koruma kuralları ve deploy logları olabilir.

Environment Oluşturma

GitHub → Repository → Settings → Environments

"New environment" → İsim: "staging"
"New environment" → İsim: "production"

Environment Koruma Kuralları

production environment ayarları:

☑ Required reviewers
  → tolgahan, tech-lead  (bu kişiler onay vermeli)

☑ Wait timer
  → 5 minutes  (deploy öncesi 5 dakika bekle)

☐ Restrict to specific branches
  → main  (sadece main branch'ten deploy edilebilir)

Environment secrets:
  → AWS_ACCESS_KEY_ID: AKIA...
  → AWS_SECRET_ACCESS_KEY: xxxxx
  → DEPLOY_URL: https://api.production.com

Workflow'da Environment Kullanma

jobs:
  deploy-staging:
    name: 🚀 Deploy to Staging
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.myapp.com    # Deploy URL (PR'da görünür)

    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
      - name: Deploy to staging
        run: |
          echo "Deploying to staging..."
          # deploy komutu
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}  # staging secret'ı

  deploy-production:
    name: 🌍 Deploy to Production
    runs-on: ubuntu-latest
    needs: deploy-staging
    environment:
      name: production              # Approval gate burada devreye girer
      url: https://myapp.com

    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
      - name: Deploy to production
        run: |
          echo "Deploying to production..."
          # deploy komutu
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}  # production secret'ı

💡 İpucu: Environment secret'ları, repo secret'larından ayrıdır. staging environment'ına eklediğin bir secret, production job'unda erişilemez. Bu, yanlışlıkla production API key'ini staging'de kullanmanı engeller.

Approval Gate Akışı

Developer: main'e merge etti
    │
    ▼
┌──────────────────┐
│ deploy-staging   │  Otomatik çalışır
│ ✅ Başarılı       │
└────────┬─────────┘
         │
         ▼
┌──────────────────────────────────────────┐
│ deploy-production                         │
│                                          │
│ ⏳ Waiting for approval...               │
│                                          │
│ Required reviewers:                      │
│   tolgahan (pending)                     │
│   tech-lead (pending)                    │
│                                          │
│ [Approve and deploy] [Reject]            │
└──────────────────────────────────────────┘
         │
    Onay verildi ✅
         │
         ▼
┌──────────────────┐
│ deploy-production│
│ 🚀 Deploying...  │
│ ✅ Deployed!      │
└──────────────────┘

Vercel'e Deploy

Vercel, Next.js ve frontend projeleri için en popüler hosting platformlarından biri. GitHub entegrasyonu son derece kolay.

Yöntem 1: Vercel GitHub Entegrasyonu (Önerilen)

Vercel'in kendi GitHub App'ini kullanmak en kolay yoldur:

1. vercel.com'da hesap aç
2. "Import Project" → GitHub repo'nu seç
3. Framework preset: Next.js (veya uygun olanı)
4. "Deploy"

Bu kadar! Artık:
- Her push → preview deploy (benzersiz URL)
- main'e merge → production deploy
- PR'larda preview URL otomatik yorum olarak eklenir

Yöntem 2: GitHub Actions ile Vercel Deploy

Daha fazla kontrol istersen:

name: Deploy to Vercel

on:
  push:
    branches: [main]

env:
  VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: ${{ steps.deploy.outputs.url }}

    steps:
      - uses: actions/checkout@v4

      - name: Install Vercel CLI
        run: npm install --global vercel@latest

      - name: Pull Vercel Environment
        run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}

      - name: Build
        run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}

      - name: Deploy
        id: deploy
        run: |
          URL=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }})
          echo "url=$URL" >> $GITHUB_OUTPUT
          echo "Deployed to: $URL"

Netlify'a Deploy

Netlify, static siteler ve JAMstack projeleri için popüler bir platform.

GitHub Actions ile Netlify Deploy

name: Deploy to Netlify

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: ${{ steps.deploy.outputs.deploy-url }}

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci
      - run: npm run build

      - name: Deploy to Netlify
        id: deploy
        uses: nwtgck/actions-netlify@v3
        with:
          publish-dir: './dist'
          production-branch: main
          production-deploy: true
          deploy-message: "Deploy from GitHub Actions - ${{ github.sha }}"
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

AWS'ye Deploy

AWS deploy senaryoları daha çeşitlidir: S3 + CloudFront (static site), Elastic Beanstalk, ECS, Lambda...

S3 + CloudFront Deploy (Static Site)

name: Deploy to AWS S3

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production

    permissions:
      id-token: write    # OIDC token için
      contents: read

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci
      - run: npm run build

      # AWS credentials (OIDC — en güvenli yol)
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
          aws-region: eu-west-1

      # S3'e yükle
      - name: Deploy to S3
        run: |
          aws s3 sync dist/ s3://my-website-bucket \
            --delete \
            --cache-control "public, max-age=31536000"

      # CloudFront cache'ini temizle
      - name: Invalidate CloudFront
        run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CF_DISTRIBUTION_ID }} \
            --paths "/*"

Docker ile ECS Deploy

name: Deploy to ECS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: eu-west-1

      - name: Login to ECR
        id: ecr-login
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build and push Docker image
        env:
          REGISTRY: ${{ steps.ecr-login.outputs.registry }}
          REPOSITORY: my-app
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $REGISTRY/$REPOSITORY:$IMAGE_TAG .
          docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
          echo "image=$REGISTRY/$REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

      - name: Deploy to ECS
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: task-definition.json
          service: my-service
          cluster: my-cluster
          wait-for-service-stability: true

GitHub Pages Deploy

En basit deploy: Static siteyi GitHub Pages'e yayınla.

name: Deploy to GitHub Pages

on:
  push:
    branches: [main]

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages
  cancel-in-progress: false

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

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci
      - run: npm run build

      - name: Upload Pages artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: dist/

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

Rollback Stratejileri

Deploy her zaman başarılı olmaz. Bir hata canlıya çıkabilir. Rollback planın hazır olmalı.

Strateji 1: Git Revert

En basit yöntem — hatalı commit'i revert et, pipeline tekrar çalışsın:

# Hatalı deploy oldu! Geri al:
$ git revert HEAD          # Son commit'i revert et
$ git push origin main     # Pipeline tekrar çalışır → eski koda deploy olur

# Birden fazla commit'i revert etmek gerekiyorsa:
$ git revert HEAD~3..HEAD  # Son 3 commit'i revert et
Avantajları:
  ✅ Basit, herkes yapabilir
  ✅ Git tarihçesinde görünür
  ✅ Normal pipeline üzerinden çalışır

Dezavantajları:
  ❌ Pipeline tekrar çalışması gerekir (5-10 dk)
  ❌ Revert commit'leri tarihçeyi kirletir

Strateji 2: Önceki Artifact'tan Re-deploy

Build artifact'ını saklıyorsan, eski build'i yeniden deploy edebilirsin:

name: Rollback

on:
  workflow_dispatch:
    inputs:
      run_id:
        description: 'Rollback yapılacak workflow run ID'
        required: true
        type: string

jobs:
  rollback:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Download previous artifact
        uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/
          run-id: ${{ inputs.run_id }}
          github-token: ${{ secrets.GITHUB_TOKEN }}

      - name: Deploy previous version
        run: |
          echo "Rolling back to run ${{ inputs.run_id }}..."
          # deploy komutu (eski artifact'ı deploy et)

Strateji 3: Versiyon Tag ile Rollback

# Her deploy'da tag oluştur:
$ git tag -a v1.2.3 -m "Release 1.2.3"
$ git push origin v1.2.3

# Rollback gerektiğinde:
$ git checkout v1.2.2     # Önceki versiyona git
# veya workflow_dispatch ile v1.2.2 tag'ini deploy et
name: Deploy by Tag

on:
  workflow_dispatch:
    inputs:
      tag:
        description: 'Deploy edilecek tag (ör: v1.2.3)'
        required: true
        type: string

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ inputs.tag }}    # Belirtilen tag'i checkout et

      - run: npm ci
      - run: npm run build
      - name: Deploy
        run: echo "Deploying ${{ inputs.tag }}..."

Strateji 4: Blue-Green Deployment

İki ortam (blue ve green) arasında geçiş yapma:

Blue-Green Deploy:

    İlk durum:
    ┌────────────┐     ┌────────────┐
    │ BLUE (v1)  │ ◄── │   Trafik   │   Blue aktif
    │ ✅ Aktif    │     │   Yön.     │
    └────────────┘     └────────────┘
    ┌────────────┐
    │ GREEN (v1) │   Green boşta
    │ ⏸️ Boşta    │
    └────────────┘

    Yeni deploy:
    ┌────────────┐
    │ BLUE (v1)  │   Blue hâlâ aktif
    │ ✅ Aktif    │
    └────────────┘
    ┌────────────┐
    │ GREEN (v2) │   Green'e yeni versiyon deploy edilir
    │ 🔄 Deploy  │   ve test edilir
    └────────────┘

    Trafik değiştir:
    ┌────────────┐
    │ BLUE (v1)  │   Blue yedekte bekler (rollback için)
    │ ⏸️ Yedek    │
    └────────────┘     ┌────────────┐
                       │   Trafik   │
    ┌────────────┐     │   Yön.     │
    │ GREEN (v2) │ ◄── └────────────┘   Green aktif oldu!
    │ ✅ Aktif    │
    └────────────┘

    Rollback gerekirse:
    Trafiği blue'ya geri yönlendir → Saniyeler içinde geri!

⚠️ Dikkat: Rollback planı olmadan production deploy yapma. "Bir şey olursa revert ederiz" düşüncesi yeterli değil — revert + pipeline süresi dakikalar alabilir. En azından health check ekle ve hata durumunda otomatik bildirim gönder.

Strateji Karşılaştırması

┌────────────────────┬───────────┬────────────┬───────────────┐
│ Strateji           │ Hız       │ Karmaşıklık│ Güvenlik      │
├────────────────────┼───────────┼────────────┼───────────────┤
│ Git Revert         │ 🐌 5-10dk │ ⭐          │ ⭐⭐           │
│ Artifact Re-deploy │ ⚡ 1-2dk  │ ⭐⭐         │ ⭐⭐⭐          │
│ Tag Deploy         │ 🐌 5-10dk │ ⭐⭐         │ ⭐⭐⭐          │
│ Blue-Green         │ ⚡ saniye  │ ⭐⭐⭐⭐       │ ⭐⭐⭐⭐         │
│ Canary (aşamalı)   │ ⚡ dakika  │ ⭐⭐⭐⭐⭐      │ ⭐⭐⭐⭐⭐        │
└────────────────────┴───────────┴────────────┴───────────────┘

Tam CD Pipeline: Gerçek Dünya Örneği

# .github/workflows/deploy.yml
name: Deploy Pipeline

on:
  push:
    branches: [main]
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deploy ortamı'
        required: true
        type: choice
        options:
          - staging
          - production

concurrency:
  group: deploy-${{ github.event.inputs.environment || 'staging' }}
  cancel-in-progress: false    # Deploy'ları iptal etme, sıraya al

jobs:
  # ═══════════════════════════════════
  # Adım 1: CI Kontrolleri
  # ═══════════════════════════════════
  ci:
    name: 🔍 CI Checks
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm test -- --ci
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist/

  # ═══════════════════════════════════
  # Adım 2: Staging Deploy (Otomatik)
  # ═══════════════════════════════════
  staging:
    name: 🚀 Deploy to Staging
    needs: ci
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.myapp.com

    steps:
      - uses: actions/download-artifact@v4
        with:
          name: build
          path: dist/

      - name: Deploy to staging
        run: |
          echo "📦 Deploying to staging..."
          # Gerçek deploy komutu:
          # npx vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}
          echo "✅ Staging deploy complete!"

      - name: Smoke test
        run: |
          echo "🧪 Running smoke tests..."
          # curl -f https://staging.myapp.com/health || exit 1
          echo "✅ Smoke tests passed!"

  # ═══════════════════════════════════
  # Adım 3: Production Deploy (Onaylı)
  # ═══════════════════════════════════
  production:
    name: 🌍 Deploy to Production
    needs: staging
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment:
      name: production       # Approval gate burada!
      url: https://myapp.com

    steps:
      - uses: actions/download-artifact@v4
        with:
          name: build
          path: dist/

      - name: Deploy to production
        run: |
          echo "🚀 Deploying to production..."
          # Gerçek deploy komutu
          echo "✅ Production deploy complete!"

      - name: Health check
        run: |
          echo "💓 Running health checks..."
          # for i in 1 2 3 4 5; do
          #   curl -sf https://myapp.com/health && exit 0
          #   sleep 10
          # done
          # exit 1
          echo "✅ Health checks passed!"

      - name: Notify team
        if: success()
        run: |
          echo "📢 Deploy successful!"
          # Slack/Discord bildirim gönder
Deploy Pipeline Akışı:

  main'e merge
       │
       ▼
  ┌─────────┐
  │ 🔍 CI   │ Otomatik
  │ lint,test│
  │ build   │
  └────┬────┘
       │
       ▼
  ┌──────────┐
  │ 🚀 Stage │ Otomatik
  │ deploy + │
  │ smoke    │
  │ test     │
  └────┬─────┘
       │
       ▼
  ┌──────────────┐
  │ ✋ Approval   │ Manuel onay
  │ tech-lead    │ bekleniyor
  │ approved ✅  │
  └──────┬───────┘
         │
         ▼
  ┌──────────┐
  │ 🌍 Prod  │ Onay sonrası
  │ deploy + │ otomatik
  │ health   │
  │ check    │
  └──────────┘

Deploy Bildirimleri

Deploy sonrası ekibi bilgilendirmek kritik:

Slack Bildirimi

      - name: Notify Slack
        if: always()
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "${{ job.status == 'success' && '✅' || '❌' }} Deploy to production: ${{ job.status }}",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "*Deploy to Production*\n*Status:* ${{ job.status }}\n*Actor:* ${{ github.actor }}\n*Commit:* `${{ github.sha }}`"
                  }
                }
              ]
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

GitHub Deployment Status

      - name: Create GitHub deployment
        uses: actions/github-script@v7
        with:
          script: |
            const deployment = await github.rest.repos.createDeployment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              ref: context.sha,
              environment: 'production',
              auto_merge: false,
              required_contexts: []
            });
            
            await github.rest.repos.createDeploymentStatus({
              owner: context.repo.owner,
              repo: context.repo.repo,
              deployment_id: deployment.data.id,
              state: 'success',
              environment_url: 'https://myapp.com'
            });

Yaygın Hatalar

1. Production'a Manuel Onay Koymamak

# ❌ main'e merge → direkt production'a deploy
deploy:
  environment: production   # Koruma kuralı yoksa direkt çalışır!

# ✅ Environment'ta approval gate ayarla
# GitHub → Settings → Environments → production
# → Required reviewers: tech-lead

2. Rollback Planı Olmadan Deploy

# ❌ Sadece deploy et, sorun olursa panik yap
- run: npm run deploy

# ✅ Health check + otomatik rollback
- name: Deploy
  run: npm run deploy

- name: Health check
  id: health
  run: |
    for i in $(seq 1 5); do
      if curl -sf https://myapp.com/health; then
        echo "healthy=true" >> $GITHUB_OUTPUT
        exit 0
      fi
      sleep 15
    done
    echo "healthy=false" >> $GITHUB_OUTPUT
    exit 1

- name: Rollback on failure
  if: failure() && steps.health.outputs.healthy == 'false'
  run: |
    echo "🔄 Rolling back..."
    # Önceki versiyonu deploy et

3. Secret'ları Yanlış Environment'a Koymak

# ❌ Production API key'i repo secret'ında
# → Staging workflow'u da production API'ye erişir!

# ✅ Environment secret'ları kullan
# staging environment → STAGING_API_KEY
# production environment → PRODUCTION_API_KEY

# Her environment kendi secret'larına erişir

4. Deploy Sırasında Cache/CDN Temizlememek

# ❌ Yeni kodu deploy ettim ama kullanıcılar eski versiyonu görüyor
- run: aws s3 sync dist/ s3://bucket

# ✅ CDN cache'ini temizle
- run: aws s3 sync dist/ s3://bucket
- run: aws cloudfront create-invalidation --distribution-id $CF_ID --paths "/*"

CD En İyi Pratikleri

🏆 CD EN İYİ PRATİKLERİ:
──────────────────────────

1. Staging → Production sıralamasını uygula
   → Staging'de test etmeden production'a çıkma

2. Production'da approval gate kullan
   → En az 1 kişi onaylamalı

3. Health check ekle
   → Deploy sonrası uygulamanın çalıştığını doğrula

4. Rollback planın hazır olsun
   → Git revert, artifact re-deploy veya blue-green

5. Deploy'ları izlenebilir yap
   → Git tag, deployment log, Slack bildirimi

6. Secret'ları environment bazlı yönet
   → staging ve production secret'ları ayrı olmalı

7. Concurrency ile paralel deploy'ları engelle
   → cancel-in-progress: false (deploy'ları sıraya al)

8. Smoke test ekle
   → Deploy sonrası kritik endpoint'leri kontrol et

9. Küçük ve sık deploy yap
   → 1000 satırlık deploy yerine 50 satırlık deploy

10. Deploy saatini kontrol et
    → Cuma 17:00'de production deploy yapma 🙂

Özet

  • CD (Continuous Delivery/Deployment) kodun otomatik olarak staging ve production'a deploy edilmesidir — Delivery'de son adım manuel, Deployment'ta tamamen otomatiktir

  • GitHub Environments deploy hedeflerini yönetir — her environment'ın kendi secret'ları, koruma kuralları (approval gate, wait timer) ve deploy URL'i olabilir

  • Approval gates production deploy'larını korur — belirlenen reviewer'lar onay vermeden deploy başlamaz; environment: production ayarı ile aktifleşir

  • Rollback stratejileri hatalı deploy'lardan kurtarır — git revert (basit), artifact re-deploy (hızlı), blue-green (anlık); health check ile hata otomatik tespit edilebilir

  • Vercel/Netlify/AWS gibi platformlara GitHub Actions ile deploy etmek mümkün — her platform kendi action'ları ve CLI araçları ile entegre olur

  • Deploy bildirimleri (Slack, GitHub Deployment) ekibin haberi olmasını sağlar — deploy'un kim tarafından, ne zaman, hangi versiyonla yapıldığı izlenebilir olmalıdır


*Bir sonraki bölümde ekip çalışması konularına geçeceğiz: Branch naming convention, commit convention ve ekip workflow'ları!*