CI/CD ve pipeline
Sürekli entegrasyon, continuous delivery/deployment, pipeline aşamaları, artifact ve versiyonlama, secret ve konfigürasyon, deployment stratejileri, migration'lar ve DORA metrikleri üzerine başlangıçtan ileri seviyeye mülakat soruları.
Konu özeti
Continuous Integration (CI) bir araç değil, bir pratiktir: ekipteki herkes değişikliğini sık (en az günde bir) ana dala entegre eder ve her commit otomatik olarak build edilip test edilir. Amaç entegrasyon hatasını, oluştuğu dakikada ve küçükken yakalamaktır. Jenkins, GitHub Actions ya da GitLab CI bu pratiği otomatikleştiren araçlardır; uzun ömürlü branch'lerde haftalarca çalışıp sonra merge eden bir ekip, Jenkins kullansa bile CI yapmıyordur.
CD iki farklı şeyi anlatır:
- Continuous Delivery: ana dal her an production'a çıkabilecek durumdadır; her başarılı build, prod'a gönderilebilir bir aday üretir. Prod'a çıkış bilinçli bir karardır (bir buton, bir onay).
- Continuous Deployment: tüm kontrollerden geçen her değişiklik insan onayı olmadan otomatik olarak production'a çıkar.
Fark sadece son adımdaki manuel onaydır. Bankacılık gibi düzenlemeye tabi ortamlarda genelde continuous delivery ve dört göz onayı görülür (terimlerin kısa tanımı için bkz. Kitap Bölüm 15).
Pipeline aşamaları
Hattın sıralama ilkesi basittir: en ucuz ve en hızlı geri bildirim en önde, pahalı ve yavaş kontroller sonra.
| Aşama | Ne yapılır | Not |
|---|---|---|
| Checkout | Kod, belirli bir commit'ten alınır | Her şey o commit SHA'sına bağlanır |
| Build | ./mvnw -B package / ./gradlew build | Bağımlılık cache'i burada kazandırır |
| Unit test | Saniyeler süren testler | Kırmızıysa devam edilmez |
| Statik analiz / lint | Checkstyle, SpotBugs, SonarQube quality gate | Mekanik hataları review'dan önce yakalar |
| Güvenlik taraması | SAST (kod), SCA (bağımlılık zafiyeti), secret taraması | Kritik bulgu hattı durdurur |
| Integration test | Testcontainers ile gerçek PostgreSQL/Kafka | Dakikalar sürer |
| Artifact / image build | JAR ve Docker image, git SHA ile etiketlenir | Bir kez build edilir |
| Registry | ECR, Nexus, Artifactory, GHCR | Değişmez (immutable) etiketler |
| Staging deploy | Aynı image, staging konfigürasyonu | Migration'lar burada da ilk kez koşar |
| Smoke / e2e test | Sağlık kontrolü, kritik akışlar | Az sayıda, anlamlı test |
| Manuel onay | Delivery'de prod kapısı | Deployment'ta yok |
| Prod deploy | Rolling, blue-green ya da canary | Risk kademeli açılır |
| Post-deploy doğrulama | Hata oranı, latency, iş metrikleri | Deploy bitti, iş bitmedi |
| Rollback | Önceki image'a dönüş veya flag kapatma | Önceden prova edilmiş olmalı |
Güvenlik taramasında terimleri ayırmak gerekir: SAST kaynak kodu çalıştırmadan inceler (SQL injection kalıbı, güvensiz deserialization); SCA / dependency scan kullandığın kütüphanelerdeki bilinen CVE'leri bulur ve bir SBOM (bileşen listesi) üretir; image scan base image ve OS paketlerine bakar; DAST ise çalışan uygulamaya dışarıdan saldırır, bu yüzden staging'de koşar.
Post-deploy doğrulama ile rollback birbirine bağlıdır. Deploy'dan sonra belirli bir süre hata oranı, p99 latency ve iş metrikleri (başarılı ödeme sayısı gibi) önceki sürümle karşılaştırılır. Eşik aşılırsa ya önceki image'a dönülür (rollback), ya feature flag kapatılır, ya da hızlı bir düzeltme hattan geçirilir (roll forward). Rollback ancak önceki sürüm mevcut şemayla hâlâ çalışabiliyorsa güvenlidir; bu yüzden migration tasarımı rollback planının parçasıdır.
İki temel ilke var. Build once, deploy many: staging'de test edilen image (digest'iyle) prod'a gider; ortamlar arasında değişen tek şey konfigürasyondur. Her ortam için yeniden build etmek, test etmediğin bir şeyi prod'a göndermektir. Hızlı geri bildirim: PR pipeline'ı on dakikayı geçerse insanlar beklemeyi bırakır, flaky testler varsa kırmızıyı görmezden gelmeye başlar.
Örnek: GitHub Actions
Java 21 + Maven, bağımlılık cache'i, test, Docker image'ın ECR'a push'u ve staging deploy. AWS'e uzun ömürlü access key yerine OIDC ile kısa ömürlü kimlik alınır.
name: ci
on:
pull_request:
branches: [main]
push:
branches: [main]
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
env:
AWS_REGION: eu-central-1
ECR_REPOSITORY: order-service
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "21"
cache: maven
- name: Build, unit and integration tests
run: ./mvnw -B verify
- name: Upload test reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports
path: target/*-reports/
- name: Upload application jar
uses: actions/upload-artifact@v4
with:
name: app-jar
path: target/*.jar
image:
needs: build-test
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: app-jar
path: target
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.ECR_PUSH_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- id: ecr
uses: aws-actions/amazon-ecr-login@v2
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy-staging:
needs: image
runs-on: ubuntu-latest
environment: staging
permissions:
contents: read
id-token: write
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.STAGING_DEPLOY_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Roll out new image
run: |
aws eks update-kubeconfig --name staging --region "$AWS_REGION"
kubectl -n orders set image deployment/order-service \
app="${{ vars.ECR_REGISTRY }}/${ECR_REPOSITORY}:${GITHUB_SHA}"
kubectl -n orders rollout status deployment/order-service --timeout=5m
- name: Smoke test
run: curl --fail --retry 5 --retry-delay 5 https://orders.staging.example.com/actuator/health/readiness
Notlar: setup-java'nın cache: maven seçeneği ~/.m2/repository'yi pom.xml dosyalarının hash'ine göre saklar. Dockerfile burada derlemez, test edilmiş JAR'ı kopyalar (build once). Gradle kullanıyorsan setup-java'dan sonra gradle/actions/setup-gradle ve ./gradlew build yeterli. Action'ların daha yeni major sürümleri çıkmış olabilir (GitHub dokümanları actions/checkout@v6 kullanıyor); güvenlik açısından üçüncü parti action'ları commit SHA'sına sabitlemek daha iyidir. Prod deploy için ayrı bir job, environment: production ve o environment'ta zorunlu onaycılar tanımlanır.
Diğer araçlardaki karşılıkları: Jenkins'te Jenkinsfile (declarative pipeline { stages { stage('Build') {...} } }), secret'lar Credentials ile withCredentials, ortak adımlar Shared Library ile; onay input adımıyla. GitLab CI'da .gitlab-ci.yml, stages, cache, artifacts, rules, environment ve onay için when: manual. Kavramlar aynı, sözdizimi farklı.
Branch stratejisi, ortamlar ve secret'lar
Trunk-based development CI'ın doğal hâlidir: kısa ömürlü branch'ler (bir-iki gün), sık merge, bitmemiş iş feature flag arkasında kapalı olarak ana dala girer. Flag deploy ile release'i ayırır: kod prod'a gider, özellik sonra açılır.
Ortamlar (dev, staging, prod) aynı artifact'ı farklı konfigürasyonla çalıştırır. Spring Boot'ta profil (SPRING_PROFILES_ACTIVE=staging), ortam değişkenleri (SPRING_DATASOURCE_URL), Kubernetes ConfigMap ya da Spring Cloud Config / AWS Parameter Store kullanılır. Ortama özel değer image'ın içine gömülmez.
Secret'lar Git'e, Dockerfile'a ya da image katmanlarına girmez. Pipeline'da CI aracının secret deposu (GitHub Secrets, GitLab masked variables, Jenkins Credentials) kullanılır; bulut erişimi için mümkünse OIDC ile kısa ömürlü kimlik alınır. Uygulamanın runtime secret'ları ise Vault ya da AWS Secrets Manager'da durur.
Deployment stratejileri ve migration'lar
- Rolling: pod'lar kademeli değişir; ucuz, ama iki sürüm bir süre birlikte çalışır.
- Blue-green: yeni ortam tam kurulur, trafik tek seferde çevrilir; rollback anlıktır, kaynak iki katıdır.
- Canary: trafiğin küçük bir yüzdesi yeni sürüme gider, metrikler iyiyse artırılır; en düşük risk, en çok altyapı.
Ayrıntılı karşılaştırma için bkz. Kitap Bölüm 15. Üçünde de ortak gerçek şu: bir süre eski ve yeni sürüm aynı veritabanını kullanır. Bu yüzden Flyway/Liquibase migration'ları geriye uyumlu olmalıdır ve geriye uyumsuz değişiklikler expand/contract ile birkaç release'e bölünür: önce ekle (expand), kodu taşı, eski yapıyı en son kaldır (contract). Migration'lar uygulama açılışında ya da deploy'dan önce ayrı bir pipeline adımında koşabilir; büyük sistemlerde ikincisi tercih edilir.
DORA metrikleri
Teslimat performansını ölçmenin yaygın çerçevesi DORA'dır. Güncel tanımda beş metrik var: throughput tarafında change lead time (commit'ten prod'a süre), deployment frequency ve failed deployment recovery time; instability tarafında change fail rate (acil müdahale gerektiren deploy oranı) ve deployment rework rate (olay yüzünden yapılan plansız deploy oranı). Hız ve kararlılık birlikte okunur; biri diğerinin pahasına iyileştiriliyorsa sorun vardır. Eski kaynaklarda "dört anahtar metrik" ve MTTR geçer; mülakatta bunu söylemek de anlaşılır, ama güncel tanımı bilmek iyi bir sinyaldir. Bu metrikler ekibin kendi darboğazını bulması içindir (lead time'ın büyük kısmı review beklemesinde mi, staging kuyruğunda mı?); ekipleri ya da kişileri karşılaştırmak için kullanıldığında hızla oyunlaştırılır.
Sorular (25)
Continuous delivery ile continuous deployment arasındaki fark nedir?
Tipik bir CI/CD pipeline'ının aşamaları nelerdir, neden bu sırada?
Build kırıldığında ne yaparsın?
Unit ve integration testler pipeline'da nerede ve nasıl koşar?
Artifact nedir, neden bir kez build edip ortamlar arasında taşırız?
Docker image'ını nasıl versiyonlarsın, latest etiketinin sorunu nedir?
Pipeline'da secret'ları nasıl saklarsın?
Ortam bazlı konfigürasyonu (dev, staging, prod) nasıl yönetirsin?
Pull request açıldığında pipeline'da ne koşmalı, main'e merge sonrası ne değişir?
Flaky test'i nasıl ele alırsın?
Yavaş bir pipeline'ı nasıl hızlandırırsın?
Quality gate nedir, coverage eşiği koymak yeterli mi?
Pipeline'a hangi güvenlik taramalarını koyarsın?
Rolling, blue-green ve canary arasındaki fark nedir, hangisini ne zaman seçersin?
Trunk-based development nedir; bitmemiş bir özelliği ana dala nasıl merge edersin?
Pipeline'dan AWS'e uzun ömürlü access key olmadan nasıl erişirsin?
Veritabanı migration'ları pipeline'ın neresinde çalışmalı?
GitOps nedir, pipeline'ın doğrudan kubectl apply yapmasından farkı ne?
Deploy'u geri alman gerekti ama yeni sürüm bir migration çalıştırmıştı. Ne yaparsın?
Geriye uyumsuz bir şema değişikliğini sıfır kesintiyle nasıl deploy edersin?
Production'a giden bir değişikliğin baştan sona yolculuğunu anlat.
Monorepo ve polyrepo'da pipeline tasarımı nasıl değişir?
DORA metrikleri nedir, nasıl ölçülür ve nasıl yanlış kullanılır?
Build ettiğin image'ın gerçekten senin pipeline'ından çıktığını ve değiştirilmediğini nasıl kanıtlarsın?
Çoktan seçmeli (15)
Aşağıdakilerden hangisi Continuous Integration'ın özünü en iyi anlatır?
Tek doğru cevap var.
Continuous delivery ile continuous deployment arasındaki temel fark nedir?
Tek doğru cevap var.
"Build once, deploy many" ilkesine göre production'a ne gitmelidir?
Tek doğru cevap var.
Production deploy'larında image'ı latest etiketiyle kullanmanın temel sorunu nedir?
Tek doğru cevap var.
Maven projesinde *IT adlı integration testleri varsayılan olarak hangi plugin çalıştırır?
Tek doğru cevap var.
Uygulamanın veritabanı şifresi için aşağıdakilerden hangisi uygun bir yerdir?
Tek doğru cevap var.
Hızlı geri bildirim ilkesine göre aşağıdaki pipeline sıralamalarından hangisi en mantıklıdır?
Tek doğru cevap var.
Bir test aynı commit'te bazen geçip bazen kalıyor. En doğru ilk yaklaşım hangisidir?
Tek doğru cevap var.
Canary deployment için aşağıdakilerden hangileri doğrudur?
Birden fazla doğru olabilir.
GitHub Actions'ta bir job'ın OIDC ile AWS rolü üstlenebilmesi için workflow'da hangi izin gereklidir?
Tek doğru cevap var.
Expand/contract ile bir kolonu kaldırırken eski kolonun DROP edilmesi ne zaman güvenlidir?
Tek doğru cevap var.
GitOps modelinde CI pipeline'ının tipik rolü nedir?
Tek doğru cevap var.
Aşağıdakilerden hangisi DORA'nın yazılım teslimat performansı metriklerinden biri değildir?
Tek doğru cevap var.
Yeni sürüm, eski sürümün tanımadığı yeni bir enum değerini veritabanına yazmaya başladı ve bir sorun yüzünden rollback yapıldı. En olası sonuç ve doğru önlem hangisidir?
Tek doğru cevap var.
Container image'ını pipeline'da imzalamak ve deploy'da imzayı doğrulamak neyi sağlar?
Tek doğru cevap var.
Kaynaklar
- Martin Fowler: Continuous Integration: CI pratiğinin özgün ve güncellenmiş anlatımı.
- Martin Fowler: Continuous Delivery: delivery ve deployment ayrımı.
- Martin Fowler: Feature Toggles: flag türleri ve maliyetleri.
- Martin Fowler: Blue Green Deployment ve Canary Release: iki stratejinin kısa tanımları.
- Martin Fowler: Parallel Change: expand/contract deseni.
- GitHub Docs: Workflow syntax for GitHub Actions:
on,jobs,permissions,concurrency,environmentalanları. - GitHub Docs: Configuring OpenID Connect in Amazon Web Services:
id-token: write,configure-aws-credentialsve trust policy'desub/audkoşulları. - GitHub Docs: Security hardening for GitHub Actions: secret kullanımı ve action'ları SHA'ya sabitleme.
- DORA: Software delivery performance metrics: güncel beş metrik ve throughput/instability ayrımı.
- Redgate Flyway: Migrations: Flyway migration türleri ve kavramları (flywaydb.org dokümantasyonu bu adrese taşındı).
- SLSA: build provenance ve tedarik zinciri olgunluk seviyeleri.