İçeriğe Atla
Mustafa Erbay
Yaşam · 9 dk okuma · görüntülenme Read in English

CI/CD Pipeline'ında Build Cache Optimizasyonu: 3 Pratik Yol

Yavaşlayan CI/CD süreçlerini hızlandırarak geliştirici yaşam kalitesini artırın. Build cache optimizasyonu için 3 pratik ve somut yöntemi inceliyoruz.

100%

CI/CD süreçlerinin yavaşlığı, bir yazılımcının gün içindeki odaklanma becerisini doğrudan baltalayan gizli bir yaşam kalitesi düşmanıdır. Her kod gönderdiğimde testlerin ve derleme (build) süreçlerinin bitmesini uzun uzun beklemek, beni bilgisayar başından uzaklaştırıp verimsiz bir döngüye sokuyordu. Kendi yan projelerimde bu süreyi kısaltmak için ciddi mesai harcadım.

Bu yazıda, doğrudan kendi uyguladığım ve pipeline sürelerini belirgin şekilde kısaltan CI/CD Pipeline’ında Build Cache Optimizasyonu yöntemlerini, somut konfigürasyonlar ve gerçek dünya tecrübelerimle anlatacağım. Amacım, teknik bir işi yaparken aslında kendi yaşam kalitemizi ve mental sağlığımızı nasıl koruyacağımızı göstermek.


CI/CD Pipeline’ında Build Cache Optimizasyonu Nedir ve Hayatımızı Nasıl Etkiler?

Yazılım geliştirme sürecinde “beklemek” en büyük motivasyon katilidir. Bir hata düzeltmesi yapıp repoya gönderdikten sonra pipeline’ın dakikalarca sıfırdan paket indirmesini izlemek, sadece sunucu faturasını kabartmaz; aynı zamanda geliştiricinin zihinsel akışını (flow state) kesintiye uğratır. CI/CD Pipeline’ında Build Cache Optimizasyonu, daha önce başarıyla tamamlanmış ara adımların sonuçlarını hafızada tutarak, sadece değişen kod parçalarını işlemeyi hedefler.

Kendi geliştirdiğim servislerde, ilk başlarda her deployment can sıkıcı şekilde uzun sürüyordu. Sadece tek satırlık bir log mesajı eklemek için bile uzun uzun beklemek beni işten soğutma noktasına getirmişti. Pratikte en çok zamanı tüketen adımlar genellikle şunlardır:

Pipeline Adımı Nerede Zaman Kaybedilir
Bağımlılıkların İndirilmesi Cache yoksa her çalıştırmada sıfırdan indirme
Docker Image Build Katman sırası yanlışsa tüm katmanların yeniden derlenmesi
Testlerin Çalıştırılması Test ortamının/veritabanının her seferinde baştan kurulması

Cache optimizasyonu bana sadece sunucu maliyetinden tasarruf ettirmedi, aynı zamanda gün içinde kahvemi soğutmadan deployment yapabilme özgürlüğü verdi. Eğer siz de her “git push” sonrası mutfağa gidip çay demliyorsanız, orada bir mühendislik problemi var demektir. Daha önce ele aldığım VPS disk doluluk sorunları yazımda da belirttiğim gibi, optimize edilmeyen her geçici dosya ve cache katmanı zamanla tüm sistemi tıkayan bir çığa dönüşür.


Yöntem 1: Docker Layer Caching (DLC) ile Boşa Geçen Dakikaları Kurtarmak

Docker imajı oluştururken yapılan en büyük hata, kaynak kodları kopyalamadan önce paket yönetim dosyalarını (package.json, go.mod, requirements.txt) doğru sırayla işleme almamaktır. Docker, her satırı (instruction) bir katman (layer) olarak kaydeder. Eğer kaynak kodlarınızı paket listesinden önce imaja kopyalarsanız, yazdığınız tek bir boşluk karakteri bile tüm paketlerin sıfırdan indirilmesine neden olur.

Kendi projelerimde kullandığım ve build süresini dramatik şekilde düşüren optimize edilmiş bir Dockerfile yapısını aşağıda paylaşıyorum. Bu yapı, Docker’ın katman önbellekleme mekanizmasını sonuna kadar sömürür:

# Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app

# Sadece paket tanımlarını kopyalıyoruz
COPY package.json package-lock.json ./

# Bağımlılıkları kuruyoruz (Bu katman paketler değişmedikçe cache'ten okunur)
RUN npm ci --prefer-offline --no-audit

# Şimdi kaynak kodları kopyalayabiliriz
COPY . .

# Derleme adımı
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

EXPOSE 3000
CMD ["node", "dist/main.js"]

Buradaki kritik numara COPY package.json package-lock.json ./ satırıdır. Eğer siz doğrudan COPY . . yapıp ardından npm ci derseniz, projedeki herhangi bir .ts veya .js dosyası değiştiğinde Docker tüm node_modules klasörünü internetten sıfırdan çekmeye başlar.


Yöntem 2: Paket Yöneticisi Cache’lerini (Node_Modules, Cargo, Go) Kalıcı Hale Getirmek

Docker katmanları lokalde çok iyi çalışır ancak GitHub Actions, GitLab CI veya self-hosted runner kullanıyorsanız, her pipeline çalışmasında temiz bir sanal makine (clean slate) ayağa kalkar. Bu durumda Docker local cache’i kaybolur. Çözüm, CI/CD sağlayıcısının sunduğu global önbellek (cache) mekanizmasını kullanarak paket yöneticilerinin indirdiği dosyaları pipeline’lar arasında taşımaktır.

Özellikle Rust (cargo) veya Go projelerinde derleme süreleri CPU limitleri yüzünden can sıkıcı boyutlara ulaşabilir. GitHub Actions üzerinde çalışan bir iş akışında (workflow) paket cache’ini nasıl kilitlediğimi gösteren YAML konfigürasyonunu aşağıda inceleyebilirsiniz:

# .github/workflows/ci.yml
name: Continuous Integration

on:
  push:
    branches: [ main ]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      # lock dosyalarının hash'ine göre cache anahtarı oluşturuyoruz
      - name: Cache Node Modules
        uses: actions/cache@v4
        id: npm-cache
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: Install Dependencies
        run: npm ci --prefer-offline --no-audit

Bu konfigürasyonda hashFiles('**/package-lock.json') ifadesi hayati önem taşır. Eğer bağımlılıklarda hiçbir değişiklik yoksa, GitHub Actions gidip ~/.npm klasörünü saniyeler içinde geri yükler. npm ci --prefer-offline parametresi ise npm’in internete gitmeden önce yerel önbelleğe bakmasını zorunlu kılar. Bu sayede dakikalarca süren paket kurulum aşaması saniyeler düzeyine iner.


Yöntem 3: Multi-Stage Builds ve Runner-Local Cache Entegrasyonu

Eğer kendi sunucunuzda (bare-metal veya VPS üzerinde) GitLab Runner veya Jenkins koşturuyorsanız, internet bant genişliğiniz ve disk yazma hızınız pipeline performansını doğrudan etkiler. Bu senaryoda bulut tabanlı cache servisleri yerine runner’ın üzerinde duran lokal disk alanını “mount” ederek kullanmak çok daha mantıklıdır.

Özellikle veritabanı ağırlıklı projelerde, PostgreSQL şemalarının taşınması (migration) ve backend testlerinin ayağa kalkması her seferinde sıfırdan veritabanı kurulmasını gerektirir. Bu tür durumlarda lokal runner üzerinde docker soketini paylaşarak (/var/run/docker.sock) ve lokal bir dizini cache olarak bağlayarak sorunu çözebilirsiniz.

Aşağıdaki Docker Compose ve CI runner entegrasyonu örneği, lokal disk üzerindeki önbelleği nasıl paylaştıracağınızı gösteriyor:

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

services:
  builder:
    image: docker:24-cli
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      # Local runner üzerindeki cache dizinini container içine bağlıyoruz
      - /tmp/ci-cache/.npm:/root/.npm
      - /tmp/ci-cache/go-build:/root/.cache/go-build
    environment:
      - DOCKER_BUILDKIT=1
    command: docker build --build-arg BUILDKIT_INLINE_CACHE=1 -t my-app:latest .

Bu yöntem sayesinde, harici bir bulut depolama alanına (S3 vb.) upload/download trafiği yapmadan, doğrudan runner’ın SSD disk hızıyla cache okuması yapıyoruz. Özellikle Türkiye lokasyonlu sunucularda yurtdışı çıkış hızlarının dalgalı olduğu dönemlerde bu lokal disk caching stratejisi hayat kurtarır.


Optimizasyon Sonrası Metrikler: Yatırımın Geri Dönüşü (ROI)

Yapılan her optimizasyonun somut bir çıktısı olmalıdır. “Sistem hızlandı” demek yerine bunu metriklerle kanıtlamak mühendislik disiplininin bir gereğidir. Bu yüzden optimizasyon öncesi ve sonrası süreleri ölçmek, kazanımı hem süre hem de finansal açıdan takip etmek önemlidir.

Bu üç yöntem birlikte uygulandığında, pipeline başına kazanılan dakikalar ay sonunda ciddi bir toplama ulaşır. Kazancı görmek için şu basit eşitliği kendi rakamlarınızla doldurmanız yeterli:

  • Pipeline başına kazanç × aylık çalıştırma sayısı = kurtarılan sunucu zamanı. Bu doğrudan CI/CD sunucu faturasına yansır.
  • Aynı süre × geliştirici sayısı = kurtarılan odaklanma zamanı. Asıl paha biçilemez kalem budur.

Sunucu maliyetinden gelen tasarruf çoğu zaman mütevazı kalır; ancak geri kazanılan geliştirici zamanı paha biçilemezdir. Geliştiricinin pipeline beklerken odağının dağılması, bağlam değiştirme (context switching) maliyetiyle birleştiğinde şirkete ve projeye faturası katlanarak büyür. Daha önce Yazılım mimarisi ve organizasyonel akış yazımda da değindiğim gibi, süreçleri optimize etmek aslında insan kaynağını en verimli şekilde kullanmanın en akıllıca yoludur.


Build Cache Yönetiminde Kaçınmanız Gereken Tuzaklar ve Sınırlar

Her güzel şeyin olduğu gibi build cache kullanımının da bazı yan etkileri ve sınırları vardır. Önbellekleme mekanizmalarına körü körüne güvenmek, bazen “lokalde çalışıyor ama sunucuda patladı” sendromunun en büyük sebebidir.

Karşılaştığım en sinsi sorunlardan biri, bozuk (corrupted) bir cache katmanının sürekli olarak yeni derlemeleri sabote etmesiydi. Bu gibi durumlarla başa çıkmak için şu kuralları asla es geçmiyorum:

  • Cache Sürümleme (Cache Busting): Bağımlılık dosyalarınız değişmese bile ara sıra cache’i tamamen sıfırlamak gerekir. Pipeline tetiklerken bir ortam değişkeni (env) ile cache versiyonunu değiştirebilmelisiniz (örn: CACHE_VERSION=v2).
  • Gizli Dosyaların Önbelleğe Sızması: .env dosyaları, SSL sertifikaları veya SSH key’ler gibi hassas verilerin asla cache dizinlerine dahil edilmediğinden emin olun. .dockerignore ve .gitignore dosyalarını güncel tutun.
  • Disk Alanı Yönetimi: Runner lokalindeki cache dizinleri zamanla şişer. systemd timer’ları ile haftalık olarak eski cache klasörlerini temizleyen küçük bir cron job çalıştırmak sistem sağlığı için elzemdir.

Sonraki adım olarak, kendi projelerinizdeki en yavaş çalışan pipeline’ı seçip işe başlayabilirsiniz. İlk olarak Dockerfile optimizasyonunu yapın, ardından paket yöneticisi cache’ini devreye alın. Farkı ilk derlemeden sonra doğrudan hissedeceksiniz.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

Sıkça Sorulanlar

Bu makale ile ilgili okurların sorduğu yaygın sorular.

CI/CD Pipeline'ında build cache optimizasyonu nasıl başlarım?
Ben, CI/CD Pipeline'ında build cache optimizasyonu yapmaya başlarken, ilk olarak pipeline süreciminizi iyice analiz etmenizi öneririm. Hangi adımların en fazla zaman aldığını belirleyin ve o adımları optimize etmeye odaklanın. Örneğin, benim kendi deneyimimde, paket indirmesi ve derleme adımları en fazla zaman alıyordu, bu nedenle bu adımları optimize etmeye odaklandım ve büyük bir hız kazanımı elde ettim.
CI/CD Pipeline'ında build cache optimizasyonu için hangi araçları kullanmalıyım?
Ben, CI/CD Pipeline'ında build cache optimizasyonu için çeşitli araçları denedim, ancak en çok Docker ve Jenkins gibi araçlarla başarılı sonuçlar elde ettim. Docker, build sürecinizi konteynırlaştırmanıza ve daha hızlı bir şekilde çalışmanıza olanak tanır, enquanto Jenkins, pipeline sürecinizi otomatikleştirmenize ve izlemenize yardımcı olur. Ayrıca, bazı projelerde GitHub Actions gibi araçları da kullanabilirsiniz.
CI/CD Pipeline'ında build cache optimizasyonu yaparken nelere dikkat etmeliyim?
Ben, CI/CD Pipeline'ında build cache optimizasyonu yaparken, özellikle cache'in doğru şekilde yapılandırılmasına dikkat etmenizi öneririm. Eğer cache doğru şekilde yapılandırılmazsa, bu, pipeline sürecinizin daha da yavaşlamasına neden olabilir. Ayrıca, pipeline sürecinizin her adımını dikkatlice analiz etmeniz ve hangi adımların en fazla zaman aldığını belirlemeniz önemlidir. Bu sayede, pipeline sürecinizi daha efektif bir şekilde optimize edebilirsiniz.
CI/CD Pipeline'ında build cache optimizasyonu yaparken karşılaşılan en büyük zorluklar nelerdir?
Ben, CI/CD Pipeline'ında build cache optimizasyonu yaparken, en büyük zorlukların başında, pipeline sürecinin kompleks olması ve doğru şekilde optimize edilmesinin zorluğu geliyor. Ayrıca, cache'in doğru şekilde yapılandırılması da bir başka zorluk olarak ortaya çıkabilir. Ancak, bu zorlukları aşmak için, pipeline sürecinizi dikkatlice analiz etmeniz, doğru araçları kullanmanız ve tecrübe kazandıkça, pipeline sürecinizi daha da optimize etmeniz önemlidir.
ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Yorumlar

Sunucu Taraflı AI Moderasyon

Yorumlar sunucuda yapay zeka ile denetlenir ve kalıcı olarak saklanır.

?
0/2000

Sunucu taraflı AI denetim

✉️ Ücretsiz · Spam yok · İstediğin an çık

Yeni yazılardan haberdar olun

Yeni içerikler ve teknik notlar e-postanıza gelsin.

  • 📌
    Haftanın en iyisi Sadece okumaya değer tek yazı
  • 🔧
    Alet çantası Bu hafta kullandığım araçlar
  • 🧠
    Perde arkası Blog'a girmeyen notlar

Spam yapmıyoruz. İstediğiniz zaman ayrılabilirsiniz. · Sadece Umami (self-hosted, Google yok) ile takip.

Okuma İstatistikleriniz

0

Yazı Okundu

0dk

Okuma Süresi

0

Gün Serisi

-

Favori Kategori

İlgili Yazılar