Mert Özen Her Satırda Daha İleri
DevOps CI/CD Temelleri — #01

CI, Continuous Delivery ve Continuous Deployment: Farkları ve Neden Önemli

Mert Özen 8 Kas 2026 8 dk 6 görüntülenme
CI, Continuous Delivery ve Continuous Deployment: Farkları ve Neden Önemli

CI, herkesin işini her gün mainline'a entegre edip her push'ta otomatik build ve test koşturmaktır; continuous delivery her commit'i release edilebilir tutar ve production'a çıkışı bir karara bırakır, continuous deployment ise o butonu da kaldırır. Integration hell senaryosu, Fowler'ın 2024 pratikleri, act ile koşulmuş bir CI workflow'u ve MinimumCD kontrol listesi.

Sürüm notu: Bu yazıdaki örnekler .NET 10 (SDK 10.0.402), act 0.2.97, actionlint 1.7.12 ve Docker 29 ile denenmiştir.

Önce Tahmin Et

Bookstore ekibi beş kişi. Herkes kendi feature branch'inde bir hafta çalışıyor, cuma öğleden sonra hepsi main'e merge ediliyor. Geçen ay ekip GitHub Actions'ı kurdu; artık her branch'e yapılan her push'ta build ve testler koşuyor ve hepsi yeşil. Soru şu: Bu ekip Continuous Integration yapıyor mu?

İkinci soru: Başka bir ekipte her commit otomatik olarak staging'e gidiyor, testlerden geçiyor, sonra bir yönetici "Production'a al" butonuna basıyor. Bu continuous delivery mi, continuous deployment mı? Cevaplarını bir kenara yaz; yazının sonunda ikisine de döneceğiz.

Cuma Akşamı: Integration Hell

Bookstore'un bir cumasını anlatayım. Ada bir haftadır feature/discounts branch'inde indirim kurallarını yazıyor ve PriceCalculator'ı baştan düzenlemiş. Alan aynı hafta feature/inventory'de çalışmış ve Book record'undaki Stock property'sini ayrı bir Inventory tipine taşımış. Grace sipariş ekranı için API'ye (Application Programming Interface) yeni bir endpoint eklemiş ve eski Stock'u kullanıyor. Üç branch kendi içinde yeşil, çünkü her biri main'in bir hafta önceki halinden ayrılmış ve diğerlerinin yaptığından habersiz.

Saat 16:00'da ilk merge giriyor, sorun yok. İkincisinde 14 dosyada conflict çıkıyor. Üçüncüsü conflict'siz merge ediliyor ama build kırılıyor: Grace'in kodu artık var olmayan bir property'yi okuyor. Düzeltiyorlar, bu sefer Ada'nın testleri kırılıyor, çünkü indirim hesabı stok kontrolüne bağlıymış. Martin Fowler'ın makalesinde anlattığı durum tam olarak bu: her düzeltme iki yeni problem ortaya çıkarıyor ve kimse işin ne zaman biteceğini söyleyemiyor. Literatürde buna "integration hell" deniyor.

Buradaki asıl problem merge'ün kendisi değil, entegrasyonun seyrekliği. Bir haftalık ayrılık, bir haftalık birikmiş fark demek. Farklar büyüdükçe çakışma ihtimali de büyür, çünkü her yeni değişiklik diğer herkesin değişiklikleriyle etkileşebilir ve kimse bu etkileşimi merge anına kadar görmez. Çözüm de buradan çıkıyor: entegrasyonu o kadar sık yap ki her seferinde küçük ve sıkıcı olsun.

Continuous Integration Ne Demek, Ne Değil

CI (Continuous Integration), Kent Beck'in 1990'larda XP (Extreme Programming) içinde tarif ettiği, Fowler'ın da 2000'deki makalesiyle yaygınlaştırdığı bir pratik. Makalenin 18 Ocak 2024 tarihli revizyonu pratikleri şöyle sıralıyor:

  • Her şey version control'deki tek bir mainline'da durur.
  • Build otomatiktir ve tek komutla çalışır.
  • Build kendini test eder (self-testing build).
  • Herkes mainline'a en az her gün push eder.
  • Mainline'a yapılan her push bir build tetikler.
  • Kırık build hemen düzeltilir.
  • Build hızlı tutulur (XP'nin "ten minute build" hedefi).
  • Yarım kalan iş gizlenir (ör. feature flag).
  • Testler production'ın bir kopyasına benzeyen ortamda koşar.
  • Herkes neler olduğunu görebilir.
  • Deployment otomatiktir.

Listeye dikkatli bak: tool sadece beşinci maddede geçiyor, o da dolaylı olarak. Geri kalanların çoğu ekibin davranışıyla ilgili. "Herkes her gün mainline'a push eder" maddesi, Bookstore ekibinin haftalık branch düzenini doğrudan dışarıda bırakıyor. Yani giriş sorusunun cevabı: hayır, o ekip CI yapmıyor. Her branch'te build koşturmak faydalı bir otomasyon, ama entegrasyon hâlâ haftada bir oluyor.

Otomasyon tarafı yine de gerekli; elle çalıştırılan bir build, kimse bakmadığında kırık kalır. Bookstore'un en küçük CI workflow'u şöyle:

name: ci

on:
  push:
    branches: [main]
  pull_request:

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-dotnet@v6
        with:
          global-json-file: global.json
      - run: dotnet test -c Release

Trigger'lar bilinçli seçildi: main'e gelen her push ve her PR (pull request). Feature branch'lerine yapılan her push'u ayrıca tetiklemek gerekmiyor, çünkü branch kısa ömürlü olacak ve PR açıldığında zaten koşacak. Bu workflow'u GitHub'a göndermeden yerelde act ile koşturdum; act, job'ları Docker container'ında GitHub runner'ına benzer bir ortamda çalıştırır. Çıktının ilgili satırları:

$ act push -W .github/workflows/ci.yml
[ci/build-and-test]   | SDK Version: 10.0.403
[ci/build-and-test]   | Passed!  - Failed:     0, Passed:     6, Skipped:     0, Total:     6, Duration: 101 ms - Bookstore.Api.Tests.dll (net10.0)
[ci/build-and-test]   ✅  Success - Main dotnet test -c Release [7.267571667s]
[ci/build-and-test] 🏁  Job succeeded

Altı test 101 milisaniyede geçti; job'ın tamamı yaklaşık 37 saniye sürdü ve bunun büyük kısmı SDK kurulumuydu. Bir detaya dikkat: global.json SDK 10.0.402 diyor ama runner 10.0.403 kurdu, çünkü rollForward değeri latestFeature. Bu tür küçük farklar build'in tekrarlanabilirliğini etkiler; serinin üçüncü yazısında buna döneceğiz.

Continuous Delivery: Her Commit Release Edilebilir

CI, kodun entegre olduğunu ve testlerden geçtiğini söyler. Ama "testler yeşil" ile "bunu müşteriye verebiliriz" arasında hâlâ mesafe var: paketleme, configuration, veritabanı migration'ı, staging'de deneme. Jez Humble ve David Farley'nin 2010 tarihli Continuous Delivery kitabı bu mesafeyi kapatmayı tarif ediyor: her değişiklik, otomatik bir pipeline'dan geçerek her an production'a çıkabilecek durumda tutulur.

Anahtar kelime "çıkabilecek". Continuous delivery'de production'a çıkış teknik bir iş değil, bir karardır. Pipeline staging'e kadar her şeyi otomatik yapar; production'a ne zaman çıkılacağına bir insan karar verir, genellikle tek bir butonla. O karar iş tarafından gelebilir ("kampanya pazartesi başlıyor"), regülasyondan gelebilir, ya da sadece ekip "bugün cuma, yarın sabah çıkalım" diyebilir. Önemli olan, butona basıldığında hiçbir elle adımın gerekmemesi.

Giriş sorusundaki ikinci ekip bu yüzden continuous delivery yapıyor: her commit staging'e kadar otomatik gidiyor, production butonla.

Continuous Deployment: Butonu da Kaldırmak

Continuous deployment bir adım daha ileri gider: pipeline'dan yeşil çıkan her commit, insan beklemeden production'a gider. Butona basan kimse yok; karar testlere ve otomatik kontrollere devredilmiş.

01-ci-cd-scope-tr.png

Üç kavram aynı hattın üzerinde duruyor; fark, otomasyonun nerede durduğu. Kısaltmalar burada kafa karıştırır: CD (Continuous Delivery ya da Continuous Deployment) iki kavram için de kullanılıyor. Bir toplantıda biri "CD'ye geçiyoruz" dediğinde hangisini kastettiğini sormak iyi bir alışkanlık.

Continuous deployment'ın bir ön koşulu daha var: deploy etmek ile kullanıcıya açmak aynı şey olmamalı. Yarım kalmış bir özellik production'a deploy edilebilir ama feature flag arkasında kapalı durur; deploy teknik bir olay, release bir iş kararıdır. Bu ayrımı, blue-green ve canary gibi tekniklerle birlikte ilerideki Deployment Stratejileri serisinde detaylı anlatacağım.

CI'ın Ön Koşulu: Küçük Batch'ler ve Trunk-Based Development

Her gün mainline'a push etmek, işi her gün entegre edilebilir parçalara bölmek demek. Bu da trunk-based development'ı doğal hale getiriyor: branch varsa bile kısa ömürlü olur, bir iki gün içinde trunk'a döner. Branch stratejilerini, GitHub flow ile Git flow farkını ve rulesets'i Git & GitHub serisinin "Git ile Ekip Çalışması: Branch Stratejileri, Rulesets ve Conventional Commits" yazısında anlattım; burada tekrar etmeyeceğim.

"Bizim işimiz bir günde bitmiyor" itirazı haklı, ama küçük batch, işin bir günde bitmesi değil, her gün tutarlı bir parçasının entegre edilmesi demek. Ada'nın indirim kuralları üç PR'a bölünebilirdi: önce yeni DiscountRule tipi ve testleri (hiçbir yerden çağrılmıyor), sonra hesaplamaya bağlanması (flag kapalı), en son flag'in açılması. Her biri tek başına merge edilebilir ve her biri Alan'ın değişikliğiyle o gün karşılaşır, cuma değil.

Continuous delivery yapıp yapmadığını ölçmek için MinimumCD topluluğunun kontrol listesi iyi bir başlangıç. Listenin continuous delivery kısmındaki dokuz madde ve Bookstore'da karşılıkları:

MinimumCD maddesiBookstore'da anlamı
Continuous integration kullanHerkes her gün main'e entegre eder
Her environment'a tek deploy yolu pipeline'dırSunucuya elle dosya kopyalamak yok
Releasability kararını pipeline verirKırmızı pipeline'a "ama ben denedim" itirazı geçmez
Pipeline'ın ürettiği artifact deploy edilebilir tanımına uyarAyrıca elle imzalama veya paketleme yok
Immutable artifactCommit'ten sonra kimse paketi değiştirmez
Ana pipeline kırmızıyken feature işi dururÖnce main düzelir
Production'a benzeyen test environment'ıStaging aynı image ve aynı veritabanı motoruyla koşar
İstendiğinde rollbackÖnceki image tek komutla geri alınır
Uygulama configuration'ı artifact ile birlikte deploy edilirConfig değişikliği de pipeline'dan geçer

Bu maddelerin çoğunu serinin ilerleyen yazılarında tek tek açacağız: artifact'ı üçüncü, environment'ları beşinci, kontrolleri altıncı yazıda.

Kısa Bir Tarihçe

Fikirlerin hangi sırayla geldiğini bilmek, terimlerin neden böyle kullanıldığını anlamayı kolaylaştırıyor. CI, 1990'ların sonunda XP'nin pratiklerinden biri olarak ortaya çıktı. Fowler makalesinin ilk sürümünü 2000'de yayımladı, 2006'da ve 2024'te önemli revizyonlar yaptı. 2010'da Humble ve Farley'nin Continuous Delivery kitabı CI'ı deployment pipeline kavramıyla production'a kadar uzattı. 2014'ten itibaren DORA (DevOps Research and Assessment) programı binlerce ekipten topladığı anketlerle bu pratiklerin teslimat performansıyla ilişkisini ölçmeye başladı ve 2015'te dört metriklik meşhur modeli oturttu. Bu metrikler 2024'te beşe çıktı; serinin son yazısında hepsini tek tek hesaplayacağız.

Üretimde Dikkat

CI'ın değeri geri bildirim süresine bağlı. Fowler'ın makalesi XP'nin on dakikalık build hedefini çoğu proje için makul buluyor; bir saatlik build'i ise çoğu meslektaşının kabul edilemez saydığını yazıyor. Pipeline'ın 25 dakika sürüyorsa insanlar beklemek yerine yeni işe başlar, sonuç geldiğinde bağlam çoktan değişmiştir.

İzlemen gereken ikinci şey, main'in ne kadar süre kırmızı kaldığı. Kırık build "birisi bakar" diye bekletildiğinde üstüne yeni commit'ler biner ve hangi commit'in neyi bozduğu bulanıklaşır. Kural basit: main kırmızıysa ilk iş onu düzeltmek ya da kıran commit'i revert etmek. MinimumCD'nin "kırmızıyken feature işi durur" maddesi bunu söylüyor.

Üçüncüsü güven. Ara sıra sebepsiz kırılan testler (flaky test) ekibe "kırmızı her zaman gerçek değil" alışkanlığı kazandırır ve gerçek hata da aynı umursamazlıkla karşılanır. Flaky test'lerle nasıl başa çıkılacağını dördüncü yazıda göreceğiz.

Sık Düşülen Tuzaklar

"Jenkins kurduk, CI yapıyoruz" en yaygın yanılgı. Tool, pratiğin sadece otomasyon kısmını sağlar; uzun ömürlü branch'ler varken her branch'te yeşil build görmek entegrasyonun yapıldığı anlamına gelmez.

Gece build'ini CI saymak da benzer bir hata. Günde bir kez koşan build, kırılan şeyi en iyi ihtimalle ertesi sabah söyler; o arada bozuk koda yeni işler eklenmiştir.

Continuous delivery'yi continuous deployment ile karıştırmak, gereksiz korkuya yol açıyor. "Her commit production'a mı gidecek?" endişesiyle ekipler pipeline'ı otomatikleştirmekten kaçınıyor. Oysa continuous delivery'de production butonu yerinde duruyor; değişen tek şey, butona basıldığında hiçbir elle adımın kalmaması.

Son tuzak, kırmızı build'i "benim değişikliğim değil" diye görmezden gelmek. CI ortak bir sorumluluk; main kırıksa herkesin işi durur.

Küçük Bir Deneme

★☆☆ Kendi projende son bir ayda main'e kaç merge yapıldığını ve feature branch'lerin ortalama kaç gün yaşadığını git log --merges --since="1 month ago" --format="%ad %s" ile çıkar. Branch'ler ortalama kaç günde trunk'a dönüyor?

★★☆ Yukarıdaki ci.yml'ı kendi .NET projene koy, act ile yerelde koştur, sonra bir testi bilerek kır ve job'ın nasıl başarısız olduğunu gözle. Kırmızı build'i görmen kaç saniye sürdü?

★★★ MinimumCD tablosunu kendi projen için doldur. Her madde için "evet", "kısmen" ya da "hayır" yaz ve "hayır" olanlardan ilk düzelteceğini seç.

Bir sonraki yazıda pipeline'ın anatomisine bakacağız: trigger, stage, job ve step kavramları, job'ları paralel koşturmak ve ucuz kontrolleri öne alarak hatayı mümkün olan en erken anda yakalamak.