GCP Cloud Scheduler ile Zamanlanmış Görevler

Cron job’lar sistem yöneticilerinin vazgeçilmez arkadaşıdır. Ancak kendi sunucularında cron çalıştırmak bazı sıkıntılar getirir: sunucu kapalıysa iş çalışmaz, loglama zayıftır, hata bildirimlerini kendin ayarlamak zorundasın. GCP Cloud Scheduler tam bu noktada devreye giriyor. Tamamen yönetilen, güvenilir ve ölçeklenebilir bir cron servisi olarak düşün. Arka planda ne çalıştığıyla uğraşmıyorsun, sadece işini tanımlıyorsun ve Google gerisini hallediyor.

Bu yazıda Cloud Scheduler’ı sıfırdan kuracağız, gerçek dünya senaryolarıyla kullanımını inceleyeceğiz ve sysadmin’lerin sık karşılaştığı durumlara pratik çözümler getireceğiz.

Cloud Scheduler Nedir ve Neden Kullanmalısın?

Cloud Scheduler, GCP’nin tam yönetilen cron job servisidir. Klasik Unix cron sözdizimini destekler, yani öğrendiklerini direkt kullanabilirsin. Ama bunun ötesinde:

  • HTTP/HTTPS endpoint’lere istek atabilir
  • Pub/Sub topic’lerine mesaj yayınlayabilir
  • App Engine uygulamalarını tetikleyebilir
  • Cloud Functions ve Cloud Run ile doğal entegrasyonu vardır
  • Her iş için ayrı servis hesabı ve kimlik doğrulama desteği sunar
  • Başarısız çalışmalarda otomatik yeniden deneme mekanizması vardır
  • Google Cloud Console üzerinden merkezi loglama sağlar

Bir iş kaçırılırsa veya hata verirse, Cloud Console’dan direkt görebilirsin. Kendi sunucuna SSH açıp /var/log/cron dosyasını karıştırmak zorunda kalmazsın.

Kurulum ve Ön Hazırlık

Başlamadan önce birkaç şeyin hazır olması gerekiyor.

gcloud CLI Kurulumu ve Proje Ayarı

# gcloud CLI kurulu değilse
curl https://sdk.cloud.google.com | bash
exec -l $SHELL

# Giriş yap
gcloud auth login

# Projeyi ayarla
gcloud config set project PROJECT_ID

# Cloud Scheduler API'yi etkinleştir
gcloud services enable cloudscheduler.googleapis.com

# Şu an aktif projeyi doğrula
gcloud config get-value project

Cloud Scheduler’ı kullanmak için App Engine’in en az bir bölgede başlatılmış olması gerekiyor. Bu biraz kafa karıştırıcı olabiliyor, ama Cloud Scheduler backend olarak App Engine altyapısını kullanıyor.

# App Engine başlatılmamışsa (sadece bir kez gerekiyor)
gcloud app create --region=europe-west1

# Mevcut Scheduler job'larını listele
gcloud scheduler jobs list

Servis Hesabı Oluşturma

Üretim ortamında her Scheduler job’u için ayrı bir servis hesabı kullanmak iyi pratiktir. Bu sayede her işin sadece ihtiyacı olan izinlere sahip olmasını sağlarsın.

# Scheduler için özel servis hesabı oluştur
gcloud iam service-accounts create scheduler-sa 
    --display-name="Cloud Scheduler Service Account" 
    --description="Cloud Scheduler job'ları için kullanılan servis hesabı"

# Servis hesabına Cloud Run Invoker rolü ver (Cloud Run tetiklemek için)
gcloud projects add-iam-policy-binding PROJECT_ID 
    --member="serviceAccount:scheduler-sa@PROJECT_ID.iam.gserviceaccount.com" 
    --role="roles/run.invoker"

# Pub/Sub Publisher rolü ver (Pub/Sub kullanacaksan)
gcloud projects add-iam-policy-binding PROJECT_ID 
    --member="serviceAccount:scheduler-sa@PROJECT_ID.iam.gserviceaccount.com" 
    --role="roles/pubsub.publisher"

İlk Job’ı Oluşturma

En basit senaryo ile başlayalım: bir HTTP endpoint’ini düzenli aralıklarla çağırmak.

HTTP Job Örneği

# Her sabah 09:00'da (Istanbul saatiyle) bir API'yi çağır
gcloud scheduler jobs create http sabah-raporu 
    --location=europe-west1 
    --schedule="0 6 * * *" 
    --uri="https://api.sirketim.com/v1/reports/daily" 
    --http-method=POST 
    --headers="Content-Type=application/json" 
    --message-body='{"report_type": "daily", "format": "pdf"}' 
    --time-zone="Europe/Istanbul" 
    --description="Her sabah günlük rapor oluşturur" 
    --attempt-deadline=5m 
    --max-retry-attempts=3 
    --min-backoff=30s 
    --max-backoff=5m

Burada önemli parametreler:

  • –schedule: Standart cron ifadesi. 0 6 * İstanbul saatiyle 09:00’a denk gelir (UTC+3 için UTC’den 3 saat çıkarıyoruz)
  • –time-zone: Zaman dilimini direkt belirtebilirsin. Europe/Istanbul yazarsan schedule’ı o zaman dilimine göre yorumlar
  • –attempt-deadline: Job’un maksimum çalışma süresi. Bu süreyi aşarsa başarısız sayılır
  • –max-retry-attempts: Başarısız olursa kaç kez tekrar denenir
  • –min-backoff ve –max-backoff: Yeniden denemeler arasındaki bekleme süreleri

Cron sözdizimini hatırlatmak gerekirse:

  • *: Dakika, Saat, Ay günü, Ay, Hafta günü
  • 0 /6 : Her 6 saatte bir
  • 0 2 1-5: Hafta içi her gece 02:00’da
  • 0 0 1 : Her ayın ilk günü gece yarısı
  • /5 *: Her 5 dakikada bir

Job Durumunu Kontrol Etme

# Job detaylarını gör
gcloud scheduler jobs describe sabah-raporu --location=europe-west1

# Job'u manuel olarak tetikle (test için çok işe yarıyor)
gcloud scheduler jobs run sabah-raporu --location=europe-west1

# Tüm job'ları listele
gcloud scheduler jobs list --location=europe-west1

# Job loglarını görüntüle
gcloud logging read "resource.type=cloud_scheduler_job AND resource.labels.job_id=sabah-raporu" 
    --limit=50 
    --format="table(timestamp,jsonPayload.status)"

Gerçek Dünya Senaryoları

Senaryo 1: Veritabanı Yedekleme Otomasyonu

Klasik sysadmin senaryosu: her gece veritabanını yedekle ve Cloud Storage’a at. Bu iş için bir Cloud Run servisi yazdığını varsayalım.

# Cloud Run servisini Scheduler ile tetikle
gcloud scheduler jobs create http veritabani-yedek 
    --location=europe-west1 
    --schedule="0 1 * * *" 
    --uri="https://db-backup-xyz-ew.a.run.app/backup" 
    --http-method=POST 
    --headers="Content-Type=application/json" 
    --message-body='{"databases": ["production", "analytics"], "destination": "gs://sirket-yedekler/db/"}' 
    --time-zone="Europe/Istanbul" 
    --oidc-service-account-email="scheduler-sa@PROJECT_ID.iam.gserviceaccount.com" 
    --oidc-token-audience="https://db-backup-xyz-ew.a.run.app" 
    --attempt-deadline=30m 
    --max-retry-attempts=2 
    --description="Gece yedekleme işlemi"

--oidc-service-account-email ve --oidc-token-audience parametreleri kritik. Cloud Run servisleri varsayılan olarak public erişime kapalıdır. Bu parametreler sayesinde Scheduler, OIDC token ile kimliğini doğrulayarak servisini çağırabilir.

Senaryo 2: Pub/Sub ile Asenkron İşlemler

Bazen doğrudan bir servisi çağırmak yerine mesaj kuyruğuna iş bırakmak daha mantıklıdır. Özellikle uzun süren işlemlerde bu pattern çok işe yarar.

# Önce Pub/Sub topic oluştur
gcloud pubsub topics create haftalik-rapor-tetikleyici

# Pub/Sub subscription oluştur
gcloud pubsub subscriptions create haftalik-rapor-sub 
    --topic=haftalik-rapor-tetikleyici 
    --ack-deadline=600

# Scheduler'dan Pub/Sub'a mesaj gönder
gcloud scheduler jobs create pubsub haftalik-analiz 
    --location=europe-west1 
    --schedule="0 8 * * 1" 
    --topic=haftalik-rapor-tetikleyici 
    --message-body='{"week": "auto", "recipients": ["[email protected]"]}' 
    --time-zone="Europe/Istanbul" 
    --description="Her Pazartesi haftalık analiz raporunu başlatır"

Bu yaklaşımın güzelliği şu: Scheduler sadece mesajı kuyruğa bırakır ve işini bitirir. Mesajı işleyen Cloud Function veya Cloud Run servisi ne kadar sürerse sürsün, Scheduler’ın umurunda değil. Timeout sorunları ortadan kalkar.

Senaryo 3: Eski Verileri Temizleme

Storage maliyetlerini kontrol altında tutmak için eski log ve geçici dosyaları temizleme işi:

# Her Pazar 03:00'da eski log dosyalarını temizle
gcloud scheduler jobs create http log-temizleme 
    --location=europe-west1 
    --schedule="0 0 * * 0" 
    --uri="https://maintenance-api.sirketim.com/cleanup" 
    --http-method=DELETE 
    --headers="Content-Type=application/json,X-Cleanup-Auth=gizli-anahtar" 
    --message-body='{"older_than_days": 90, "buckets": ["logs-bucket", "temp-bucket"]}' 
    --time-zone="Europe/Istanbul" 
    --attempt-deadline=20m 
    --description="90 günden eski logları temizler"

Senaryo 4: Çoklu Ortam Yönetimi (Dev/Staging/Prod)

Gerçek bir projede genellikle birden fazla ortam vardır. Her ortam için ayrı job’lar yönetmek karmaşıklaşabilir. Terraform kullanmak bu noktada hayat kurtarıcıdır, ama gcloud ile de yapılabilir:

#!/bin/bash
# scheduler_setup.sh - Tüm ortamlar için job'ları kur

ENVIRONMENTS=("dev" "staging" "prod")
LOCATION="europe-west1"

for ENV in "${ENVIRONMENTS[@]}"; do
    PROJECT_ID="sirket-${ENV}"
    
    # Prod dışında daha seyrek çalıştır
    if [ "$ENV" == "prod" ]; then
        SCHEDULE="0 1 * * *"
    else
        SCHEDULE="0 3 * * 0"  # Dev ve staging'de sadece haftalık
    fi
    
    gcloud scheduler jobs create http "veritabani-yedek-${ENV}" 
        --project="${PROJECT_ID}" 
        --location="${LOCATION}" 
        --schedule="${SCHEDULE}" 
        --uri="https://backup-api.${ENV}.sirketim.com/run" 
        --http-method=POST 
        --time-zone="Europe/Istanbul" 
        --oidc-service-account-email="scheduler-sa@${PROJECT_ID}.iam.gserviceaccount.com" 
        --oidc-token-audience="https://backup-api.${ENV}.sirketim.com" 
        --description="${ENV} ortamı yedekleme işi" 
        --quiet
    
    echo "${ENV} ortamı için job oluşturuldu."
done

Job Yönetimi ve İzleme

Job’ları Güncelleme ve Duraklatma

# Mevcut job'u güncelle (schedule değiştir)
gcloud scheduler jobs update http sabah-raporu 
    --location=europe-west1 
    --schedule="0 7 * * 1-5" 
    --description="Hafta içi 10:00'da çalışır (güncellendi)"

# Job'u geçici olarak duraklat (tatil dönemleri için)
gcloud scheduler jobs pause veritabani-yedek --location=europe-west1

# Job'u tekrar başlat
gcloud scheduler jobs resume veritabani-yedek --location=europe-west1

# Job'u sil
gcloud scheduler jobs delete eski-job --location=europe-west1 --quiet

Cloud Monitoring ile Alarm Kurma

Bir job başarısız olduğunda haberdar olmak istiyorsun. Bunu Cloud Monitoring üzerinden yapabilirsin:

# Bildirim kanalı oluştur (email)
gcloud beta monitoring channels create 
    --display-name="SysAdmin Ekibi Email" 
    --type=email 
    --channel-labels="[email protected]"

# Kanal ID'sini al
CHANNEL_ID=$(gcloud beta monitoring channels list 
    --filter="displayName='SysAdmin Ekibi Email'" 
    --format="value(name)")

# Scheduler job başarısızlık alarmı oluştur
gcloud alpha monitoring policies create 
    --display-name="Cloud Scheduler Job Hatası" 
    --condition-display-name="Job başarısız oldu" 
    --condition-filter='resource.type="cloud_scheduler_job" AND metric.type="cloudscheduler.googleapis.com/job/attempt_count" AND metric.labels.status!="success"' 
    --condition-threshold-value=1 
    --condition-threshold-comparison=COMPARISON_GT 
    --condition-aggregations-alignment-period=300s 
    --condition-aggregations-per-series-aligner=ALIGN_SUM 
    --notification-channels="${CHANNEL_ID}"

Log Tabanlı Metrikler

Cloud Scheduler loglarından özel metrikler çıkarabilirsin:

# Başarısız job çalışmalarını say
gcloud logging metrics create scheduler-hata-sayaci 
    --description="Cloud Scheduler job hatalarını sayar" 
    --log-filter='resource.type="cloud_scheduler_job" AND jsonPayload.status="FAILED"'

# Son 24 saatteki tüm job çalışmalarını gör
gcloud logging read 
    'resource.type="cloud_scheduler_job"' 
    --freshness=24h 
    --format="table(timestamp, resource.labels.job_id, jsonPayload.status, jsonPayload.targetType)"

Terraform ile Cloud Scheduler Yönetimi

Büyük ölçekli ortamlarda gcloud komutlarını tek tek çalıştırmak yerine Terraform kullanmak çok daha sürdürülebilir. Konfigürasyonu versiyon kontrolüne alabilir, değişiklikleri gözden geçirebilirsin.

# main.tf içeriği (bash bloğuna sığdırmak için bu şekilde yazıyoruz)
cat > scheduler.tf << 'EOF'
resource "google_cloud_scheduler_job" "veritabani_yedek" {
  name             = "veritabani-yedek"
  description      = "Gece veritabanı yedekleme işi"
  schedule         = "0 1 * * *"
  time_zone        = "Europe/Istanbul"
  attempt_deadline = "1800s"

  retry_config {
    retry_count          = 3
    max_retry_duration   = "3600s"
    min_backoff_duration = "30s"
    max_backoff_duration = "300s"
    max_doublings        = 3
  }

  http_target {
    http_method = "POST"
    uri         = "https://backup-api.sirketim.com/run"
    body        = base64encode(jsonencode({
      databases   = ["production", "analytics"]
      destination = "gs://sirket-yedekler/db/"
    }))
    headers = {
      "Content-Type" = "application/json"
    }

    oidc_token {
      service_account_email = google_service_account.scheduler_sa.email
      audience              = "https://backup-api.sirketim.com"
    }
  }
}

resource "google_service_account" "scheduler_sa" {
  account_id   = "scheduler-sa"
  display_name = "Cloud Scheduler Service Account"
}
EOF

# Terraform'u başlat ve uygula
terraform init
terraform plan
terraform apply

Yaygın Sorunlar ve Çözümleri

Job çalışıyor ama endpoint’e ulaşamıyor: Cloud Run veya Cloud Functions kullanıyorsan OIDC token ayarlarını kontrol et. Public endpoint değilse --oidc-service-account-email ve --oidc-token-audience mutlaka olmalı.

Zaman dilimi karışıklığı: Schedule’ı UTC olarak yazdığın halde işler beklediğin saatte çalışmıyorsa --time-zone parametresini eksik bırakmış olabilirsin. Her zaman açıkça belirt.

Job tekrar tekrar başarısız oluyor: attempt-deadline değerini kontrol et. Uzun süren işler için bu değeri artır. Yedekleme işleri bazen 20-30 dakika sürebilir, varsayılan değer yeterli olmayabilir.

Birden fazla instance çalışıyor: Bu durum genellikle job’un bir önceki çalışmasının bitmediği ve yeni bir çalışmanın başladığı durumlarda olur. Servis tarafında idempotent bir yapı kur ya da çalışma süresini azalt.

# Job'un son çalışma durumunu hızlıca kontrol et
gcloud scheduler jobs describe JOB_ADI 
    --location=europe-west1 
    --format="yaml(lastAttemptTime,status,schedule)"

Maliyet Optimizasyonu

Cloud Scheduler oldukça uygun fiyatlıdır. Aylık ilk 3 job ücretsiz, sonrası iş başına çok düşük bir ücret. Ama yine de dikkat etmek gerekiyor:

  • Gereksiz yüksek frekanslı job’lardan kaçın: Her 1 dakikada bir çalışan ve aslında 5 dakikada bir yeterli olacak job’lar zaman içinde birikerek maliyet oluşturur
  • Başarısız job’ların tetiklediği retry’lar: Downstream servis bozuksa ve retry sayısını yüksek tuttuysan, servis başına yüzlerce istek gidebilir. Bunlar hem maliyet hem de log kirliliği yaratır
  • Zombie job’ları düzenli temizle: Artık kullanılmayan job’ları listele ve sil
# Uzun süredir hiç çalışmamış veya hep başarısız olan job'ları bul
gcloud scheduler jobs list --location=europe-west1 
    --format="table(name, schedule, state, lastAttemptTime, status)"

Sonuç

Cloud Scheduler, GCP ekosisteminde çalışan sysadmin’ler için kendi cron daemon’larını yönetme zahmetinden kurtaran güçlü bir araç. Kurulumu basit, yönetimi merkezi, hata ayıklaması Stackdriver Logging sayesinde kolaylaşıyor.

Özellikle dikkat etmeni önerdiğim noktalar şunlar: servis hesaplarını her job için ayrı oluştur, OIDC kimlik doğrulamasını ihmal etme, attempt-deadline değerlerini iş sürelerine göre ayarla ve alarmları baştan kur. Bir job gece yarısı başarısız olmuş ama sabaha kadar kimse haberdar olmamışsa, bu gerçek bir sorun.

Terraform entegrasyonu büyük ortamlarda mutlak olmazsa olmaz. Job konfigürasyonlarını kod olarak yönetmek, ekip içinde değişikliklerin gözden geçirilmesini ve ortamlar arası tutarlılığı sağlıyor. Bu adımı erkenden at, sonradan taşımak zahmetli oluyor.

Klasik cron’dan göç ediyorsan, mevcut crontab’ını al, zaman dilimi farkını hesapla ve job’ları teker teker Cloud Scheduler’a taşı. Geçiş döneminde her ikisini paralel çalıştırıp logları karşılaştırabilirsin. Güven oluştuktan sonra eski cron job’larını kaldır.

Bir yanıt yazın

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