HomeBlogCI/CD Pipeline Optimizasyonu: Build Sürelerinizi %60 Azaltın
CI/CD & Automation

CI/CD Pipeline Optimizasyonu: Build Sürelerinizi %60 Azaltın

March 28, 202610 dkArticle
ci-cd pipeline optimizasyon github-actions

Yavaş CI/CD pipeline'ları, geliştirici deneyiminin sessiz katilidir. Her commit'te 20 dakika beklemek, günde onlarca kez tekrarlandığında saatler süren boşa geçen zamana dönüşür. Dahası, yavaş pipeline'lar geliştiricileri daha az commit yapmaya, büyük batch'ler halinde değişiklik göndermeye iter; bu da code review kalitesini düşürür ve merge conflict riskini artırır.

Bu yazıda, CI/CD pipeline'ınızı somut tekniklerle nasıl hızlandırabileceğinizi ele alıyoruz. Örnekler GitHub Actions üzerinden verilmiştir, ancak prensipler GitLab CI, Jenkins veya CircleCI gibi diğer platformlara da uygulanabilir.

Docker Layer Caching

Docker image build süresi, pipeline'ların en yavaş adımlarından biridir. Docker'ın katmanlı yapısını cache olarak kullanmak, build süresini dramatik şekilde azaltır.

# GitHub Actions - Docker Build with Cache
- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Build and push
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: myapp:${{ github.sha }}
    cache-from: type=gha
    cache-to: type=gha,mode=max

GitHub Actions'ın native cache backend'i (type=gha) ile BuildKit cache'ini doğrudan CI ortamında saklayabilirsiniz. Alternatif olarak registry-based caching de kullanılabilir:

cache-from: type=registry,ref=ghcr.io/myorg/myapp:cache
cache-to: type=registry,ref=ghcr.io/myorg/myapp:cache,mode=max

Dockerfile'ınızı cache-friendly yazmak da kritiktir. Sık değişen katmanları (uygulama kodu) sona, nadir değişen katmanları (dependency kurulumu) başa koyun:

FROM node:20-alpine AS builder
WORKDIR /app

# Dependency katmanı - sadece package dosyaları değiştiğinde rebuild
COPY package.json package-lock.json ./
RUN npm ci --production=false

# Uygulama kodu - her commit'te değişir
COPY . .
RUN npm run build

Dependency Caching

Paket yöneticisi bağımlılıklarını her build'de sıfırdan indirmek gereksiz zaman kaybıdır. Tüm büyük CI platformları dependency caching destekler.

# GitHub Actions - Node.js dependency cache
- name: Setup Node.js
  uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'

# Veya manuel cache kontrolü
- name: Cache node modules
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      npm-${{ runner.os }}-

Farklı diller için cache path'leri:

| Dil | Cache Path | Key Dosyası | |-----|-----------|-------------| | Node.js | ~/.npm veya node_modules | package-lock.json | | Python | ~/.cache/pip | requirements.txt / poetry.lock | | Go | ~/go/pkg/mod | go.sum | | Rust | ~/.cargo/registry + target/ | Cargo.lock |

Parallel Test Execution

Testleri seri çalıştırmak, pipeline süresini gereksiz yere uzatır. Test suite'inizi paralel job'lara bölmek en etkili optimizasyonlardan biridir.

# GitHub Actions - Matrix Strategy ile Paralel Testler
jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        shard: [1, 2, 3, 4]
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: |
          npx jest --shard=${{ matrix.shard }}/4

Jest, pytest ve diğer modern test framework'leri native sharding desteği sunar. fail-fast: false ayarı, bir shard başarısız olduğunda diğerlerinin de çalışmaya devam etmesini sağlar; böylece tüm hataları tek seferde görebilirsiniz.

Daha gelişmiş bir yaklaşım olarak, test sürelerine göre dinamik sharding yapabilirsiniz. Önceki çalışmalardan elde edilen timing bilgileriyle test'leri eşit süreli gruplara ayırmak, shard'lar arası dengesizliği ortadan kaldırır.

Selective Testing (Akıllı Test Seçimi)

Her commit'te tüm test suite'ini çalıştırmak çoğu zaman gereksizdir. Değişen dosyalara göre sadece etkilenen testleri çalıştırmak büyük zaman tasarrufu sağlar.

# Değişen dosyalara göre test seçimi
- name: Get changed files
  id: changed
  uses: tj-actions/changed-files@v44
  with:
    files_yaml: |
      backend:
        - 'src/api/**'
        - 'src/services/**'
      frontend:
        - 'src/ui/**'
        - 'src/components/**'
      infra:
        - 'terraform/**'
        - 'kubernetes/**'

- name: Run backend tests
  if: steps.changed.outputs.backend_any_changed == 'true'
  run: npm run test:backend

- name: Run frontend tests
  if: steps.changed.outputs.frontend_any_changed == 'true'
  run: npm run test:frontend

Monorepo'larda bu yaklaşım özellikle değerlidir. Nx, Turborepo veya Bazel gibi build araçları, dependency graph'ını analiz ederek sadece etkilenen projelerin testlerini çalıştırır.

Artifact Reuse

Aynı artifact'ı birden fazla kez build etmek yaygın bir israftır. Build artifact'larını bir kez oluşturup, sonraki adımlarda yeniden kullanın.

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build application
        run: npm run build
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: dist/
          retention-days: 1

  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: build-output
          path: dist/
      - name: Run tests
        run: npm run test:e2e

  deploy:
    needs: [build, test]
    runs-on: ubuntu-latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: build-output
          path: dist/
      - name: Deploy
        run: ./scripts/deploy.sh

Bu pattern ile build bir kez yapılır, test ve deploy aşamalarında aynı artifact kullanılır. Hem tutarlılık sağlar hem de toplam pipeline süresini kısaltır.

Build Matrix Optimizasyonu

Multi-platform veya multi-version testleri kaçınılmaz olabilir, ancak akıllıca yapılandırılmalıdır.

jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest]
        node: [18, 20, 22]
        include:
          # macOS ve Windows sadece ana versiyon için
          - os: macos-latest
            node: 20
          - os: windows-latest
            node: 20

Tüm OS ve versiyon kombinasyonlarını test etmek yerine, kritik kombinasyonlara odaklanın. Tam matrix'i sadece release öncesi veya scheduled workflow'larda çalıştırın.

Monorepo Stratejileri

Monorepo'larda pipeline optimizasyonu ekstra önem taşır. Turborepo ile remote caching örneği:

- name: Build with Turborepo
  run: npx turbo run build test lint --filter=...[HEAD^1]
  env:
    TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
    TURBO_TEAM: ${{ vars.TURBO_TEAM }}

--filter=...[HEAD^1] flag'i, son commit'ten bu yana değişen paketleri ve onlara bağımlı olan paketleri belirler. Remote cache sayesinde, bir geliştiricinin lokal ortamında build ettiği artifact'lar CI'da yeniden kullanılabilir.

Ölçün ve İyileştirin

Optimizasyon yapmadan önce mevcut durumu ölçmek şarttır. GitHub Actions'ta her adımın süresini workflow summary'den görebilirsiniz. Daha detaylı analiz için:

  • GitHub Actions: Workflow timing API'si ve üçüncü parti araçlar (BuildPulse, Datadog CI Visibility)
  • GitLab CI: Pipeline analytics dashboard
  • Jenkins: Pipeline Stage View ve Blue Ocean

Hedef metrikler belirleyin:

  • PR pipeline süresi: 10 dakikanın altında
  • Main branch pipeline: 15 dakikanın altında
  • Deployment pipeline: 5 dakikanın altında

Sonuç

Pipeline optimizasyonu tek seferlik bir proje değil, sürekli bir süreçtir. Küçük iyileştirmeler birikerek büyük farklar yaratır. Docker layer caching tek başına build süresini yarıya indirebilir. Paralel test execution ile test süresi shard sayısına bölünür. Selective testing ile gereksiz çalışmalar ortadan kalkar.

En önemli adım ölçmekle başlar. Pipeline sürelerinizi izleyin, darboğazları tespit edin ve yukarıdaki teknikleri sırasıyla uygulayın. Hedef, geliştiricilerin pipeline'ı bir engel olarak değil, güvenli ve hızlı bir geçit olarak görmesini sağlamaktır.

Weekly DevOps Newsletter

Get new tool reviews, comparisons and DevOps trends delivered to your inbox weekly.