← Kursa Dön
📄 Text · 22 min

Cloud Deployment: AWS ve GCP Temelleri

Giriş — Kendi Evin mi, Kiralık Daire mi?

Bir yazılım şirketi kurduğunu düşün. İki seçeneğin var:

On-premise (kendi evin): Sunucu odası kur, sunucuları satın al, rack'lere yerleştir, soğutma sistemi kur, elektrik kesintisine karşı UPS al, güvenlik duvarı konfigüre et, yedek sunucu hazır tut, bir de bunları yönetecek ekip kur. İlk yatırım: yüz binlerce dolar. Ayda 500 kullanıcı da gelse, 5 milyon da gelse aynı altyapıyı taşıyorsun.

Cloud (kiralık daire): AWS veya GCP'ye kaydol, kredi kartını gir, 5 dakikada sunucu ayağa kaldır. Kullanıcılar artınca kapasiteyi artır, azalınca küçült. Sadece kullandığın kadar öde. İlk yatırım: 0 dolar.

Cloud computing, başkasının bilgisayarını kullanmaktır — ama bu "başkası" dünyanın en büyük altyapı şirketleri: Amazon (AWS), Google (GCP), Microsoft (Azure). Bu şirketler milyarlarca dolar yatırım yaparak dünyanın dört bir yanına data center'lar kurmuş ve bu altyapıyı API üzerinden herkese kiralıyor.


On-Premise vs Cloud — Karşılaştırma

ÖzellikOn-PremiseCloud
İlk maliyetÇok yüksek (sunucu, oda, soğutma)Sıfıra yakın (kullandıkça öde)
ÖlçeklemeHaftalarca sürer (sipariş, kurulum)Dakikalar içinde (API çağrısı)
BakımSenin sorumluluğun (7/24 ekip)Provider'ın sorumluluğu
GüvenlikTam kontrolPaylaşımlı sorumluluk modeli
EsneklikDüşük (aldığın sunucu kadar)Yüksek (sınırsız kaynak havuzu)
Veri lokasyonuTam kontrol (regülasyon uyumu)Bölge seçimi var ama provider'a güven
Uzun vadeli maliyetÖngörülebilir (sabit maliyet)Değişken (trafik artarsa fatura artar)

Cloud her zaman doğru seçim mi? Hayır. Bankalar, savunma sanayi, sağlık sektörü gibi regülasyonların ağır olduğu alanlarda on-premise veya hibrit (on-prem + cloud) model tercih edilir. Ama startup'lar, SaaS ürünleri, e-ticaret siteleri için cloud neredeyse tek mantıklı seçenek.


AWS (Amazon Web Services) — En Büyük Bulut

AWS, dünya cloud pazarının yaklaşık %31'ine sahip en büyük bulut sağlayıcısıdır. 200'den fazla servisi var ama Spring Boot geliştirici olarak ihtiyacın olan temel servisleri görelim.

EC2 (Elastic Compute Cloud) — Sanal Sunucu

EC2, AWS'nin sanal makine servisidir. Bir Linux veya Windows sunucusu kirala, SSH ile bağlan, istediğini kur. En temel ama en esnek seçenek.

# EC2'ye Spring Boot uygulaması deploy etme

# 1. JAR oluştur
./mvnw clean package -DskipTests

# 2. JAR'ı EC2'ye kopyala
scp -i my-key.pem target/myapp-1.0.0.jar ec2-user@54.123.45.67:~/

# 3. EC2'ye bağlan
ssh -i my-key.pem ec2-user@54.123.45.67

# 4. Java kur (Amazon Corretto — AWS'nin OpenJDK dağıtımı)
sudo yum install -y java-21-amazon-corretto-headless

# 5. Uygulamayı systemd servisi olarak çalıştır
sudo tee /etc/systemd/system/myapp.service << 'EOF'
[Unit]
Description=My Spring Boot App
After=network.target

[Service]
Type=simple
User=ec2-user
ExecStart=/usr/bin/java -jar /home/ec2-user/myapp-1.0.0.jar --spring.profiles.active=production
Restart=always
RestartSec=10
Environment=JAVA_OPTS=-Xmx512m -Xms256m

[Install]
WantedBy=multi-user.target
EOF

# 6. Servisi başlat
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp

# 7. Log takibi
journalctl -u myapp -f

EC2 en temel yaklaşım ama en çok bakım gerektiren yöntem. İşletim sistemi güncellemeleri, güvenlik yamaları, disk yönetimi, log rotasyonu — hepsi senin sorumluluğunda. Küçük projeler için pratik ama büyüdükçe managed servislere geçmek mantıklı.

RDS (Relational Database Service) — Yönetilen Veritabanı

RDS, veritabanını senin yerine AWS yönetir. Yedekleme, güncelleme, failover, replikasyon — hepsi otomatik.

# application-production.yml — RDS bağlantısı
spring:
  datasource:
    url: jdbc:postgresql://${RDS_HOSTNAME}:5432/${RDS_DB_NAME}
    username: ${RDS_USERNAME}
    password: ${RDS_PASSWORD}
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000

  jpa:
    hibernate:
      ddl-auto: validate  # Production'da her zaman validate!
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect

RDS'in en büyük avantajı Multi-AZ deployment. Birincil veritabanın çökerse, saniyeler içinde yedek veritabanına otomatik geçiş yapar. Manuel failover yapmana gerek yok.

S3 (Simple Storage Service) — Dosya Depolama

S3, dosya depolamak için kullanılır. Kullanıcı profil fotoğrafları, raporlar, loglar, yedekler — hepsi S3'te saklanır. Spring Boot ile S3 entegrasyonu:

@Service
public class S3StorageService {

    private final S3Client s3Client;
    private final String bucketName;

    public S3StorageService(
            @Value("${aws.s3.bucket}") String bucketName,
            @Value("${aws.region}") String region) {
        this.bucketName = bucketName;
        this.s3Client = S3Client.builder()
            .region(Region.of(region))
            .build();
    }

    // Dosya yükle
    public String uploadFile(String key, byte[] content, String contentType) {
        s3Client.putObject(
            PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)  // "uploads/2024/profile-photo.jpg"
                .contentType(contentType)
                .build(),
            RequestBody.fromBytes(content)
        );

        return String.format("https://%s.s3.amazonaws.com/%s", bucketName, key);
    }

    // Dosya indir
    public byte[] downloadFile(String key) {
        ResponseBytes<GetObjectResponse> response = s3Client.getObjectAsBytes(
            GetObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build()
        );
        return response.asByteArray();
    }

    // Dosya sil
    public void deleteFile(String key) {
        s3Client.deleteObject(
            DeleteObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build()
        );
    }
}
<!-- pom.xml — AWS S3 SDK -->
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.25.0</version>
</dependency>

ECS/Fargate — Container Orkestrasyonu

ECS (Elastic Container Service), Docker container'larını AWS üzerinde çalıştırır. Fargate mode'unda sunucu yönetimi bile gerekmez — sadece Docker image'ını ver, kaç container istediğini söyle, gerisini AWS halleder.

// ECS Task Definition — Fargate
{
  "family": "myapp-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "containerDefinitions": [
    {
      "name": "myapp",
      "image": "123456789.dkr.ecr.eu-west-1.amazonaws.com/myapp:latest",
      "portMappings": [
        {
          "containerPort": 8080,
          "protocol": "tcp"
        }
      ],
      "environment": [
        { "name": "SPRING_PROFILES_ACTIVE", "value": "production" }
      ],
      "secrets": [
        {
          "name": "RDS_PASSWORD",
          "valueFrom": "arn:aws:secretsmanager:eu-west-1:123456789:secret:myapp/rds-password"
        }
      ],
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      },
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/myapp",
          "awslogs-region": "eu-west-1",
          "awslogs-stream-prefix": "myapp"
        }
      }
    }
  ]
}

EC2 vs ECS/Fargate kararı basit: Docker kullanıyorsan ve sunucu yönetmek istemiyorsan → Fargate. Daha fazla kontrol ve maliyet optimizasyonu istiyorsan → EC2. Fargate birim fiyat olarak daha pahalı ama operasyonel maliyeti (zaman, insan gücü) çok düşük.

Elastic Beanstalk — En Kolay Yol

Elastic Beanstalk, Spring Boot uygulamasını deploy etmenin en kolay yolu. JAR dosyasını yükle, gerisini AWS halleder: EC2, load balancer, auto-scaling, monitoring, log yönetimi.

# Elastic Beanstalk CLI ile deploy

# 1. EB CLI kur
pip install awsebcli

# 2. Proje dizininde EB başlat
eb init myapp --platform "Corretto 21 running on 64bit Amazon Linux 2023" --region eu-west-1

# 3. Ortam oluştur (ilk deploy)
eb create production \
  --instance_type t3.small \
  --database.engine postgres \
  --database.instance db.t3.micro \
  --envvars SPRING_PROFILES_ACTIVE=production

# 4. Sonraki deploy'lar
./mvnw clean package -DskipTests
eb deploy

# 5. Logları görüntüle
eb logs

# 6. Uygulamayı aç
eb open

Elastic Beanstalk, başlangıç için mükemmel ama ölçeklendikçe sınırlarına ulaşırsın. Daha fazla kontrol istediğinde ECS/Fargate'e geçiş yaparsın.


GCP (Google Cloud Platform) — Google'ın Bulutu

GCP, AWS'den sonra üçüncü büyük bulut sağlayıcıdır (Azure ikinci). Google'ın kendi iç altyapısında kullandığı teknolojileri sunar. Kubernetes'in doğduğu yer — container orkestrasyonunda güçlü.

Compute Engine — Sanal Sunucu

AWS'nin EC2'sine karşılık gelir. Sanal makine oluştur, SSH ile bağlan, istediğini kur.

# GCP Compute Engine'de Spring Boot deploy

# 1. VM oluştur
gcloud compute instances create myapp-server \
  --zone=europe-west1-b \
  --machine-type=e2-small \
  --image-family=ubuntu-2204-lts \
  --image-project=ubuntu-os-cloud \
  --boot-disk-size=20GB \
  --tags=http-server

# 2. Firewall kuralı (8080 portunu aç)
gcloud compute firewall-rules create allow-8080 \
  --allow=tcp:8080 \
  --target-tags=http-server

# 3. SSH ile bağlan
gcloud compute ssh myapp-server --zone=europe-west1-b

# 4. Java kur ve JAR'ı çalıştır (EC2 ile aynı mantık)
sudo apt update && sudo apt install -y openjdk-21-jre-headless
# JAR'ı kopyala ve systemd servisi oluştur (AWS örneğiyle aynı)

Cloud SQL — Yönetilen Veritabanı

AWS RDS'in GCP karşılığı. PostgreSQL, MySQL, SQL Server destekler.

# application-gcp.yml — Cloud SQL bağlantısı
spring:
  datasource:
    # Cloud SQL Proxy ile bağlantı (önerilen yöntem)
    url: jdbc:postgresql://127.0.0.1:5432/${DB_NAME}
    username: ${DB_USER}
    password: ${DB_PASSWORD}
    hikari:
      maximum-pool-size: 15

  # Alternatif: Spring Cloud GCP ile otomatik bağlantı
  cloud:
    gcp:
      sql:
        database-name: myapp-db
        instance-connection-name: my-project:europe-west1:myapp-sql

Cloud SQL Proxy, veritabanına güvenli bağlantı sağlar. Uygulaman localhost:5432'ye bağlanır, proxy arkaplanda GCP'ye şifreli tünel kurar. Veritabanını public IP'ye açmana gerek kalmaz.

Cloud Run — Serverless Container

Cloud Run, GCP'nin en pratik servisidir. Docker image'ını ver, gerisini Google halleder. Trafik yokken sıfıra ölçeklenir — sadece kullanıldığında para ödersin.

# Cloud Run'a Spring Boot deploy etme

# 1. Docker image oluştur ve push et
gcloud builds submit --tag gcr.io/my-project/myapp:1.0.0

# 2. Cloud Run'a deploy et
gcloud run deploy myapp \
  --image gcr.io/my-project/myapp:1.0.0 \
  --platform managed \
  --region europe-west1 \
  --port 8080 \
  --memory 512Mi \
  --cpu 1 \
  --min-instances 0 \
  --max-instances 10 \
  --set-env-vars "SPRING_PROFILES_ACTIVE=production" \
  --set-secrets "DB_PASSWORD=myapp-db-password:latest" \
  --allow-unauthenticated

# 3. URL'i al
gcloud run services describe myapp --region europe-west1 --format='value(status.url)'
# https://myapp-xyz123.a.run.app

Cloud Run, Spring Boot için çok uygun. Ama bir dikkat noktası var: cold start. Trafik yokken instance sıfıra düşer. İlk istek geldiğinde yeni instance başlatılır — Spring Boot'un başlama süresi (genelde 3-10 saniye) cold start süresine eklenir. min-instances: 1 ile en az bir instance'ı daima ayakta tutabilirsin ama bu durumda sürekli ödeme yaparsın.

App Engine — Platform as a Service

Elastic Beanstalk'ın GCP karşılığı. JAR dosyasını yükle, gerisini Google halleder.

# app.yaml — App Engine konfigürasyonu
runtime: java21
instance_class: F2  # 512MB RAM, 0.6 GHz CPU

env_variables:
  SPRING_PROFILES_ACTIVE: production

automatic_scaling:
  min_instances: 1
  max_instances: 5
  target_cpu_utilization: 0.7
# Deploy
gcloud app deploy

# Logları gör
gcloud app logs tail

AWS vs GCP — Hangisini Seçmeli?

ÖzellikAWSGCP
Pazar payı~%31 (en büyük)~%12 (üçüncü)
Servis sayısı200+100+
KubernetesEKS (iyi ama karmaşık)GKE (en iyi K8s deneyimi)
ServerlessLambda + FargateCloud Run + Cloud Functions
FiyatlandırmaKarmaşık, committed use indirimiDaha şeffaf, sustained use indirimi
ToplulukEn büyük topluluk ve dokümantasyonDaha küçük ama büyüyen topluluk
Güçlü yanıServis çeşitliliği, enterpriseData/ML, Kubernetes, BigQuery

Pratikte çoğu ekip takımın deneyimine göre seçer. AWS bilen ekip AWS kullanır, GCP bilen GCP. İkisi de Spring Boot uygulaması çalıştırmak için fazlasıyla yeterli.


Spring Boot JAR → Docker → Cloud Deploy Akışı

Cloud'a deploy etmenin en yaygın yolu: JAR → Docker → Container Registry → Cloud Servisi. Bu akış tüm cloud provider'larda aynıdır.

Adım 1: Dockerfile

# Dockerfile — Multi-stage build (küçük ve güvenli image)
# === Build aşaması ===
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY .mvn/ .mvn/
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline  # Dependency'leri cache'le
COPY src/ src/
RUN ./mvnw clean package -DskipTests

# === Runtime aşaması ===
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app

# Güvenlik: root olmayan kullanıcı
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

# JAR kopyala
COPY --from=builder /app/target/*.jar app.jar

# JVM optimizasyonları
ENV JAVA_OPTS="-XX:+UseContainerSupport \
               -XX:MaxRAMPercentage=75.0 \
               -XX:+UseG1GC \
               -Djava.security.egd=file:/dev/./urandom"

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=40s \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

Bu Dockerfile'da birkaç önemli detay var:

  • Multi-stage build: Build aşamasında JDK kullanılır (400MB+), runtime'da sadece JRE (150MB). Final image küçük ve güvenli

  • `UseContainerSupport`: JVM'in container'daki bellek limitini doğru okumasını sağlar. Bu flag olmadan JVM host'un tüm belleğini kullanmaya çalışabilir

  • `MaxRAMPercentage=75.0`: Container'a ayrılan belleğin %75'ini heap için kullan. Geri kalanı metaspace, thread stack, native bellek için

  • Non-root user: Container'ı root olarak çalıştırmamak güvenlik best practice'idir

Adım 2: Build ve Push

# Lokal build ve test
docker build -t myapp:1.0.0 .
docker run -p 8080:8080 myapp:1.0.0

# AWS ECR'a push
aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin 123456789.dkr.ecr.eu-west-1.amazonaws.com
docker tag myapp:1.0.0 123456789.dkr.ecr.eu-west-1.amazonaws.com/myapp:1.0.0
docker push 123456789.dkr.ecr.eu-west-1.amazonaws.com/myapp:1.0.0

# GCP Artifact Registry'ye push
gcloud auth configure-docker europe-west1-docker.pkg.dev
docker tag myapp:1.0.0 europe-west1-docker.pkg.dev/my-project/myapp/myapp:1.0.0
docker push europe-west1-docker.pkg.dev/my-project/myapp/myapp:1.0.0

Adım 3: Spring Boot Docker Profili

# application-docker.yml — Container ortamına özel ayarlar
server:
  port: 8080
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

  # Container ortamında external config
  config:
    import: optional:configserver:, optional:file:/config/

  datasource:
    url: jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:myapp}
    username: ${DB_USERNAME:myapp}
    password: ${DB_PASSWORD:secret}

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      probes:
        enabled: true

logging:
  pattern:
    # JSON format — cloud log aggregation araçlarıyla uyumlu
    console: '{"timestamp":"%d{ISO8601}","level":"%level","logger":"%logger{36}","message":"%msg","thread":"%thread"}%n'

⚠️ Logging pattern'i JSON formatına çevirmek cloud ortamında kritik. AWS CloudWatch, GCP Cloud Logging gibi araçlar JSON logları otomatik parse eder. Plain text logları ise tek bir string olarak gösterir — filtreleme ve arama zorlaşır.


Secrets Yönetimi — Şifreleri Nereye Koymalı?

Veritabanı şifreleri, API key'leri, JWT secret'ları — bunları asla kaynak koduna veya Docker image'ına gömme. Her cloud provider'ın bir secret management servisi var.

AWS Secrets Manager

// AWS Secrets Manager ile secret okuma
@Configuration
public class SecretsConfig {

    @Bean
    public DataSource dataSource() {
        // AWS SDK ile secret oku
        SecretsManagerClient client = SecretsManagerClient.builder()
            .region(Region.EU_WEST_1)
            .build();

        GetSecretValueResponse response = client.getSecretValue(
            GetSecretValueRequest.builder()
                .secretId("myapp/database-credentials")
                .build()
        );

        // Secret JSON formatında: {"username":"admin","password":"s3cret"}
        JsonNode secret = new ObjectMapper()
            .readTree(response.secretString());

        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:postgresql://mydb.rds.amazonaws.com:5432/myapp");
        ds.setUsername(secret.get("username").asText());
        ds.setPassword(secret.get("password").asText());
        return ds;
    }
}

Environment Variable Yaklaşımı (Daha Basit)

Çoğu durumda secret'ları environment variable olarak enjekte etmek yeterli:

# docker-compose.yml veya ECS Task Definition'da
environment:
  - DB_PASSWORD=${DB_PASSWORD}  # CI/CD pipeline'dan gelir

# Kubernetes'te Secret objesi
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secrets
type: Opaque
data:
  db-password: cDRzc3cwcmQ=  # base64 encoded
---
# Pod'a mount etme
env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: myapp-secrets
        key: db-password

Spring Boot'ta ${DB_PASSWORD} placeholder'ı otomatik olarak environment variable'dan çözümlenir. Bu yaklaşım basit, taşınabilir ve tüm cloud provider'larda çalışır.

💡 Secret rotation (şifre döndürme) unutulmamalı. AWS Secrets Manager otomatik rotation destekler — belirlediğin aralıklarla (30, 60, 90 gün) şifreler otomatik değiştirilir. Uygulamanın yeniden başlatılmasına gerek kalmaz çünkü her bağlantıda güncel secret okunur.


Auto-Scaling — Trafik Arttığında Otomatik Büyüme

Auto-scaling, trafik arttığında otomatik olarak instance ekler, azaldığında kaldırır. Spring Boot uygulaması için en yaygın scaling metrikleri CPU kullanımı ve istek sayısıdır.

AWS Auto Scaling

// AWS Auto Scaling Group konfigürasyonu
{
  "AutoScalingGroupName": "myapp-asg",
  "LaunchTemplate": {
    "LaunchTemplateId": "lt-0abc123",
    "Version": "$Latest"
  },
  "MinSize": 2,
  "MaxSize": 10,
  "DesiredCapacity": 2,
  "TargetGroupARNs": ["arn:aws:elasticloadbalancing:..."],
  "HealthCheckType": "ELB",
  "HealthCheckGracePeriod": 120,
  "Tags": [
    { "Key": "Environment", "Value": "production" }
  ]
}
// Scaling Policy — CPU %70'i aştığında scale-up
{
  "PolicyName": "cpu-target-tracking",
  "PolicyType": "TargetTrackingScaling",
  "TargetTrackingConfiguration": {
    "PredefinedMetricSpecification": {
      "PredefinedMetricType": "ASGAverageCPUUtilization"
    },
    "TargetValue": 70.0,
    "ScaleInCooldown": 300,
    "ScaleOutCooldown": 60
  }
}

ScaleOutCooldown: 60 — yeni instance ekledikten sonra 60 saniye bekle, tekrar scale etme. ScaleInCooldown: 300 — instance kaldırdıktan sonra 5 dakika bekle. Scale-in'de daha yavaş hareket etmek önemli çünkü ani trafik düşüşlerinde gereksiz yere instance kaldırılıp tekrar eklenmesini önler.

Kubernetes HPA (Horizontal Pod Autoscaler)

# k8s-hpa.yaml — Kubernetes auto-scaling
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
        - type: Pods
          value: 2          # Aynı anda en fazla 2 pod ekle
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Pods
          value: 1          # Aynı anda en fazla 1 pod kaldır
          periodSeconds: 120

Maliyet Optimizasyonu — Cloud Faturasını Kontrol Altında Tutmak

Cloud'un en büyük tuzağı: fatura şoku. "Kullandıkça öde" modeli, kontrolsüz kullanımda sürpriz faturalara yol açar.

Temel Tasarruf Yöntemleri

YöntemAçıklamaTasarruf
Right-sizingGerçek kullanıma göre boyutlandır (Dev: t3.micro, Prod: t3.medium)%30-50
Reserved/Committed1-3 yıllık taahhütle indirim (stable workload'lar)%30-60
Spot/PreemptibleKesintiye toleranslı iş yükleri için (batch, test)%70-90
Auto-scaling + ScheduleGece/hafta sonu instance sayısını düşür%40-60
Unused resource temizliğiHaftalık kontrol: boş EBS, idle RDS, kullanılmayan IPDeğişken

Spring Boot Seviyesinde Optimizasyon

# application-production.yml — Kaynak optimizasyonu
spring:
  datasource:
    hikari:
      # DB bağlantı havuzu — gereğinden fazla bağlantı açma
      maximum-pool-size: 10     # Default 10, çoğu uygulama için yeterli
      minimum-idle: 2           # Boşta minimum 2 bağlantı
      idle-timeout: 300000      # 5 dakika boşta kalan bağlantıyı kapat
      max-lifetime: 1800000     # 30 dakikada bir bağlantıyı yenile

  jpa:
    open-in-view: false  # Lazy loading tuzağını kapat, DB bağlantısını erken bırak
    properties:
      hibernate:
        jdbc:
          batch_size: 25
        order_inserts: true
        order_updates: true

server:
  tomcat:
    threads:
      max: 50      # Varsayılan 200 — çoğu uygulama için fazla
      min-spare: 5
    max-connections: 200
    accept-count: 50

open-in-view: false ayarı çok önemli. Varsayılan true'da Hibernate session'ı tüm HTTP isteği boyunca açık kalır — veritabanı bağlantısı gereksiz yere tutulur. false yaparak bağlantıyı service katmanı bittiğinde serbest bırakırsın. Bu, daha az bağlantı havuzu boyutuyla daha fazla concurrent isteği karşılayabilmeni sağlar.

⚠️ Cloud faturası kontrolden çıkmadan önce "billing alert" kur. AWS'de CloudWatch Billing Alarm, GCP'de Budget & Alerts ile aylık bütçe belirle. Bütçenin %50, %80 ve %100'ünde email bildirimi al. Bu basit adım, binlerce dolarlık sürpriz faturaları önler.


Tam Deploy Akışı — Uçtan Uca

Tüm parçaları birleştirelim. Bir Spring Boot uygulamasının geliştirmeden production'a kadar olan yolculuğu:

Developer                CI/CD Pipeline              Cloud (AWS örneği)
─────────                ──────────────              ─────────────────
git push → main     →    1. Build (Maven)        →   
                         2. Test (Unit + Integration)
                         3. Docker build           →   
                         4. Push to ECR            →   ECR (Image Registry)
                         5. Deploy to ECS/Fargate  →   ECS Task (Container)
                                                       ↓
                                                   ALB (Load Balancer)
                                                       ↓
                                                   Target Group (Health Check)
                                                       ↓
                                                   Auto Scaling Group
                                                       ↓
                                                   RDS (PostgreSQL)
                                                   S3 (Dosyalar)
                                                   Secrets Manager (Şifreler)
                                                   CloudWatch (Loglar + Metrikler)
#!/bin/bash
# deploy.sh — Uçtan uca deploy scripti (AWS ECS Fargate)

set -e  # Hata olursa dur

APP_NAME="myapp"
AWS_REGION="eu-west-1"
ECR_REPO="123456789.dkr.ecr.${AWS_REGION}.amazonaws.com/${APP_NAME}"
CLUSTER="production"
SERVICE="myapp-service"
VERSION=$(git rev-parse --short HEAD)  # Git commit hash'ini versiyon olarak kullan

echo "=== 1. Build ==="
./mvnw clean package -DskipTests

echo "=== 2. Docker Build ==="
docker build -t ${APP_NAME}:${VERSION} .

echo "=== 3. Push to ECR ==="
aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ECR_REPO}
docker tag ${APP_NAME}:${VERSION} ${ECR_REPO}:${VERSION}
docker tag ${APP_NAME}:${VERSION} ${ECR_REPO}:latest
docker push ${ECR_REPO}:${VERSION}
docker push ${ECR_REPO}:latest

echo "=== 4. Update ECS Service ==="
aws ecs update-service \
  --cluster ${CLUSTER} \
  --service ${SERVICE} \
  --force-new-deployment \
  --region ${AWS_REGION}

echo "=== 5. Wait for Deployment ==="
aws ecs wait services-stable \
  --cluster ${CLUSTER} \
  --services ${SERVICE} \
  --region ${AWS_REGION}

echo "=== Deploy tamamlandı! Versiyon: ${VERSION} ==="

Bu script, geliştirici git push yaptığında CI/CD pipeline tarafından çalıştırılır. Maven build, Docker image oluşturma, ECR'a push, ECS service güncelleme ve stabilite bekleme — tüm adımlar otomatik.


Özet

  • Cloud deployment, on-premise'e göre esneklik, ölçeklenebilirlik ve düşük başlangıç maliyeti sağlar — startup'lar ve SaaS ürünleri için neredeyse tek mantıklı seçenek, regülasyon gerektiren sektörlerde hibrit model tercih edilir

  • AWS servisleri katmanlı bir yapı sunar: EC2 (tam kontrol), ECS/Fargate (container yönetimi), Elastic Beanstalk (en kolay deploy) — proje büyüdükçe daha managed servislere geçiş mantıklıdır

  • GCP servisleri benzer bir yapı sunar: Compute Engine (sanal sunucu), Cloud Run (serverless container), App Engine (PaaS) — özellikle Kubernetes (GKE) deneyimi en iyisidir

  • Spring Boot → Docker → Cloud akışı tüm provider'larda aynıdır: multi-stage Dockerfile ile küçük image oluştur, container registry'ye push et, managed servis üzerinde çalıştır

  • Secrets yönetimi kritik öneme sahiptir — şifreleri asla kaynak koduna veya Docker image'ına gömme, AWS Secrets Manager veya environment variable ile enjekte et, secret rotation uygula

  • Maliyet optimizasyonu sürekli bir süreçtir — right-sizing, reserved/committed instances, auto-scaling, scheduled scaling ve unused resource temizliği ile cloud faturasını kontrol altında tut