GitHub Actions mühendislik ekiplerini yavaş yavaş öldürüyor
(iankduncan.com)- Depoya varsayılan olarak dahil edilen bir CI olduğu için yaygın kullanılıyor, ancak yapısal verimsizlikler ve istikrarsız kullanıcı deneyimi geliştirici verimliliğini düşürüyor
- Log görüntüleyicisinin yavaş yüklenmesi ve tarayıcı çökmesi, karmaşık YAML sözdizimi ve ifade hataları tekrar eden debug süreçlerine yol açıyor
- Hesaplama kaynaklarının sahibi olunamayan yapı nedeniyle performans, ölçeklenebilirlik ve ortam kontrolü açısından sınırlar ortaya çıkıyor
- Bu sorunların çoğunu aşmaya çalışırken, karmaşık YAML veya devasa Bash betikleriyle CI'ı baştan kurma durumu tekrar tekrar yaşanıyor
- Buna karşılık Buildkite, basit YAML yapısı, self-hosted çalışabilen ajanları ve pratik log deneyimiyle uzun vadede sürdürülebilir bir CI alternatifi sunuyor
GitHub Actions'ın sorunları
- GitHub Actions log görüntüleyicisi verimsizdir: Basit bir hatayı kontrol etmek için bile birden fazla tıklama ve sayfa yüklemesi gerekir
- Build başarısız olduğunda check özet sayfası → workflow çalıştırma sayfası → job sayfası → kapalı step'e tıklamaya kadar 3-4 aşamalı sayfa geçişi gerekir ve her aşamada ayrı yükleme olur
- Büyük build loglarında tarayıcıyı tekrar tekrar çökertir; arama özelliği kullanıldığında Chrome'un donması yeniden üretilebilir düzeydedir
- Uzun loglarda kaydırma bile çalışmaz; sonunda ham log artifact'ini indirip bir metin editöründe açmak gerekir
- Geri düğmesi, asıl PR sayfası yerine öngörülemez bir GitHub Actions UI sayfasına götürür ve tarayıcı geçmişi Actions URL'leriyle dolar
- Debug sürecindeki verimsizlik
- Ortam değişkenlerini kontrol etmek için
run: envstep'i ekleyip yeniden push ettiğinizde 20 dakikalık bir geri bildirim döngüsü oluşur; tek satırlık bir değişiklik için bu süreç ondan fazla kez tekrarlanabilir - 20 dakikalık geri bildirim döngüleri tekrarlandıkça, iş gününün tamamı CI bekleme süresine harcanır
- Ortam değişkenlerini kontrol etmek için
- YAML'in yapısal sınırları
- GitHub Actions YAML'i, kendine özgü bir ifade dili, bağlam nesnesi modeli ve string interpolation kuralları birleşiminden oluşan özel bir yapıdır
${{ }}ifadelerinde tek bir tırnağı yanlış kullandığınızda, runner ayağa kalkana kadar 4 dakika bekledikten sonra string'in bozulduğunu fark edersiniz- İfade sözdizimi ayar yazmak için fazla karmaşık, tam teşekküllü programlama dili olarak kullanmak içinse fazla kısıtlı bir ara bölgede (liminal space) bulunur
- Sözdizimi, dokümantasyondan değil başarısızlık deneyimleri üzerinden öğrenilir
- Marketplace'in güvenlik riskleri
uses:sözdizimiyle harici action'lar çağrıldığında, repo, secret'lar ve build ortamına erişim yetkileri doğrulanmamış üçüncü taraflara verilir- SHA sabitleme (pinning) mümkündür ama bunu gerçekten yapan neredeyse yoktur; sabitlense bile okunmamış opak kod,
GITHUB_TOKENerişimiyle birlikte çalıştırılır - Marketplace, kalite seviyesi farklı topluluk tarafından sürdürülen action'larla doludur ve çoğu shell script ve Dockerfile'dan oluşur
- Bağımlılık yönetimi opaktır ve güvensiz kod çalıştırma ihtimali vardır
- Hesaplama ortamının kısıtları
- GitHub Actions'ın varsayılan runner'ı, Microsoft'a ait paylaşımlı bir runner'dır; yavaştır, kaynakları sınırlıdır ve anlamlı özelleştirme yapılamaz
- Daha büyük runner maliyetleri, finans ekibinden "bir konuşalım" seviyesinde toplantı talebi getirebilir; buna rağmen ortam kontrolü yine de mümkün değildir
- Namespace, Blacksmith, Actuated, Runs-on, BuildJet gibi, yalnızca GitHub Actions runner'larının yavaşlığını çözmeye odaklanan en az 6 startup'ın varlığı, varsayılan hesaplama ortamının yetersizliğini tek başına kanıtlar
- Self-hosted runner kurulduğunda hesaplama sorunu çözülür, ancak YAML ifadeleri, yetki modeli, Marketplace, log görüntüleyici gibi diğer sorunlar aynen kalır
Ayrıntılı ama biriken sorunlar
actions/cache: Cache anahtarları kafa karıştırıcıdır, cache miss sessizce yaşanır ve cache kaldırma (eviction) süreci opaktır; cache debug'ı, kazandırdığından daha fazla zaman harcatır- Yeniden kullanılabilir workflow'lar: Belli bir derinliğin ötesinde iç içe kullanılamaz, çağıran workflow'un bağlamına temiz biçimde erişilemez, izole test yapılamaz
GITHUB_TOKENyetki modeli:permissions: write-allfazla geniştir; ayrıntılı yetkiler ise repo, workflow ve job düzeyi ayarların etkileşimi nedeniyle labirent gibi karmaşıktır- Eşzamanlılık (concurrency) kontrolü: Aynı branch'teki devam eden çalıştırmaları iptal etmek tek satırla mümkündür, ancak bunun ötesinde ince ayarlı kontrol sunulmaz
- Secret'ların
ifkoşulunda kullanılamaması:if: secrets.DEPLOY_KEY != ''gibi koşullu çalıştırma mümkün değildir; güvenlik açısından makul olsa da hem fork'ta hem ana repoda çalışan workflow'lar yazarken geçici çözümler gerekir
"Sadece Bash script yazalım" tuzağı
- CI YAML'inden yorulan mühendisler için her şeyi
run:Bash betiklerine çevirmek cazip görünür, ancak zamanla koşullar, fonksiyonlar, argüman ayrıştırma ve paralel işleme eklenir - 3 ay sonra 800 satırlık Bash,
waitve PID dosyalarıyla job paralelleştirmesini yeniden uygular; kendi retry ve çıktı ayrıştırma mantığına da sahip olur - Sonuçta CI sisteminden kaçılmış olmaz; bunun yerine test çatısı olmayan ve kimsenin takip edemediği daha kötü bir CI sistemi Bash ile elde yazılmış olur
- Bash, glue amaçlı uygundur; ancak build sistemi veya test harness olarak kullanıldığında, karmaşıklığı korkulukların olduğu bir yerden olmadığı bir yere taşır
Buildkite'ın alternatif yaklaşımı
-
İstikrarlı log görüntüleyici
- Buildkite'ın log görüntüleyicisi tarayıcıyı çökertmeden logları düzgün gösterir; ANSI renkleri ve test framework biçimlendirmeleri olduğu gibi render edilir
- Annotation özelliğiyle build step'leri, test başarısızlığı özetlerini, coverage raporlarını, deployment bağlantılarını doğrudan build sayfasına Markdown olarak yazdırabilir
- Ajanlar kendi altyapınızda çalıştığı için SSH ile build makinesine bağlanıp doğrudan debug yapılabilir
-
Basit YAML yapısı
- Buildkite'ın YAML'i, pipeline'ı tanımlayan saf bir veri yapısıdır; yalnızca step, command ve plugin'ler bildirilir
- Gerçek mantık gerektiğinde, yerelde de çalıştırılabilen gerçek programlama dilleriyle script yazılır
- "Orkestrasyon ayarda, mantık kodda" sınırını net biçimde korur; GitHub Actions'ın bulanıklaştırdığı sınır tam da budur
-
Hesaplama ortamı üzerinde tam kontrol
- Buildkite ajanı tek bir binary olarak kendi cloud'unuzda, on-prem ortamınızda veya özel donanımınızda çalıştırılabilir
- Instance türü, caching, yerel depolama ve ağ üzerinde tam kontrol mümkündür; NVMe diskli ve 20 GB Docker layer cache'li büyük EC2 instance'lardan Raspberry Pi'ye kadar desteklenir
- "Buildkite ama daha hızlı" diye bir üçüncü taraf endüstrisi yoktur; sadece daha büyük makine çalıştırmanız yeterlidir
- Küçük açık kaynak kütüphanelerini sürdüren bireysel maintainer'lar için GitHub Actions'ın public repo ücretsiz katmanı hâlâ değerlidir
- Bu yazının ana hedefi, production sistemleri işleten ekiplerdir; burada CI süresi haftalık mühendislik zamanı kaybı olarak ölçülür ve 45 dakikalık build'ler hem hesaplama maliyeti hem iş gücü maliyeti yaratır
- Böyle ortamlarda Buildkite ajanlarını işletmenin ek yükü maliyetini hızla çıkarır
-
Dinamik pipeline desteği
- Buildkite'da pipeline step'leri veridir; script'ler çalışma anında dinamik olarak ek step'ler üretip (emit) yükleyebilir
- Monorepo'da değişen dosyalara göre yalnızca gerekli build ve test step'lerini tam isabetle oluşturmak mümkündür; sabit kodlanmış matrix'lere veya
if: contains(...)spagettisine gerek kalmaz - GitHub Actions'ın
matrix,ifkoşulları ve yeniden kullanılabilir workflow'ları bunu yaklaşık olarak sağlamaya çalışır, ancak ifade gücü düşük deklaratif bir dille bir Rube Goldberg makinesi kurmaya neden olur
-
Plugin yapısının sadeliği
- Yapı olarak GitHub Actions Marketplace'e benzer şekilde üçüncü taraf repolardan kod çekilir
- Fark şu ki Buildkite plugin'leri genelde Docker image yerine ince shell hook'lardır; bu yüzden yüzey alanı küçüktür ve birkaç dakikada tamamen okunabilir
- Kendi altyapınızda çalıştığı için blast radius kullanıcı tarafından kontrol edilebilir
-
Kullanıcı deneyimi odaklı ince detaylar
- Buildkite, özel emoji'leri (
:parrot:,:docker:vb.) pipeline step'lerinin yanında gösterebilir; küçük görünse de ürün deneyimine yönelik ince düşünülmüş bir yaklaşımı gösterir - GitHub Actions, "Bu keyifli mi?" sorusunu hiç sormamış gibi duran bir komite tasarımının ürünü gibidir
- Buildkite, özel emoji'leri (
Sonuç: CI sistemi seçmenin ölçütü
- GitHub Actions, varsayılan olarak gelme avantajıyla pazara hâkim oldu; public repo ücretsiz, herkesin zaten kullandığı platforma gömülü ve "yeterince iyi (Good Enough)" seviyesinde
- CI dünyasının Internet Explorer'ı gibidir; geçiş maliyeti gerçektir ve zaman sınırlı olduğu için kullanım sürer
- Buildkite, sürdürülebilir kullanım ve geliştirici deneyimi açısından daha üstündür
- Basit açık kaynak projeleri için GitHub Actions yeterlidir, ancak büyük production ortamlarında Buildkite daha uygundur
- CI sistemleri tarihinde pazar payını alan şey, en iyi sistem değil, başlaması en kolay sistem olmuştur
- GitHub Actions başlaması en kolay CI, Buildkite ise kullanmaya devam etmesi en iyi CI'dır; uzun vadede önemli olan da budur
- Bir CI aracı geliştiricinin zamanını tüketen bir yapıya sahipse, sorun geliştiricide değil aracın kendisindedir
3 yorum
Sorun galiba CI'ın karmaşıklaşmasının kendisi.
Sanki aynı yazı iki kez paylaşılmış gibi ama. Yapay zekanın kurgulaması için fena bir kombinasyon gibi görünmüyor bugünlerde..
Hacker News yorumları
Birçok CI sistemi kullandım. CircleCI ve GitHub Actions’ı çok kullandım ama yazarla aynı sonuca varmıyorum
Eskiden Jenkins Java’ya, Travis ise Rails’e özeldi; ama bu tür uzmanlaşmış CI yaklaşımları sonunda çıkmaza giriyordu. Artık CI, basitçe bir iş akışı orkestratörü haline evrildi
CircleCI 2’den GitHub Actions’a geçmemin nedeni de CircleCI’ın bu dönüşümü doğru düzgün yapamamasıydı. GHA yeterince ifade gücüne sahipti
Log görüntüleyici ya da YAML sözdizimi gibi şeyler ikincil meseleler. Asıl önemli olan hesaplama kaynaklarının sahipliği ve dinamik pipeline; ilki her CI’da mümkün, ikincisi ise Buildkite’ın güçlü yanı
Benim vardığım sonuç şu: Actions pratikte gayet iyi, yeni bir şirket kuracak olsam Buildkite, açık kaynak içinse Actions kullanırdım
Build grafiğini anlamıyorsa artımlı build durumunu korumak zorunda kalırsınız, bu da geçici hatalara yol açar. Bu yüzden UnrealEngine Horde ya da UBA gibi build yapısını derinlemesine anlayan sistemler gerekiyor
Genelleştirilmiş CI kullanırsanız build’in bir günden uzun sürmesi bile mümkün
Ben GHA’nin sadece iyi taraflarını kullanıyorum. Mesela GitHub olay dağıtıcısı olarak harika ama iş akışı orkestratörü olarak zayıf, bu yüzden o kısmı başka sistemlere devrediyorum
Günde onlarca kez baktığınız loglar kullanışsızsa üretkenlik düşer. Ham logda escape kodlarını yok sayarak okumak gerçekten eziyet
Ben sadeliği koruyorum. Tüm orkestrasyonu deploy.sh betiğine koyup yerel Mac’te ya da AWS CodeBuild’de çalıştırıyorum
YAML sadece
bash deploy.shsatırından ibaret. Docker container olduğu sürece Azure, GitHub Actions vb. her yerde aynı şekilde çalışıyorTüm CI ortamlarının temel stratejisi, yerelle aynı build sistemine sahip olmak
Ben hep Makefile ile başlarım. Docker, CI build’i, linting, her şeyi Makefile çalıştırır. Proje büyüyünce başka araçlara geçilebilir ama temel fikir tek bir tetikleme aracıdır
Mobil tarafta Fastlane’i çok kullanıyorum; boilerplate’i azaltıyor ve yapı sağlıyor. Sonuçta Ruby olduğu için gerekirse dışarı çıkmak da mümkün
(GNU Make doküman bağlantısı)
Sonunda “gidin Bash betiği yazın” noktasına çıkıyor, yani gereksiz karmaşıklık eklenmiş oluyor
Şu anki şirkette de tüm pipeline’ı yerelde çalıştırmak mümkün olmayınca, tek bir MR’ı test etmek için build’i 10 kez döndüren devasa bir CI altyapısı oluştu
Bana bu yazı Nix/Buildkite reklamı gibi geldi
CI’ın sadece betikleri ya da build hedeflerini çalıştırması yeterli. CI yalnızca ortamı ve yapılandırmayı sunmalı, mantık kodun içinde olmalı
Bu sayede CI bağımsızlığı kazanılır ve sistemler arasında geçiş kolaylaşır
GitLab CI bu karmaşıklığı ele almada oldukça iyi. Şablon ve job yapılandırma özellikleri harika ama debug etmesi zor, koşul mantığı da bazen beklenmedik şekilde bozuluyor
.shdosyalarına koymuş ekiplerin geçişi çok kolay olmuştuBuna karşılık her şeyi UI içinde parçalara ayıran ekipler çok zorlandı
Sorun CI/CD’nin kendisi değil, yapılandırma dosyalarıyla programlama yapma kültürü
git commit -m "try fix"deyip 10 dakika bekleme döngüsü fazlasıyla yaygın. Yerelde yeniden üretilebilen CI ortamı hâlâ eksikOrtam izolasyonunu politika olarak kurarsanız hangi aracı kullandığınız çok fark etmez. Sonuçta önemli olan araç ile metodolojinin uyumu
actgibi araçlar CI’ı yerelde yeniden üretmede çok yardımcı oluyor“Mühendislik ekibini öldürüyor” başlığı abartılı. GitHub Actions yeterince iyi
Bitbucket ya da GitLab’a tercih ederim
Son dönemde GitHub’ın güvenilirliği ciddi biçimde düştü
actions/checkoutsebepsiz yere başarısız olabiliyor, release job’ı iki kez çalışabiliyor ya da 40 dakika boyunca sadece beklediği oluyorYıllardır kullanıyorum ama temel kararlılık geriliyor. Buildkite’ı kaçırmış olmak üzücü
GitHub Actions, kullandığım en kötü CI araçlarından biri (Jenkins ile aynı seviyede)
Buna karşılık Buildkite en iyisi. Dinamik pipeline sayesinde test başarısız olduğunda otomatik olarak yeniden deneme adımları üretebilir ya da kod değişikliklerine göre paralel testleri ayarlayabilir
Her CI job’ı için farklı makine yapılandırmaları kullanabilmek de büyük avantaj. Kesinlikle tavsiye ederim
“Basit betik tabanlı CI” savunanların büyük ölçekli gerçek projelerde deneyimi yokmuş gibi geliyor