İki yazılım ekibi hayal et.
Birincisi uygulamanın yeni sürümünü hazırlıyor.
Geliştirici görevi tamamlıyor. Birisi kodu inceliyor. Sonra testlerin çalıştırılması gerekiyor. Birisi paket hazırlıyor. Başka biri sunucuya giriş yapıyor. Ardından birkaç manuel işlem yapmak, yapılandırmayı kontrol etmek ve dağıtımdan sonra sistemi izlemek gerekiyor. Her şey yolunda giderse yeni sürüm kullanılabilir oluyor.
İkinci ekip farklı çalışıyor.
Kod depoya gidiyor. Testler, kalite analizi ve güvenlik kontrolleri otomatik olarak çalışıyor. Sistem uygulamanın sürümünü oluşturuyor, test ortamına dağıtıyor, ek kontroller yapıyor ve belirli koşullar sağlanırsa onu üretime alabiliyor. Bir şeyler ters giderse dağıtım durduruluyor ya da sistem önceki sürüme dönebiliyor.
Her iki ekip de yazılım üretiyor.
Ama yalnızca biri tekrarlanabilir bir yazılım teslim süreci kurdu.
CI/CD tam olarak bununla ilgilidir.
"Üretimde çalışıyor" henüz olgun bir süreç değildir
Birçok şirket başarıyı çok basit bir ölçütle değerlendirir: uygulama çalışıyor.
Elbette bu temel bir koşuldur.
Ama sistem büyüdükçe şu sorular ortaya çıkar:
- Bir düzeltmeyi ne kadar hızlı dağıtabiliriz?
- Yeni özellikleri ne kadar sık yayımlayabiliriz?
- Her dağıtımda kaç manuel işlem yapıyoruz?
- Her geliştirici aynı kurallara göre dağıtım sürecini başlatabilir mi?
- Şu anda hangi sürümün çalıştığını biliyor muyuz?
- Önceki sürüme dönebiliyor muyuz?
- Dağıtımdan sonra sistemin doğru çalışıp çalışmadığını otomatik olarak kontrol ediyor muyuz?
- İzleme sistemimiz var mı?
- Müşteri bildirmeden önce bir dağıtımın sorun yarattığını biliyor muyuz?
Bunlar yalnızca programlamayla değil, yazılım teslimi ile ilgili sorulardır.
CI ve CD - tek bir sürecin iki parçası
CI, yani Continuous Integration, değişikliklerin sürekli entegrasyonu anlamına gelir.
Pratikte amaç, değişikliklerin sık sık ortak depoya gitmesi ve otomatik olarak kontrol edilmesidir.
Tipik bir pipeline şunları çalıştırabilir:
-
uygulamanın derlenmesi veya oluşturulması,
-
birim testleri,
-
entegrasyon testleri,
-
linting,
-
statik kod analizi,
-
bağımlılık taraması,
-
güvenlik kontrolleri,
-
dağıtım artefaktlarının oluşturulması.
Bunun sayesinde problem kod üretime ulaşmadan önce tespit edilebilir.
CD, yani Continuous Delivery veya Continuous Deployment, bir sonraki aşamayla - değişikliklerin teslimiyle - ilgilidir.
Benimsenen modele bağlı olarak sistem, dağıtıma hazır bir sürüm hazırlayabilir veya belirli kontrollerden geçtikten sonra onu otomatik olarak dağıtabilir.
Bu önemli bir ayrımdır.
Continuous Delivery her değişikliğin otomatik olarak üretime alınması anlamına gelmek zorunda değildir.
Bu, her sürümün tekrarlanabilir biçimde dağıtıma hazırlanması anlamına gelebilir.
Manuel dağıtımlar neden sorun haline gelir?
Manuel dağıtım kötü olmak zorunda değildir.
Küçük bir projede tamamen yeterli olabilir.
Sorun, süreç uygulamayla birlikte büyüdüğünde başlar.
Önce sistemi nasıl dağıtacağını bilen tek bir kişi olur. Sonra ikinci sunucu eklenir. Ardından test ortamı gelir. Sonra veritabanı, önbellek, kuyruklar, depolama, birkaç servis ve dış API'ler eklenir. Buna ek olarak development, test ve production için farklı yapılandırmalar ortaya çıkar.
Birkaç yıl sonra süreç kabaca şöyle görünebilir:
"Önce X'i çalıştır, sonra Y parametresini değiştir, ardından Z servisini yeniden başlat, ama önce veritabanının yedeğini al. Eğer bir hata çıkarsa, bunu geçen sefer dağıtan kişiyi ara."
Bu artık bir süreç değildir. Bu insanın kafasında saklı bilgidir. Ve risk tam da o anda artar.
Otomasyon yalnızca geliştiricilerin rahatlığı için değildir
CI/CD çoğu zaman geliştiricilerin konforunu artıran bir araç olarak sunulur. Bu doğrudur, ama resmin yalnızca bir parçasıdır.
Teslimat otomasyonu öncelikle sürecin tekrarlanabilirliğini artırır.
Dağıtımı bir insan yaparsa, her seferinde biraz farklı bir şey yapma ihtimali vardır.
Bunu bir pipeline yaparsa, adımların kesin sırası tanımlanabilir.
Aynı sürüm.
Aynı testler.
Aynı kontroller.
Aynı kurallar.
Bu, özellikle birkaç kişi veya birkaç ekip tarafından geliştirilen projelerde çok önemlidir.
Dağıtımdan önceki testler, dağıtım hızından daha önemlidir
Testsiz otomasyon, yalnızca hataların daha hızlı ortaya çıkmasına neden olabilir.
Bu yüzden iyi tasarlanmış bir pipeline sadece şu mekanizma olmamalıdır: "kod → üretim".
Bir kalite kontrol sistemi olmalıdır.
Projeye bağlı olarak içinde şunlar bulunabilir:
- Birim testleri - mantığın tekil parçalarını kontrol eder.
- Entegrasyon testleri - bileşenlerin birlikte çalışmasını kontrol eder.
- Uçtan uca testler - gerçek kullanıcı senaryolarını simüle eder.
- Güvenlik testleri - diğer şeylerin yanı sıra bağımlılıkları ve bilinen açıkları kontrol eder.
- Performans testleri - belirli bir yükün karşılanmasının önemli olduğu yerlerde gerekir.
Her uygulamanın bu katmanların hepsine aynı ölçüde ihtiyacı yoktur.
Ve bu önemlidir.
CI/CD, pipeline'a mümkün olan en fazla sayıda aracı koymak değildir.
Mesele, kontrolleri belirli sistemin riskine göre seçmektir.
Test geçmediğinde ne olur?
Bu, tüm süreçteki en önemli sorulardan biridir.
Olgun bir pipeline'ın açıkça tanımlanmış kuralları olmalıdır.
Kritik bir test geçmezse, sürüm dağıtıma hazır olarak kabul edilmemelidir.
Bir güvenlik taraması belirli bir risk seviyesini tespit ederse, pipeline süreci durdurabilir.
Build oluşturulamıyorsa, dağıtılacak bir şey yoktur.
Bu basit gibi görünür. Ama tam da bu tür otomatik "kapılar", kalitenin yalnızca insanın hafızasına ve dikkatine bağlı olmamasını sağlar.
Peki ya dağıtım yine de başarısız olursa?
En iyi süreç bile tüm hataları ortadan kaldırmaz. Bu yüzden olgun teslimatın ikinci unsuru, değişikliği kontrollü bir şekilde geri alma imkanıdır.
Rollback önceki bir artefakta, bir konteyner imajına ya da uygulama sürümüne dönüş anlamına gelebilir. Ama burada önemli bir sorun ortaya çıkar. Kod rollback'i her zaman veri rollback'i anlamına gelmez.
Yeni sürüm veritabanı yapısını değiştirdiyse, durum daha karmaşık hale gelir.
Bu yüzden veritabanı migrasyonları, tüm sürecin mümkün olduğunca güvenli ve geri alınabilir ya da en azından uygulamanın önceki sürümüyle uyumlu olacak şekilde tasarlanmalıdır.
Bu, profesyonel CI/CD’nin sadece bir araç konfigürasyonu değil, bir mimari sorunu olduğunu gösteren örneklerden biridir.
Blue-green, canary ve diğer dağıtım stratejileri
Daha zorlu sistemlerde tüm kullanıcıları hemen yeni sürüme geçirmek gerekmez. Farklı deployment stratejileri uygulanabilir.
Blue-green deployment
İki ortam sürümü çalışır.
Biri trafiği karşılar, diğeri trafiği devralmaya hazırlanır.
Başarılı doğrulamadan sonra geçiş yapılır.
Avantajı, önceki ortama hızlıca geri dönme imkânıdır.
Dezavantajı, altyapı tüketiminin daha fazla olması olabilir.
Canary deployment
Yeni sürüm önce kullanıcıların veya trafiğin küçük bir kısmına gider.
Eğer izleme herhangi bir sorun göstermiyorsa, dağıtım kapsamı kademeli olarak artırılabilir.
Bu, hatanın potansiyel etkisini sınırlar.
Ancak uygun altyapı, izleme ve trafik yönetimi yöntemi gerektirir.
Feature flags
Bir özellik sisteme dağıtılabilir, ancak kullanıcılar için kapalı bırakılabilir.
Böylece kodun dağıtımı ve özelliğin açılması iki ayrı süreç haline gelir.
Bu, özellikle büyük değişikliklerde daha fazla kontrol sağlar.
Ancak feature flags’in her proje için çözüm olduğu anlamına gelmez. Fazlası da sistemin karmaşıklığını artırabilir.
Dağıtımdan sonra izleme
Tüm testleri yapabilirsiniz. Harika bir pipeline’ınız olabilir. Yeni sürümü hiçbir hata olmadan dağıtabilirsiniz. Ve birkaç dakika sonra uygulama gerçek yük altında farklı davranmaya başlayabilir.
Bu yüzden süreç deploy ile bitmemelidir. Observability gerekir; yani çalışan sistemin içinde neler olduğunu anlayabilme yeteneği.
Mimariye bağlı olarak bunlar arasında şunlar yer alır:
-
loglar,
-
metrikler,
-
tracing,
-
altyapı izleme,
-
uygulama izleme,
-
uyarılar,
-
hata bilgileri,
-
iş metrikleri.
Amaç her şeyi toplamak değildir. Amaç, önemli soruların verilere dayanarak yanıtlanabilmesidir.
Uygulama çalışıyor mu?
Eskisinden daha yavaş mı çalışıyor?
Hata sayısı arttı mı?
Hangi servis soruna neden oluyor?
Sorun tüm kullanıcıları mı yoksa yalnızca bir kısmını mı etkiliyor?
Günde 100 dağıtım her zaman hedef değildir
Bu makalenin başlığı günde 100 dağıtımdan bahsediyor, ama amaç bunu bir hedef olarak belirlemek değildir.
Ayda bir güncellenen bir iç sistemde, yapay olarak yüzlerce deployment’a ulaşmaya çalışmanın anlamı yoktur. Ancak çok yoğun geliştirilen bir sistemde bu sıklık teknik olarak mümkün olabilir.
Temel olan değişiklikleri güvenli bir şekilde teslim etme yeteneğidir, dağıtım sayısı değil. Bu temel bir farktır.
Sürecin olgunluğu, ne sıklıkta dağıtım yaptığımızla değil, bunu ne kadar öngörülebilir ve güvenli şekilde yapabildiğimizle ölçülür.
CI/CD ne zaman şekilciliğin içeriğe baskın çıkması olabilir?
Her uygulamanın karmaşık bir deployment altyapısına ihtiyacı yoktur.
Eğer küçük bir uygulamamız, küçük bir ekibimiz ve yılda birkaç dağıtımımız varsa, kapsamlı bir pipeline çözmekten çok daha pahalıya mal olabilir.
Benzer şekilde, güvenlik, regülasyon ya da altyapının doğası nedeniyle dağıtımın manuel kontrol gerektirdiği çok özel sistemlerde de durum böyledir.
Bu yüzden delivery mimarisi sistemin ihtiyaçlarından doğmalıdır. Modadan değil.
Dağıtım otomasyonu ne zaman özellikle çok değer sağlar?
Özellikle şu durumlarda değerlendirmeye değerdir:
-
sistem düzenli olarak geliştiriliyorsa,
-
kod üzerinde birkaç kişi çalışıyorsa,
-
birden fazla ortam varsa,
-
dağıtımlar sık yapılıyorsa,
-
manuel dağıtımlar hataya yol açıyorsa,
-
sistem iş açısından kritik öneme sahipse,
-
hızlı rollback gerekiyorsa,
-
uygulamanın birçok bileşeni varsa,
-
denetimler veya değişiklik izi gerekiyorsa,
-
özellik teslim süresi iş açısından önemliyse.
Bu gibi durumlarda, iyi tasarlanmış bir pipeline yazılım geliştirme sürecinin en önemli unsurlarından biri olabilir.
CI/CD kötü mimariyi düzeltmez
Bunu da vurgulamak gerekir.
Kötü bir uygulama için harika bir pipeline oluşturulabilir.
Kötü kod otomatik olarak test edilebilir.
Kötü mimari otomatik olarak dağıtılabilir.
Kötü tasarlanmış bir sistem otomatik olarak ölçeklenebilir.
Bu nedenle otomasyon, mimarinin, testlerin ya da ekibin yetkinliğinin yerini almaz.
Var olan süreci güçlendirir.
Süreç iyiyse, onu ölçeklendirmeye yardımcı olur.
Süreç kötüyse, sadece kötü şeyleri daha hızlı yapabilir.
Olgun bir süreç nasıl görünür?
Tek bir evrensel pipeline yoktur.
Ama olgun bir sürecin birkaç temel özelliği olmalıdır.
Tekrarlanabilirlik - dağıtım, tanımlanmış adımlara göre yapılır.
Otomasyon - makineler tekrarlanan işin mümkün olduğunca büyük kısmını yapar.
Test edilebilirlik - değişiklikler otomatik olarak doğrulanır.
Güvenlik - süreç uygun güvenlik kontrollerini içerir.
Gözlemlenebilirlik - dağıtımdan sonra sistemde ne olduğu bilinir.
Geri alınabilirlik - başarısız bir değişikliğe nasıl yanıt verileceği önceden planlanmıştır.
Değişiklik takibi - hangi sürümün dağıtıldığı ve neye dayandığı bilinir.
Erişim kontrolü - herkes istediği her şeyi prod'a keyfi olarak dağıtamaz.
İşte profesyonel bir software delivery süreci tam da bu unsurlardan oluşur.
En önemli değişim farklı bir soruyla başlar
Şirketler çoğu zaman şunu sorar: "Bu özelliği ne kadar hızlı oluşturabiliriz?"
İkinci bir soru eklemek gerekir: "Sonraki 50 özelliği ne kadar hızlı ve güvenli bir şekilde teslim edebileceğiz?"
Çünkü tek bir dağıtım manuel yapılabilir. Bir uygulamayı birkaç yıl boyunca manuel olarak da dağıtabilirsiniz. Ama ürün, ekip, kullanıcı sayısı ve değişiklik sayısı arttıkça böyle bir yaklaşımın bedeli de artar.
Bu yüzden CI/CD, otomatik testler, izleme ve kontrollü deployment’lar yalnızca büyük şirketler için çözümler değildir.
Bunlar, her bir sonraki değişikliğe gereksiz risk eklemeden yazılımı geliştirmeyi mümkün kılan süreç altyapısının parçalarıdır.
Ve sonuçta mesele tam olarak budur.
Günde 100 dağıtım değil.
Moda araçlar değil.
En karmaşık pipeline’dan değil.
Sadece şunu diyebilme imkânından:
"Bir değişikliğimiz var. Onu kontrol ettik. Neyi dağıttığımızı biliyoruz. Nasıl izleyeceğimizi biliyoruz. Ve bir şeyler ters giderse ne yapacağımızı biliyoruz."



