GCP App Engine ile Uygulama Dağıtımı
Google Cloud Platform üzerinde uygulama deploy etmek söz konusu olduğunda, App Engine hâlâ en pratik ve hızlı başlangıç noktalarından biri olmaya devam ediyor. Kubernetes’in karmaşıklığına girmeden, sunucu yönetimi derdi olmadan, sadece kodunuzu yükleyip çalıştırmak istediğinizde App Engine tam da aradığınız şey oluyor. Bu yazıda gerçek dünya senaryoları üzerinden App Engine’i nasıl kullanacağınızı, tuzaklarını ve dikkat etmeniz gereken noktaları ele alacağız.
App Engine Nedir ve Ne Zaman Kullanmalısınız
App Engine, GCP’nin tamamen yönetilen Platform as a Service (PaaS) çözümüdür. Siz sadece uygulamanızı yazarsınız, App Engine altyapıyı, ölçeklendirmeyi, load balancing’i ve SSL sertifikalarını kendisi halleder.
İki farklı ortam sunuyor:
- Standard Environment: Belirli runtime’lar için optimize edilmiş, hızlı başlatma, ücretsiz tier mevcut, daha kısıtlı ama daha ucuz
- Flexible Environment: Docker container tabanlı, herhangi bir dil/runtime desteği, daha fazla kontrol ama minimum 1 instance her zaman çalışır yani maliyeti var
Şunu net söyleyelim: Eğer trafiği tahmin edilemeyen bir web uygulamanız veya API’niz varsa, ekibinizde DevOps kaynağı sınırlıysa ve hızlı bir şekilde deploy etmeniz gerekiyorsa, App Engine çok mantıklı bir tercih. Ama mikroservis mimarisi kuruyorsanız veya çok özel container gereksinimleriniz varsa, GKE veya Cloud Run daha iyi seçenekler olabilir.
Ön Gereksinimler ve Ortam Hazırlığı
Başlamadan önce birkaç şeyin hazır olması gerekiyor.
gcloud CLI kurulumu:
# Linux için
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud init
# Kurulumu doğrula
gcloud --version
Proje oluşturma ve yapılandırma:
# Yeni proje oluştur
gcloud projects create my-appengine-project --name="My App Engine Project"
# Projeyi aktif et
gcloud config set project my-appengine-project
# Billing hesabını bağla (zorunlu)
gcloud billing projects link my-appengine-project
--billing-account=BILLING_ACCOUNT_ID
# App Engine uygulaması oluştur ve region seç
gcloud app create --region=europe-west3
Region seçimi sonradan değiştirilemez, bu yüzden dikkatli seçin. Kullanıcılarınız Avrupa’daysa europe-west1 (Belçika) veya europe-west3 (Frankfurt) iyi seçenekler.
İlk Python Uygulamasını Deploy Etmek
Gerçek bir senaryo üzerinden gidelim: Basit bir Flask API’si deploy edeceğiz.
Proje yapısı:
my-flask-api/
├── main.py
├── requirements.txt
└── app.yaml
main.py dosyası:
from flask import Flask, jsonify, request
import os
app = Flask(__name__)
@app.route('/')
def hello():
return jsonify({
'message': 'Hello from App Engine!',
'environment': os.environ.get('APP_ENV', 'production')
})
@app.route('/health')
def health():
return jsonify({'status': 'healthy'}), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
app.yaml konfigürasyonu:
runtime: python311
instance_class: F2
automatic_scaling:
min_idle_instances: 0
max_idle_instances: 2
min_pending_latency: 30ms
max_pending_latency: automatic
max_concurrent_requests: 80
env_variables:
APP_ENV: "production"
LOG_LEVEL: "INFO"
handlers:
- url: /.*
script: auto
secure: always
Deploy işlemi:
cd my-flask-api
# requirements.txt oluştur
pip freeze > requirements.txt
# Deploy et
gcloud app deploy
# Uygulamayı tarayıcıda aç
gcloud app browse
# Logları takip et
gcloud app logs tail -s default
gcloud app deploy komutu çalıştığında ne olduğunu anlamak önemli. GCP, kaynak kodunuzu Cloud Build’e yükler, orada container image’ı build eder, image’ı Container Registry’e push eder ve ardından trafiği yeni versiyona yönlendirir. Tüm bu süreç genellikle 2-5 dakika sürer.
app.yaml’ı Derinlemesine Anlamak
app.yaml, App Engine’in beyni. Yanlış yapılandırılmış bir app.yaml hem performans sorunlarına hem de beklenmedik maliyetlere yol açabilir.
Scaling seçenekleri:
- automatic_scaling: Trafik yüküne göre otomatik scale up/down, standard environment’ta ücretsiz tier için idealdir
- manual_scaling: Sabit sayıda instance çalıştırır, tahmin edilebilir iş yükleri için uygundur
- basic_scaling: İstek geldiğinde instance başlatır, idle kalınca kapatır
Instance class seçimi kritik:
- F1: 256MB RAM, 600MHz CPU, en ucuz, basit uygulamalar için
- F2: 512MB RAM, 1.2GHz CPU, orta yük için önerilir
- F4: 1GB RAM, 2.4GHz CPU, memory-intensive uygulamalar için
- F4_1G: 2GB RAM, 2.4GHz CPU, büyük uygulamalar için
Flexible environment için ise:
- B1, B2, B4, B8: Background processing ve worker’lar için
Ortam Değişkenleri ve Secret Yönetimi
Production’da environment variable yönetimi kritik bir konu. Şifreler ve API anahtarları asla app.yaml’a yazılmamalı.
Secret Manager entegrasyonu:
# Secret Manager API'yi etkinleştir
gcloud services enable secretmanager.googleapis.com
# Secret oluştur
echo -n "super-secret-db-password" |
gcloud secrets create db-password --data-file=-
# App Engine servis hesabına erişim ver
gcloud secrets add-iam-policy-binding db-password
--member="serviceAccount:[email protected]"
--role="roles/secretmanager.secretAccessor"
Python kodunda Secret Manager kullanımı:
from google.cloud import secretmanager
import os
def get_secret(secret_id, project_id=None):
if project_id is None:
project_id = os.environ.get('GOOGLE_CLOUD_PROJECT')
client = secretmanager.SecretManagerServiceClient()
name = f"projects/{project_id}/secrets/{secret_id}/versions/latest"
response = client.access_secret_version(request={"name": name})
return response.payload.data.decode("UTF-8")
# Kullanımı
DB_PASSWORD = get_secret('db-password')
Bu yaklaşımla hassas bilgiler ne kaynak kodunda ne de app.yaml’da bulunur. Secret Manager versiyonlama desteklediği için rotasyon da çok kolaylaşır.
Çoklu Servis (Microservices) Mimarisi
Gerçek dünya projelerinde genellikle tek servis yetmez. App Engine, default servisi yanında ek servisler oluşturmanıza imkan tanır.
Diyelim ki bir e-ticaret uygulaması yapıyorsunuz:
defaultservisi: Ana web uygulamasıapiservisi: REST API backendworkerservisi: Background job işleyici
API servisi için ayrı app.yaml:
service: api
runtime: python311
instance_class: F2
automatic_scaling:
max_instances: 10
min_instances: 1
target_cpu_utilization: 0.65
env_variables:
SERVICE_NAME: "api"
DATABASE_URL: "postgresql://..."
handlers:
- url: /api/.*
script: auto
secure: always
Worker servisi için:
service: worker
runtime: python311
instance_class: B2
manual_scaling:
instances: 2
env_variables:
SERVICE_NAME: "worker"
handlers:
- url: /.*
script: auto
Servisleri deploy etmek:
# API servisini deploy et
cd api-service
gcloud app deploy app.yaml
# Worker servisini deploy et
cd ../worker-service
gcloud app deploy app.yaml
# Tüm servislerin listesini gör
gcloud app services list
# Belirli servisin versiyonlarını gör
gcloud app versions list --service=api
Traffic Splitting ve Blue-Green Deployment
App Engine’in en güçlü özelliklerinden biri traffic splitting. Yeni bir versiyon deploy ettiğinizde trafiği kademeli olarak yeni versiyona yönlendirebilirsiniz.
# Yeni versiyonu %0 trafik ile deploy et (hiç canlıya almadan test için)
gcloud app deploy --no-promote
# Mevcut versiyonları listele
gcloud app versions list
# Trafiği ikiye böl: %80 eski, %20 yeni
gcloud app services set-traffic default
--splits v1=0.8,v2=0.2
--split-by=random
# Her şey iyiyse %100 yeni versiyona geç
gcloud app services set-traffic default
--splits v2=1.0
# Sorun çıkarsa anında eski versiyona dön
gcloud app services set-traffic default
--splits v1=1.0
--split-by parametresi üç seçenek alır:
- random: Rastgele dağılım, en basit yöntem
- ip: Aynı IP her zaman aynı versiyona gider
- cookie: Cookie tabanlı, A/B test için idealdir
Bu özellik sayesinde canary deployment yapabilirsiniz. Üretim ortamında bir şeyler ters giderse tek komutla eski versiyona dönmek hayat kurtarır.
Cron Job ve Task Queue Yönetimi
App Engine’in yerleşik cron job sistemi var. Zamanlanmış görevler için ayrı bir servis kurmaya gerek yok.
cron.yaml oluşturma:
cron:
- description: "Günlük rapor oluştur"
url: /tasks/daily-report
schedule: every day 02:00
timezone: Europe/Istanbul
retry_parameters:
job_retry_limit: 3
- description: "Cache temizle"
url: /tasks/clear-cache
schedule: every 6 hours
- description: "Haftalık özet maili"
url: /tasks/weekly-summary
schedule: every monday 09:00
timezone: Europe/Istanbul
Cron’u deploy et:
gcloud app deploy cron.yaml
# Aktif cron job'ları gör
gcloud app describe
dispatch.yaml ile URL yönlendirme:
dispatch:
- url: "*/api/*"
service: api
- url: "*/worker/*"
service: worker
- url: "*/*"
service: default
gcloud app deploy dispatch.yaml
Monitoring ve Loglama
Uygulamayı deploy ettiniz ama işin zor kısmı izleme. App Engine, Cloud Monitoring ve Cloud Logging ile sıkı entegrasyon sunar.
Structured logging:
import logging
import json
from flask import request
class StructuredLogger:
def __init__(self, name):
self.logger = logging.getLogger(name)
def log(self, severity, message, **kwargs):
entry = {
'severity': severity,
'message': message,
'httpRequest': {
'requestMethod': request.method if request else None,
'requestUrl': request.url if request else None,
}
}
entry.update(kwargs)
print(json.dumps(entry))
def info(self, message, **kwargs):
self.log('INFO', message, **kwargs)
def error(self, message, **kwargs):
self.log('ERROR', message, **kwargs)
logger = StructuredLogger(__name__)
gcloud ile log sorguları:
# Son 1 saatin ERROR logları
gcloud logging read
"resource.type=gae_app AND severity=ERROR"
--freshness=1h
--format="table(timestamp, textPayload)"
# Belirli servisin logları
gcloud logging read
"resource.type=gae_app AND resource.labels.module_id=api"
--freshness=6h
# Canlı log takibi
gcloud app logs tail -s api --level=warning
Alerting policy oluşturma:
# 5xx hata oranı %5'i geçerse alarm ver
gcloud alpha monitoring policies create
--notification-channels=CHANNEL_ID
--display-name="App Engine High Error Rate"
--condition-display-name="5xx Rate"
--condition-filter='resource.type="gae_app" metric.type="appengine.googleapis.com/http/server/response_count" metric.labels.response_code_class="5xx"'
Maliyet Optimizasyonu
App Engine’de maliyet kontrolü yapmak çok önemli. Yanlış konfigürasyonla fatura sürpriziyle karşılaşabilirsiniz.
Dikkat edilmesi gereken noktalar:
- min_idle_instances: Bu değeri 0 yapın; eğer uygulamanız 24/7 aktif olmak zorunda değilse sıfır idle instance tutun
- Flexible Environment tuzağı: Flexible’da minimum 1 instance her zaman çalışır, aylık yaklaşık 30-40 dolar maliyeti olur
- Versiyon biriktirme: Eski versiyonları silmezseniz gereksiz depolama maliyeti oluşur
- Cloud Build ücreti: Her deploy bir build tetikler, ücretsiz kota aşılabilir
Eski versiyonları temizleme:
# Tüm versiyonları listele
gcloud app versions list --sort-by=~LAST_DEPLOYED
# Belirli versiyon sil
gcloud app versions delete v20240101 --service=default
# Trafiği olmayan tüm versiyonları tek komutla sil
gcloud app versions list
--filter="traffic_split=0"
--format="value(id,service)" |
while read version service; do
gcloud app versions delete $version --service=$service --quiet
done
CI/CD Pipeline Entegrasyonu
Manuel deploy yapmak hata yaratır. Cloud Build ile otomatik pipeline kuralım.
cloudbuild.yaml:
steps:
# Unit testleri çalıştır
- name: 'python:3.11'
entrypoint: 'bash'
args:
- '-c'
- |
pip install -r requirements.txt
python -m pytest tests/ -v --tb=short
# Staging'e deploy et
- name: 'gcr.io/cloud-builders/gcloud'
args:
- 'app'
- 'deploy'
- 'app-staging.yaml'
- '--project=$PROJECT_ID'
- '--no-promote'
- '--version=staging-$SHORT_SHA'
# Smoke test çalıştır
- name: 'curlimages/curl'
args:
- '-f'
- 'https://staging-dot-my-app.ew.r.appspot.com/health'
# Production'a deploy et (sadece main branch)
- name: 'gcr.io/cloud-builders/gcloud'
args:
- 'app'
- 'deploy'
- 'app.yaml'
- '--project=$PROJECT_ID'
- '--version=prod-$SHORT_SHA'
id: 'deploy-production'
timeout: '1200s'
options:
logging: CLOUD_LOGGING_ONLY
# Cloud Build trigger oluştur (GitHub entegrasyonu)
gcloud builds triggers create github
--repo-name=my-flask-api
--repo-owner=myusername
--branch-pattern=^main$
--build-config=cloudbuild.yaml
Sık Karşılaşılan Sorunlar ve Çözümleri
“Quota exceeded” hatası:
App Engine’de bazı varsayılan kotalar oldukça düşük. Özellikle yeni projelerde bunu görürsünüz.
# Mevcut kota kullanımını kontrol et
gcloud compute project-info describe --project=my-appengine-project
# Kota artışı için istek aç (Cloud Console'dan)
# IAM & Admin -> Quotas bölümünden yapılır
Cold start problemi:
Standard environment’ta instance’lar uzun süre boşta kalırsa kapatılır ve ilk istek yavaş gelir. Çözüm:
automatic_scaling:
min_idle_instances: 1 # Her zaman 1 instance sıcak tut
min_pending_latency: 10ms
Memory limit aşımı:
App Engine’de instance belleği aşılırsa process restart edilir. Bellek kullanımını izleyin:
# Memory metrics'i gör
gcloud monitoring metrics list
--filter="metric.type:appengine AND memory"
Eğer sürekli OOM (Out of Memory) alıyorsanız ya instance class’ı yükseltin ya da uygulama seviyesinde bellek optimizasyonu yapın.
Sonuç
App Engine, doğru kullanım senaryosunda gerçekten değerli bir araç. Küçük ve orta ölçekli uygulamalar, API servisleri, dahili araçlar için mükemmel bir seçenek. Altyapı yönetimi yerine uygulama geliştirmeye odaklanmak istiyorsanız bu platformu ciddi ciddi değerlendirmenizi öneririm.
Ancak şunu da belirtmek gerekir: App Engine bir silver bullet değil. Çok özel networking gereksinimleri, stateful uygulamalar veya özelleştirilmiş runtime ihtiyaçlarınız varsa Cloud Run ya da GKE daha uygun seçenekler olabilir. Platform seçimi her zaman iş gereksinimlerine, ekip kapasitesine ve maliyet beklentilerine göre yapılmalı.
Bu yazıda anlattıklarımı adım adım uygulayarak başlayın. İlk deploy’u yapın, logları inceleyin, scaling davranışını gözlemleyin. App Engine’i tanımanın en iyi yolu üzerinde çalışmak. Sorularınız olursa yorumlarda buluşalım.
