GCP Cloud Build ile CI/CD Pipeline Kurulumu

Bir prodüksiyon ortamında sürekli entegrasyon ve sürekli dağıtım süreçlerini manuel yönetmek, ekibi hem yavaşlatır hem de hata riskini artırır. GCP Cloud Build, Google’ın tam yönetilen CI/CD servisi olarak bu sorunu köklü biçimde çözüyor. Sunucu kurmanıza, agent yönetmenize gerek yok; sadece pipeline’ınızı tanımlayın ve Google’ın altyapısının geri kalanını halletmesine izin verin. Bu yazıda gerçek bir uygulama senaryosu üzerinden Cloud Build pipeline’ı sıfırdan kuracağız, yaygın tuzaklardan bahsedeceğiz ve prodüksiyon kalitesinde bir CI/CD süreci nasıl oluşturulur onu göstereceğiz.

Cloud Build Nedir ve Neden Kullanmalısınız

Cloud Build, GCP üzerinde kod derleme, test çalıştırma ve artifact üretme işlemlerini otomatikleştiren tam yönetilen bir servistir. Jenkins gibi araçlara kıyasla en büyük avantajı altyapı yönetimi gerektirmemesidir. Ama asıl güç, GCP ekosistemiyle olan derin entegrasyondan geliyor: Cloud Source Repositories, Artifact Registry, GKE, Cloud Run ve Secret Manager ile neredeyse sıfır konfigürasyonla çalışıyor.

Tipik bir senaryoyu düşünelim: Bir e-ticaret uygulaması geliştiriyorsunuz. Her main branch’e push geldiğinde uygulamanın test edilmesi, Docker image’ının build edilmesi, Artifact Registry’e push edilmesi ve Cloud Run’a deploy edilmesi gerekiyor. Bu zinciri kurmak için Cloud Build mükemmel bir tercih.

Ön Gereksinimler

Başlamadan önce şunların hazır olduğundan emin olun:

  • Aktif bir GCP projesi ve billing etkin
  • gcloud CLI kurulu ve authenticate edilmiş
  • Temel Docker ve YAML bilgisi
  • Git repository (GitHub, GitLab veya Cloud Source Repositories)

GCP Tarafında Temel Kurulum

Önce gerekli API’leri etkinleştirip servis hesabı izinlerini düzenleyelim.

# Gerekli API'leri etkinleştir
gcloud services enable cloudbuild.googleapis.com
gcloud services enable artifactregistry.googleapis.com
gcloud services enable run.googleapis.com
gcloud services enable secretmanager.googleapis.com

# Proje ID'nizi bir değişkene atayın
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')

echo "Project ID: $PROJECT_ID"
echo "Project Number: $PROJECT_NUMBER"

Cloud Build’ın kullandığı servis hesabına gerekli rolleri verin. Bu adımı atlamak en yaygın hata kaynaklarından biridir:

# Cloud Build servis hesabına gerekli roller
gcloud projects add-iam-policy-binding $PROJECT_ID 
  --member="serviceAccount:[email protected]" 
  --role="roles/run.admin"

gcloud projects add-iam-policy-binding $PROJECT_ID 
  --member="serviceAccount:[email protected]" 
  --role="roles/artifactregistry.writer"

gcloud projects add-iam-policy-binding $PROJECT_ID 
  --member="serviceAccount:[email protected]" 
  --role="roles/secretmanager.secretAccessor"

# Cloud Run için servis hesabı aktörü rolü
gcloud iam service-accounts add-iam-policy-binding 
  [email protected] 
  --member="serviceAccount:[email protected]" 
  --role="roles/iam.serviceAccountUser"

Artifact Registry Kurulumu

Docker image’larını saklamak için Artifact Registry reposu oluşturalım. Eski Container Registry artık deprecated durumda olduğundan direkt Artifact Registry kullanın:

# Artifact Registry reposu oluştur
gcloud artifacts repositories create app-repo 
  --repository-format=docker 
  --location=europe-west1 
  --description="Uygulama Docker image'ları"

# Repository'i listele ve doğrula
gcloud artifacts repositories list --location=europe-west1

cloudbuild.yaml Dosyası Anatomisi

Cloud Build’ın kalbi cloudbuild.yaml dosyasıdır. Bu dosya pipeline adımlarını, değişkenleri ve tetikleyici koşulları tanımlar. Basit bir yapıdan başlayalım:

# cloudbuild.yaml - Temel yapı
steps:
  # Adım 1: Bağımlılıkları yükle ve testleri çalıştır
  - name: 'python:3.11-slim'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        pip install -r requirements.txt
        pip install pytest
        pytest tests/ -v --tb=short
    env:
      - 'PYTHONPATH=/workspace'

  # Adım 2: Docker image'ını build et
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'build'
      - '-t'
      - 'europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/myapp:$COMMIT_SHA'
      - '-t'
      - 'europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/myapp:latest'
      - '.'

  # Adım 3: Image'ı Artifact Registry'e push et
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'push'
      - '--all-tags'
      - 'europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/myapp'

  # Adım 4: Cloud Run'a deploy et
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'myapp-service'
      - '--image=europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/myapp:$COMMIT_SHA'
      - '--region=europe-west1'
      - '--platform=managed'
      - '--allow-unauthenticated'

# Build timeout - varsayılan 10 dakika, prodüksiyon için artırın
timeout: '1200s'

# Üretilen image'ları kaydet
images:
  - 'europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/myapp:$COMMIT_SHA'
  - 'europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/myapp:latest'

$COMMIT_SHA, $PROJECT_ID, $BRANCH_NAME gibi değişkenler Cloud Build tarafından otomatik olarak enjekte edilir. Bunları manuel tanımlamanıza gerek yoktur.

GitHub Entegrasyonu ve Trigger Kurulumu

Cloud Build’ı GitHub repository’siyle bağlamak için önce GCP konsolundan GitHub App’i yetkilendirmeniz gerekiyor. Bunu CLI üzerinden de yapabilirsiniz:

# GitHub reposunu Cloud Build'a bağla
# Bu komut tarayıcıda OAuth akışı başlatır
gcloud builds triggers create github 
  --repo-name="myapp" 
  --repo-owner="kullaniciadi" 
  --branch-pattern="^main$" 
  --build-config="cloudbuild.yaml" 
  --name="main-branch-deploy" 
  --description="main branch'e push gelince deploy et"

# Feature branch'ler için sadece test trigger'ı
gcloud builds triggers create github 
  --repo-name="myapp" 
  --repo-owner="kullaniciadi" 
  --branch-pattern="^feature/.*$" 
  --build-config="cloudbuild.yaml" 
  --name="feature-branch-test" 
  --substitutions="_DEPLOY_ENV=staging"

# Mevcut trigger'ları listele
gcloud builds triggers list

Ortam Bazlı Pipeline Stratejisi

Gerçek dünyada tek bir pipeline yetmez. Genellikle şu yapı kullanılır:

  • feature/* branch’leri: Sadece test ve build
  • develop branch’i: Staging ortamına deploy
  • main branch’i: Production ortamına deploy

Bunun için substitution variable’lardan faydalanın:

# cloudbuild-multi-env.yaml
substitutions:
  _DEPLOY_ENV: 'production'
  _REGION: 'europe-west1'
  _SERVICE_NAME: 'myapp'

steps:
  # Kod kalite kontrolü
  - name: 'python:3.11-slim'
    id: 'lint-and-test'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        pip install -r requirements.txt flake8 pytest pytest-cov
        echo "=== Linting ==="
        flake8 src/ --max-line-length=120 --statistics
        echo "=== Tests ==="
        pytest tests/ -v --cov=src --cov-report=term-missing
        echo "Coverage threshold kontrolü"
        pytest tests/ --cov=src --cov-fail-under=80

  # Docker build - cache kullanımıyla hızlandırılmış
  - name: 'gcr.io/cloud-builders/docker'
    id: 'docker-build'
    waitFor: ['lint-and-test']
    args:
      - 'build'
      - '--cache-from'
      - 'europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/$_SERVICE_NAME:latest'
      - '-t'
      - 'europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/$_SERVICE_NAME:$COMMIT_SHA'
      - '-t'
      - 'europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/$_SERVICE_NAME:latest'
      - '--build-arg'
      - 'BUILD_ENV=$_DEPLOY_ENV'
      - '.'

  # Image push
  - name: 'gcr.io/cloud-builders/docker'
    id: 'docker-push'
    waitFor: ['docker-build']
    args:
      - 'push'
      - '--all-tags'
      - 'europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/$_SERVICE_NAME'

  # Deploy adımı - sadece main ve develop için
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    id: 'deploy'
    waitFor: ['docker-push']
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        if [ "$BRANCH_NAME" = "main" ] || [ "$BRANCH_NAME" = "develop" ]; then
          echo "Deploying to $_DEPLOY_ENV environment..."
          gcloud run deploy $_SERVICE_NAME-$_DEPLOY_ENV 
            --image=europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/$_SERVICE_NAME:$COMMIT_SHA 
            --region=$_REGION 
            --platform=managed 
            --set-env-vars="APP_ENV=$_DEPLOY_ENV" 
            --memory=512Mi 
            --cpu=1 
            --max-instances=10 
            --min-instances=1
          echo "Deploy tamamlandı!"
        else
          echo "Feature branch - deploy atlanıyor"
        fi

timeout: '1800s'

waitFor direktifi ile adımlar arasındaki bağımlılıkları kontrol edebilirsiniz. Bağımsız adımları paralel çalıştırarak build süresini önemli ölçüde kısaltabilirsiniz.

Secret Manager Entegrasyonu

API anahtarları, veritabanı şifreleri gibi hassas bilgileri asla YAML dosyasına yazmayın. Secret Manager kullanın:

# Secret oluştur
echo -n "super-secret-db-password" | 
  gcloud secrets create db-password 
  --replication-policy=automatic 
  --data-file=-

# Yeni versiyon ekle
echo -n "yeni-sifre-v2" | 
  gcloud secrets versions add db-password --data-file=-

# Cloud Build servis hesabına erişim ver
gcloud secrets add-iam-policy-binding db-password 
  --member="serviceAccount:[email protected]" 
  --role="roles/secretmanager.secretAccessor"

YAML’da secret’ı şu şekilde kullanırsınız:

# Secret Manager entegrasyonu
steps:
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'bash'
    secretEnv: ['DB_PASSWORD', 'API_KEY']
    args:
      - '-c'
      - |
        echo "Veritabanına bağlanılıyor..."
        # DB_PASSWORD ve API_KEY artık environment variable olarak mevcut
        gcloud run deploy myapp 
          --image=europe-west1-docker.pkg.dev/$PROJECT_ID/app-repo/myapp:$COMMIT_SHA 
          --region=europe-west1 
          --set-secrets="DB_PASSWORD=db-password:latest,API_KEY=api-key:latest"

availableSecrets:
  secretManager:
    - versionName: projects/$PROJECT_ID/secrets/db-password/versions/latest
      env: 'DB_PASSWORD'
    - versionName: projects/$PROJECT_ID/secrets/api-key/versions/latest
      env: 'API_KEY'

Build Geçmişini İzleme ve Debugging

Pipeline çalıştıktan sonra log’ları takip etmek için:

# Son build'ı listele
gcloud builds list --limit=5

# Belirli bir build'ın log'larını görüntüle
gcloud builds log BUILD_ID

# Build'ı gerçek zamanlı takip et
gcloud builds log BUILD_ID --stream

# Manuel build tetikle (test amaçlı)
gcloud builds submit 
  --config=cloudbuild.yaml 
  --substitutions=_DEPLOY_ENV=staging,COMMIT_SHA=manual-test-$(date +%s) 
  .

# Build'ı filtrele - sadece başarısız olanlar
gcloud builds list 
  --filter="status=FAILURE" 
  --format="table(id,status,createTime,duration)" 
  --limit=10

Bir build başarısız olduğunda en hızlı debug yöntemi log’u stream modunda izlemektir. Hangi adımda hata aldığınızı, tam hata mesajını ve environment variable değerlerini görebilirsiniz.

Bildirim Kurulumu

Pipeline başarısız olduğunda haberdar olmak için Pub/Sub ve Cloud Functions kombinasyonu kullanabilirsiniz. Daha pratik bir yöntem ise direkt Slack webhook entegrasyonudur:

# Başarısız build'da Slack bildirimi gönder
steps:
  # ... diğer adımlar ...

  # Bildirim adımı - her zaman çalışır
  - name: 'curlimages/curl'
    id: 'notify-slack'
    entrypoint: 'sh'
    secretEnv: ['SLACK_WEBHOOK']
    args:
      - '-c'
      - |
        STATUS="Başarılı"
        COLOR="good"
        
        curl -X POST -H 'Content-type: application/json' 
          --data "{
            "attachments": [{
              "color": "$COLOR",
              "title": "Cloud Build: $STATUS",
              "fields": [
                {"title": "Proje", "value": "$PROJECT_ID", "short": true},
                {"title": "Branch", "value": "$BRANCH_NAME", "short": true},
                {"title": "Commit", "value": "$COMMIT_SHA", "short": true}
              ]
            }]
          }" 
          "$$SLACK_WEBHOOK"

availableSecrets:
  secretManager:
    - versionName: projects/$PROJECT_ID/secrets/slack-webhook/versions/latest
      env: 'SLACK_WEBHOOK'

Maliyet Optimizasyonu

Cloud Build ücretsiz katmanda günlük 120 dakika build süresi sunuyor. Bunu aşarsanız dakika başına ücretlendiriliyorsunuz. Maliyeti düşürmek için şu önlemleri alın:

  • Docker layer caching: --cache-from direktifini kullanın, tekrar eden build’larda önemli zaman tasarrufu sağlar
  • Paralel adımlar: Bağımsız adımları waitFor: ['-'] ile paralel çalıştırın
  • Küçük base image’lar: alpine veya slim varyantlarını tercih edin
  • Gereksiz trigger’ları devre dışı bırakın: Sadece kritik branch’lerde full pipeline çalıştırın
  • Build timeout’larını optimize edin: Gerçekçi değerler koyun, varsayılan 10 dakika çoğu proje için yeterli
# Aylık build dakikası kullanımını kontrol et
gcloud builds list 
  --format="table(id,duration)" 
  --filter="createTime>2024-01-01T00:00:00Z" | 
  awk '{sum += $2} END {print "Toplam dakika:", sum/60}'

Yaygın Sorunlar ve Çözümleri

Prodüksiyon ortamlarında sıkça karşılaşılan sorunları ve çözümlerini listeleyelim:

  • “Permission denied” hatası: Cloud Build servis hesabının gerekli rollere sahip olduğundan emin olun. En sık atlanan rol roles/iam.serviceAccountUser‘dır.
  • “Image not found” hatası: Artifact Registry bölgesinin build bölgesiyle uyumlu olduğunu kontrol edin.
  • Timeout hataları: timeout değerini artırın ve --machine-type=E2_HIGHCPU_8 ile daha güçlü makine kullanmayı değerlendirin.
  • Cache çalışmıyor: --cache-from kullanmadan önce image’ın registry’de mevcut olduğundan emin olun. İlk build’da cache yoktur.
  • Secret erişim sorunu: availableSecrets bloğunun steps ile aynı seviyede olduğunu doğrulayın.
  • YAML parse hatası: Cloud Build YAML’ı strict şekilde parse eder. Tab yerine space kullanın ve girintilere dikkat edin.
# Build konfigürasyonunu yerel olarak doğrula
gcloud builds submit --config=cloudbuild.yaml --dry-run .

# Servis hesabı izinlerini kontrol et
gcloud projects get-iam-policy $PROJECT_ID 
  --flatten="bindings[].members" 
  --filter="bindings.members:[email protected]" 
  --format="table(bindings.role)"

Private Repository ile Çalışma

Eğer npm, pip veya go modülleri için özel registry kullanıyorsanız, build sırasında kimlik doğrulaması yapmanız gerekir. Cloud Build’ın servis hesabı bu konuda yardımcı olur:

steps:
  - name: 'python:3.11-slim'
    entrypoint: 'bash'
    secretEnv: ['PRIVATE_PYPI_TOKEN']
    args:
      - '-c'
      - |
        # Private PyPI token ile pip configure
        pip config set global.index-url 
          https://oauth:[email protected]/simple/
        pip install -r requirements.txt
        # Sonra test çalıştır
        pytest tests/

Sonuç

Cloud Build, GCP ekosisteminde çalışan takımlar için son derece güçlü ve ölçeklenebilir bir CI/CD çözümü sunuyor. Altyapı yönetimi gerektirmemesi, GCP servisleriyle yerli entegrasyonu ve esnek pipeline yapısı onu özellikle cloud-native projeler için cazip kılıyor. Jenkins veya GitLab CI gibi araçlara kıyasla öğrenme eğrisi daha kısa olmakla birlikte, ince noktalar var: servis hesabı izinleri, secret yönetimi ve maliyet optimizasyonu konularına baştan dikkat etmek ilerleyen süreçte büyük zaman tasarrufu sağlıyor.

Prodüksiyon ortamında bu yapıyı kurarken önce basit bir pipeline ile başlayıp kademeli olarak özellik ekleyin. Test adımlarını asla atlamamayı, secret’ları mutlaka Secret Manager’da tutmayı ve her ortam için ayrı trigger yapılandırması oluşturmayı alışkanlık haline getirin. Pipeline olgunlaştıkça build süreleri kısalacak, deployment güveni artacak ve ekip üyeleri “çalışır mı bilmiyorum, yolla gitsin” yaklaşımından “main’e merge ettim, on dakikaya kadar canlıda” güvenine geçecektir.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir