Git Commit Çöplüğüne Son: CI/CD Pipeline Süreçlerini Yerelde Test Etme Yöntemleri
Yazım hatası yüzünden patlayan bir build. Arkasından gelen “fix typo” commit’i. O da yemedi; “fix syntax again”, “please work”, “test 4” ve nihayetinde “really fix this time”. Tanıdık geldi mi? Reponun commit geçmişini adeta bir çöplüğe çeviren bu döngü, yalnızca estetik bir problem değil. Her push işleminde buluttaki runner’ın ayağa kalkmasını beklemek, saatlik faturaları şişirmek ve geri bildirim döngüsünü (feedback loop) dakikalarca uzatmak demektir. Profesyonel bir SRE veya DevOps mühendisi için bu kabul edilemez bir zaman kaybıdır.
Bu pratik rehberde, commit-push-wait döngüsünden kurtulup yerel pipeline testi (local cicd testing) süreçlerini nasıl profesyonelce kurgulayacağımızı ele alacağız. GitHub Actions ve GitLab CI pipeline’larınızı, uzak sunuculara hiç dokunmadan, doğrudan kendi terminalinizde nasıl simüle edeceğinizi gerçek senaryolarla inceleyeceğiz.
Neden Yerelde Test Etmeliyiz? (The SRE Perspective)
Bunu sadece “temiz git geçmişi” motivasyonuyla açıklamıyoruz. Altında yatan asıl nedenler tamamen operasyonel verimlilik ve güvenlikle ilgilidir:
- Hızlı Geri Bildirim Döngüsü: Buluttaki bir runner’ın kuyrukta beklemesi, imajı çekmesi ve init olması ortalama 1-3 dakika sürer. Yerelde bu süre saniyeler mertebesindedir.
- Maliyet Optimizasyonu: GitHub Actions veya GitLab CI faturalarınızın önemli bir kısmı, aslında “deneme-yanılma” aşamasındaki başarısız run’lardan kaynaklanır.
- Güvenli Secret Yönetimi: Yeni bir entegrasyonu denerken production secret’larını ya da hassas API anahtarlarını geçici olarak buluttaki CI ortamına eklemek her zaman güvenlik riski barındırır.
—
GitHub Actions’ı Yerelde Koşturmak: act
GitHub Actions workflow’larını yerel makinede çalıştırmanın fiili standardı act aracıdır. `act`, lokalinizdeki Docker daemon’ını kullanarak GitHub’ın runner ortamlarını simüle eden container’lar ayağa kaldırır ve tanımladığınız adımları bu container’lar içinde çalıştırır.
act Kurulumu ve Temel Kullanımı
Kurulumu macOS işletim sistemlerinde Homebrew ile hızlıca yapabilirsiniz:
brew install nektos/tap/act
Eğer Linux kullanıyorsanız, doğrudan binary olarak çekebilirsiniz:
curl -s https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
Gerçekçi Bir Senaryo: Secret’lar ve Matrix Yapıları
Diyelim ki elinizde node.js uygulamasını test eden ve deploy etmeden önce bir API anahtarına ihtiyaç duyan aşağıdaki gibi bir `.github/workflows/ci.yml` dosyanız var:
name: Node.js CI
on:
push:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
Bu workflow’u yerelde çalıştırmak istediğinizde doğrudan `act` komutunu vermeniz yetmez; çünkü `secrets.DATABASE_URL` boş kalacaktır ve matrix yapısı yüzünden süreç uzayacaktır. İşte tam bu noktada profesyonel parametreler devreye giriyor.
Öncelikle bir `.secrets` dosyası oluşturun:
DATABASE_URL=mongodb://localhost:27017/test_db
Şimdi sadece Node 20 versiyonunu ve sadece `test` job’ını tetiklemek, üstelik bunu yaparken de yerel secret dosyamızı beslemek için şu komutu koşturuyoruz:
act -j test --matrix node-version:20.x --secret-file .secrets
In-depth Tip: Runner Boyutu Sorunsalı
`act` ilk çalıştığında size hangi imaj boyutunu kullanmak istediğinizi sorar (Micro, Medium, Large). Varsayılan “Micro” imaj genelde hızlı iner ancak içinde `curl`, `docker`, `aws-cli` gibi temel araçları barındırmaz. Gerçekçi bir act github actions deneyimi için en azından “Medium” imajı seçmeli veya `.actrc` dosyanıza şu custom imaj eşlemesini eklemelisiniz:
-P ubuntu-latest=catthehacker/ubuntu:act-latest
—
GitLab CI Pipeline’larını Yerelde Simüle Etmek
GitLab tarafında işler biraz daha karmaşıktır. Resmi `gitlab-runner exec` komutu uzun süredir “deprecated” durumdadır ve `needs`, `parent-child pipelines` veya modern `artifacts` tanımlamalarını tam olarak desteklemez. SRE topluluğu bu boşluğu doldurmak için harika bir açık kaynaklı alternatif geliştirdi: gitlab-ci-local.
gitlab-ci-local Kurulumu
NodeJS tabanlı bu CLI aracını sisteminize kurmak için NPM veya Homebrew kullanabilirsiniz:
brew install firecow/gitlab-ci-local/gitlab-ci-local
Uygulama: Kompleks Bir .gitlab-ci.yml Testi
Şöyle bir pipeline yapımız olduğunu düşünelim. Uygulamayı derliyor, artifact üretiyor ve bir sonraki stage’de bu artifact’i kullanıyor:
stages:
- build
- test
compile-code:
stage: build
image: node:20-alpine
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
run-unit-tests:
stage: test
image: node:20-alpine
needs: ["compile-code"]
script:
- ls dist/
- npm run test:unit
Bu pipeline’ı `gitlab-runner local` mantığıyla kendi makinenizde çalıştırmak için terminalden şu komutu vermeniz yeterlidir:
gitlab-ci-local
`gitlab-ci-local`, projenizin kök dizinindeki `.gitlab-ci.yml` dosyasını analiz eder, adımları sırasıyla çalıştırır, `needs` direktifine sadık kalır ve en önemlisi üretilen `dist/` klasörünü lokalinizdeki `.gitlab-ci-local/artifacts/` klasörüne otomatik olarak map eder. Böylece build artifact’lerinin bir sonraki job’a düzgün aktarılıp aktarılmadığını gözlerinizle görebilirsiniz.
Yerel GitLab Variable’larını Yönetmek
Gerçek CI ortamında GitLab UI üzerinden tanımladığınız “masked/protected” değişkenleri yerelde taklit etmek için `.gitlab-ci-local-variables.yml` adında bir dosya oluşturabilirsiniz:
STAGING_KUBE_TOKEN: "kube-token-12345"
DB_PASSWORD: "super-secret-password"
Bu dosya `.gitignore` listenizde olmalıdır. Araç, bu değişkenleri otomatik olarak okuyacak ve container’ların içerisine enjekte edecektir.
—
Docker-in-Docker (DinD) ve Soket Paylaşımı Çıkmazı
Yerel pipeline testlerinde en çok baş ağrıtan konulardan biri, pipeline adımının kendisinin de Docker ayağa kaldırmaya çalışmasıdır (örneğin, entegrasyon testleri için geçici bir DB container’ı başlatmak veya imajı `docker build` ile derlemek).
Eğer `act` kullanıyorsanız ve job’ınız içinde Docker komutları koşturacaksanız, lokalinizdeki Docker soketini container içine mount etmeniz gerekir:
act --bind-workdir -v /var/run/docker.sock:/var/run/docker.sock
Benzer şekilde, `gitlab-ci-local` kullanırken `services: – docker:dind` tanımınız varsa, aracın konfigürasyonunda yerel soketin paylaşıldığından emin olun. Bu sayede iç içe (nested) container yapısı yerine, tüm container’ların sizin host Docker daemon’ınız üzerinde “sibling” (kardeş) container’lar olarak ayağa kalkmasını sağlarsınız. Bu, hem disk alanından tasarruf sağlar hem de performansı katlar.
—
Özet ve Best Practice’ler
Süreci bir standarta oturtmak adına ekibinize şu kuralları aşılamanızı öneririz:
- Pre-commit Hook Entegrasyonu: Kritik CI script değişikliklerinde, geliştiricilerin lokalde en azından bir `act` veya `gitlab-ci-local` kuru testi yapmasını zorunlu tutun.
- Maksimum İmaj Önbellekleme (Caching): Lokal testlerin hızlı olması için Docker imajlarını yerelde optimize edin. Sık kullanılan base imajları (`node`, `python`, `golang` alpine versiyonları) önceden `docker pull` ile çekin.
- Lokal .env/.secrets Dosyalarını Asla Push Etmeyin: Güvenlik en katı kuraldır. `.gitignore` dosyanızda yerel pipeline testlerinde kullandığınız tüm taklit secret dosyalarının tanımlı olduğundan emin olun.
Geliştirme hızınızı (velocity) artırmak ve CI bütçelerini optimize etmek tamamen feedback loop süresini kısaltmaktan geçiyor. Araçlarınızı doğru yapılandırın, lokal gücü kullanın ve o commit çöplüğünü tarihe gömün.