AWS Elastic Beanstalk ile Uygulama Dağıtımı

Yıllardır sunucu kurup uygulama deploy etmekle uğraştıysanız, bir noktada şunu düşünmüşsünüzdür: “Bu işin daha az acı veren bir yolu olmalı.” İşte tam bu noktada AWS Elastic Beanstalk devreye giriyor. PaaS (Platform as a Service) kategorisinde yer alan bu servis, altyapı detaylarıyla boğuşmadan uygulamanızı hızlıca ayağa kaldırmanızı sağlıyor. Ama “kolaylık” kelimesine aldanmayın; Beanstalk’ı doğru kullanmak için altında ne döndüğünü anlamak şart. Bu yazıda hem temel kavramları hem de gerçek dünya senaryolarını ele alacağız.

Elastic Beanstalk Nedir ve Neden Kullanılır?

Elastic Beanstalk, kodunuzu yüklediğinizde otomatik olarak EC2 instance’ları, Load Balancer, Auto Scaling grupları, güvenlik grupları ve S3 bucket’larını sizin yerinize oluşturup yönetir. Siz sadece uygulamanızı ve konfigürasyonunuzu sağlarsınız.

Peki kimler için ideal?

  • Küçük-orta ölçekli ekipler: DevOps mühendisi olmayan ekipler için ciddi zaman tasarrufu sağlar.
  • Hızlı prototipleme: MVP’yi hızla ayağa kaldırmak isteyenler için biçilmiş kaftan.
  • Mevcut AWS altyapısıyla entegrasyon: RDS, ElastiCache, SQS gibi servislerle kolay entegre olur.

Desteklenen platformlar arasında Python, Node.js, Java, .NET, PHP, Ruby, Go ve Docker bulunuyor. Docker desteği sayesinde neredeyse her stack’i çalıştırabilirsiniz.

Temel Kavramlar

Beanstalk’ı anlamak için şu kavramları iyi kavramanız gerekiyor:

  • Application: En üst seviyedeki mantıksal container. Birden fazla environment içerebilir.
  • Environment: Uygulamanın çalıştığı gerçek altyapı. Web server veya worker tipi olabilir.
  • Environment Tier: Web Server Tier HTTP isteklerini karşılar, Worker Tier ise arka plan işleri için SQS’ten mesaj tüketir.
  • Application Version: Deploy ettiğiniz her kod paketi bir versiyondur, S3’te saklanır.
  • Configuration Template: Ortam ayarlarını tekrar kullanmak için şablon oluşturmanızı sağlar.
  • Platform: Çalışma zamanı ortamı (örneğin Python 3.11 running on Amazon Linux 2023).

AWS CLI ve EB CLI Kurulumu

Beanstalk ile çalışmak için iki araç şart: AWS CLI ve EB CLI. Şimdi bunları kuralım.

# AWS CLI kurulumu (Linux)
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

# AWS CLI konfigürasyonu
aws configure
# AWS Access Key ID: AKIAIOSFODNN7EXAMPLE
# AWS Secret Access Key: wJalrXUtn...
# Default region name: eu-west-1
# Default output format: json

# EB CLI kurulumu
pip install awsebcli --upgrade --user

# PATH'e ekleyelim (bash kullanıcıları için)
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

# Versiyon kontrolü
eb --version
# EB CLI 3.20.x (Python 3.x)

İlk Uygulamanızı Deploy Etmek

Senaryo: Bir Flask uygulamasını Beanstalk’a deploy edeceğiz. Basit ama gerçek dünyada en sık karşılaşılan senaryo bu.

Önce uygulama dosyalarını hazırlayalım:

# Proje dizini oluşturalım
mkdir flask-beanstalk-demo && cd flask-beanstalk-demo

# Virtual environment
python3 -m venv venv
source venv/bin/activate

# Bağımlılıkları kuralım
pip install flask gunicorn

# requirements.txt oluştur
pip freeze > requirements.txt

# Basit Flask uygulaması
cat > application.py << 'EOF'
from flask import Flask, jsonify
import os

application = Flask(__name__)

@application.route('/')
def index():
    return jsonify({
        "status": "ok",
        "environment": os.environ.get("APP_ENV", "development"),
        "version": os.environ.get("APP_VERSION", "1.0.0")
    })

@application.route('/health')
def health():
    return jsonify({"status": "healthy"}), 200

if __name__ == '__main__':
    application.run(debug=False, port=5000)
EOF

Önemli not: Beanstalk, Python uygulamalarında dosya adının application.py ve WSGI nesnesinin application olmasını bekler. Buna uymayan uygulamalarda deploy sonrası 502 hatası alırsınız, bu klasik bir tuzak.

Şimdi Beanstalk’ı initialize edelim:

# EB CLI ile projeyi başlat
eb init flask-beanstalk-demo 
  --platform "Python 3.11 running on 64bit Amazon Linux 2023" 
  --region eu-west-1

# Environment oluştur ve deploy et
eb create production 
  --instance-type t3.small 
  --min-instances 2 
  --max-instances 4 
  --elb-type application 
  --tags Environment=production,Team=backend

# Deploy durumunu izle
eb status
eb logs

.ebextensions ile Gelişmiş Konfigürasyon

Beanstalk’ın gerçek gücü .ebextensions klasöründe saklı. Bu klasör içindeki YAML dosyaları ile instance konfigürasyonu, ortam değişkenleri, paket kurulumu ve çok daha fazlasını yönetebilirsiniz.

mkdir -p .ebextensions

# Ortam değişkenleri ve instance ayarları
cat > .ebextensions/01_environment.config << 'EOF'
option_settings:
  aws:elasticbeanstalk:application:environment:
    APP_ENV: production
    LOG_LEVEL: WARNING
    DATABASE_URL: "{{resolve:ssm:/myapp/production/database_url}}"
  aws:elasticbeanstalk:environment:proxy:staticfiles:
    /static: static
  aws:autoscaling:launchconfiguration:
    InstanceType: t3.small
    IamInstanceProfile: aws-elasticbeanstalk-ec2-role
  aws:autoscaling:asg:
    MinSize: 2
    MaxSize: 6
  aws:elasticbeanstalk:cloudwatch:logs:
    StreamLogs: true
    DeleteOnTerminate: false
    RetentionInDays: 30
EOF

# Sistem paketleri ve özel komutlar
cat > .ebextensions/02_packages.config << 'EOF'
packages:
  yum:
    htop: []
    postgresql-devel: []

commands:
  01_upgrade_pip:
    command: "/var/app/venv/staging-LQM1lest/bin/pip install --upgrade pip"
    ignoreErrors: false

container_commands:
  01_migrate:
    command: "source /var/app/venv/staging-LQM1lest/bin/activate && python manage.py migrate"
    leader_only: true
  02_collectstatic:
    command: "source /var/app/venv/staging-LQM1lest/bin/activate && python manage.py collectstatic --noinput"
EOF

container_commands ile commands arasındaki farka dikkat edin. container_commands uygulama kodu deploy edildikten sonra, commands ise daha önce çalışır. leader_only: true ayarı ise migration gibi sadece bir kez çalışması gereken komutlar için kritik öneme sahiptir.

Procfile ve Gunicorn Konfigürasyonu

Production ortamında Flask’ın built-in sunucusu kesinlikle kullanılmamalı. Gunicorn ile çalıştıralım:

# Procfile oluştur
cat > Procfile << 'EOF'
web: gunicorn --workers=3 --threads=2 --timeout=60 --bind=0.0.0.0:8000 --access-logfile=- --error-logfile=- application:application
EOF

# Alternatif olarak .platform/nginx/conf.d/ ile Nginx'i özelleştirebilirsiniz
mkdir -p .platform/nginx/conf.d

cat > .platform/nginx/conf.d/custom.conf << 'EOF'
client_max_body_size 20M;
keepalive_timeout 75;

upstream gunicorn {
    server 127.0.0.1:8000;
    keepalive 32;
}
EOF

Multi-Environment Yönetimi

Gerçek dünyada staging ve production ortamlarını ayrı tutmak şart. Beanstalk’ta bu oldukça temiz bir şekilde yönetilebilir.

# Staging environment oluştur
eb create staging 
  --instance-type t3.micro 
  --min-instances 1 
  --max-instances 2 
  --elb-type application 
  --tags Environment=staging,Team=backend

# Staging'e deploy
eb deploy staging

# Production'a deploy
eb deploy production

# Environment'lar arası geçiş
eb use staging
eb status

eb use production
eb status

# Staging'i production ile swap et (Blue/Green deployment)
eb swap staging --destination_name production

eb swap komutu, Beanstalk’ın en güçlü özelliklerinden biridir. DNS seviyesinde iki environment’ı birbirleriyle takas eder, bu sayede sıfır downtime deployment yapabilirsiniz. Swap sonrasında eski production, staging olarak kalır ve bir şeyler ters giderse aynı komutla geri alabilirsiniz.

CloudFormation ile Beanstalk Altyapısını Kod Olarak Yönetmek

Beanstalk ortamlarını manuel oluşturmak yerine Infrastructure as Code yaklaşımını benimseyelim. AWS CloudFormation ile Beanstalk kaynaklarını tanımlayabiliriz:

# cfn-template.yaml oluştur
cat > cfn-template.yaml << 'EOF'
AWSTemplateFormatVersion: '2010-09-09'
Description: Elastic Beanstalk Production Environment

Parameters:
  ApplicationName:
    Type: String
    Default: flask-beanstalk-demo
  EnvironmentName:
    Type: String
    Default: production
  SolutionStackName:
    Type: String
    Default: "64bit Amazon Linux 2023 v4.0.0 running Python 3.11"

Resources:
  BeanstalkApplication:
    Type: AWS::ElasticBeanstalk::Application
    Properties:
      ApplicationName: !Ref ApplicationName
      Description: Flask Demo Application

  BeanstalkEnvironment:
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      ApplicationName: !Ref BeanstalkApplication
      EnvironmentName: !Ref EnvironmentName
      SolutionStackName: !Ref SolutionStackName
      OptionSettings:
        - Namespace: aws:autoscaling:asg
          OptionName: MinSize
          Value: '2'
        - Namespace: aws:autoscaling:asg
          OptionName: MaxSize
          Value: '6'
        - Namespace: aws:elasticbeanstalk:environment
          OptionName: EnvironmentType
          Value: LoadBalanced
        - Namespace: aws:elasticbeanstalk:cloudwatch:logs
          OptionName: StreamLogs
          Value: 'true'
        - Namespace: aws:elasticbeanstalk:cloudwatch:logs
          OptionName: RetentionInDays
          Value: '30'

Outputs:
  EnvironmentURL:
    Description: Beanstalk Environment URL
    Value: !GetAtt BeanstalkEnvironment.EndpointURL
EOF

# Stack'i deploy et
aws cloudformation create-stack 
  --stack-name beanstalk-production 
  --template-body file://cfn-template.yaml 
  --capabilities CAPABILITY_IAM 
  --region eu-west-1

# Stack durumunu izle
aws cloudformation wait stack-create-complete 
  --stack-name beanstalk-production 
  --region eu-west-1

CI/CD Pipeline ile Otomatik Deploy

Manuel deploy yapmak hata yaratır. GitHub Actions ile otomatik bir pipeline kuralım:

# .github/workflows/deploy.yml
mkdir -p .github/workflows

cat > .github/workflows/deploy.yml << 'EOF'
name: Deploy to Elastic Beanstalk

on:
  push:
    branches:
      - main
      - staging

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run tests
        run: python -m pytest tests/ -v

  deploy-staging:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/staging'
    steps:
      - uses: actions/checkout@v4
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: eu-west-1
      - name: Deploy to Staging
        run: |
          pip install awsebcli
          eb init flask-beanstalk-demo --region eu-west-1 --platform "Python 3.11 running on 64bit Amazon Linux 2023"
          eb deploy staging --timeout 20
          eb status staging

  deploy-production:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - uses: actions/checkout@v4
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: eu-west-1
      - name: Deploy to Production
        run: |
          pip install awsebcli
          eb init flask-beanstalk-demo --region eu-west-1 --platform "Python 3.11 running on 64bit Amazon Linux 2023"
          eb deploy production --timeout 20
EOF

Yaygın Sorunlar ve Çözümleri

Beanstalk ile çalışırken mutlaka karşılaşacağınız sorunlar ve çözümleri:

502 Bad Gateway hatası: En sık karşılaşılan sorun. Neden olabilir?

  • WSGI nesnesinin adı application değil
  • Gunicorn port numarası Nginx ile uyuşmuyor
  • Uygulama exception fırlatıyor ve başlamıyor
# Logları hemen kontrol et
eb logs --all

# Sadece uygulama loglarını çek
eb logs --log-group /aws/elasticbeanstalk/production/var/log/web.stdout.log

# Instance'a doğrudan bağlan
eb ssh production

# Bağlandıktan sonra logları kontrol et
sudo tail -f /var/log/web.stdout.log
sudo tail -f /var/log/nginx/error.log
sudo systemctl status web

Deployment timeout sorunları: Büyük uygulamalarda veya yavaş migration’larda deployment timeout alabilirsiniz.

# Timeout süresini artır
eb deploy production --timeout 30

# .ebextensions ile de ayarlanabilir
cat > .ebextensions/03_timeout.config << 'EOF'
option_settings:
  aws:elasticbeanstalk:command:
    DeploymentPolicy: RollingWithAdditionalBatch
    BatchSizeType: Percentage
    BatchSize: 25
    Timeout: 1800
    HealthCheckSuccessThreshold: Ok
EOF

Health check başarısızlıkları: Load Balancer health check’i başarısız olduğunda instance’lar sürekli terminate edilip yeniden başlatılır.

# Health check path'ini özelleştir
cat > .ebextensions/04_healthcheck.config << 'EOF'
option_settings:
  aws:elasticbeanstalk:environment:process:default:
    HealthCheckPath: /health
    MatcherHTTPCode: 200
    Port: 80
    Protocol: HTTP
    HealthCheckInterval: 30
    HealthCheckTimeout: 5
    HealthyThresholdCount: 2
    UnhealthyThresholdCount: 5
EOF

Maliyet Optimizasyonu

Beanstalk kullanırken maliyeti kontrol altında tutmak için birkaç kritik nokta:

  • Scheduled Scaling: Test ortamları için gece saatlerinde instance sayısını sıfıra indirin.
  • Spot Instance kullanımı: Non-production ortamlarda Spot Instance’lar ile %70’e kadar tasarruf mümkün.
  • Environment saat dilimi yönetimi: Staging environment’ı hafta sonları terminate edip Pazartesi sabahı yeniden oluşturun.
# Auto Scaling scheduled action ile gece kapatma
aws autoscaling put-scheduled-update-group-action 
  --auto-scaling-group-name "awseb-e-xxxxxxxx-stack-AWSEBAutoScalingGroup" 
  --scheduled-action-name "scale-down-night" 
  --recurrence "0 22 * * 1-5" 
  --min-size 0 
  --max-size 0 
  --desired-capacity 0

# Sabah tekrar açma
aws autoscaling put-scheduled-update-group-action 
  --auto-scaling-group-name "awseb-e-xxxxxxxx-stack-AWSEBAutoScalingGroup" 
  --scheduled-action-name "scale-up-morning" 
  --recurrence "0 8 * * 1-5" 
  --min-size 1 
  --max-size 4 
  --desired-capacity 2

Beanstalk’ın Sınırları ve Ne Zaman Bırakmalısınız?

Beanstalk her senaryoya uygun değil. Şu durumlarda Beanstalk’tan ECS, EKS veya başka bir çözüme geçmeyi düşünün:

  • Microservice mimarisine geçiş: Onlarca servisi Beanstalk’ta yönetmek karmaşıklaşır, ECS Fargate daha uygun olur.
  • Gelişmiş deployment stratejileri: Canary deployment veya feature flag tabanlı rollout için Beanstalk yetersiz kalır.
  • Altyapı üzerinde tam kontrol ihtiyacı: Beanstalk bazı altyapı değişikliklerini zorlaştırır veya imkansız kılar.
  • Çok kiracılı (multi-tenant) uygulamalar: Her müşteri için ayrı environment açmak hem maliyetli hem yönetimi güç olur.

Beanstalk’ın oluşturduğu EC2 instance’lara, güvenlik gruplarına ve Auto Scaling gruplarına konsol üzerinden müdahale etmekten kaçının. Beanstalk bu kaynakları yeniden deploy sırasında sıfırlayabilir, yaptığınız değişiklikler kaybolur.

Sonuç

Elastic Beanstalk, doğru kullanıldığında gerçekten hayat kurtarır. Altyapı yönetimiyle vakit kaybetmek yerine uygulama geliştirmeye odaklanmanızı sağlar. Ancak “sihirli bir çözüm” değil; altında ne döndüğünü anlamadan kullanmak, sorunlar çıktığında sizi çıkmaza sokabilir.

Bu yazıda anlattıklarımı özetlersek:

  • .ebextensions klasörünü etkin kullanmak, tekrar edilebilir ve öngörülebilir deployment’lar için zorunlu.
  • eb swap komutu ile Blue/Green deployment yaparak sıfır downtime hedefleyin.
  • Log’ları gerçek zamanlı izleyin, sorun çıktığında ilk bakacağınız yer burası.
  • CI/CD pipeline olmadan production deploy etmeyin, manuel müdahaleler hata kaynağı.
  • Maliyeti unutmayın, küçük ayarlarla ciddi tasarruf yapılabilir.

Beanstalk ile başlayıp zamanla Kubernetes’e geçmek çok yaygın bir yolculuk. Beanstalk, bu yolculuğun ilk adımı için mükemmel bir başlangıç noktası. Umarım bu yazı hem başlamanıza hem de daha verimli kullanmanıza yardımcı olur.

Bir yanıt yazın

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