AWS EC2 Load Balancer Yapılandırması: Adım Adım Rehber
Üretim ortamında çalışan bir uygulamanızın tek bir sunucu üzerinde koştuğunu düşünün. Trafik aniden artıyor, sunucu yanıt veremiyor ve uygulamanız çöküyor. İşte tam bu noktada load balancer devreye giriyor. AWS’de Elastic Load Balancing (ELB) servisi, gelen trafiği birden fazla EC2 instance’ına akıllıca dağıtarak hem yüksek erişilebilirlik hem de ölçeklenebilirlik sağlıyor. Bu yazıda sıfırdan bir load balancer yapılandırmasını, gerçek dünya senaryolarıyla birlikte ele alacağız.
AWS Load Balancer Türleri
AWS üç farklı load balancer türü sunuyor. Hangisini kullanacağınızı belirlemek, mimarinizin temelini oluşturuyor.
Application Load Balancer (ALB): HTTP/HTTPS trafiği için ideal. Layer 7’de çalışıyor, URL path bazlı yönlendirme yapabiliyor. Mikroservis mimarileri için biçilmiş kaftan.
Network Load Balancer (NLB): TCP/UDP trafiği için kullanılıyor. Layer 4’te çalışıyor, çok düşük latency gereksinimleriniz varsa ve milyonlarca istek per second bekliyorsanız NLB doğru seçim.
Gateway Load Balancer (GWLB): Firewall, IDS/IPS gibi üçüncü taraf network appliance’larını ölçeklendirmek için kullanılıyor. Daha niş bir kullanım senaryosu.
Büyük ihtimalle günlük işlerde en çok ALB kullanacaksınız. Biz de bu yazıda ALB üzerine yoğunlaşacağız, ancak NLB için de pratik örnekler vereceğiz.
Ön Hazırlık: VPC ve Güvenlik Grupları
Load balancer kurmadan önce altyapınızın hazır olması gerekiyor. En azından iki farklı Availability Zone’da subnet’lerinizin bulunması şart. AWS bu konuda sizi zorluyor, tek AZ’de ALB oluşturamazsınız.
Önce AWS CLI ile mevcut VPC ve subnet bilgilerinizi kontrol edelim:
# Mevcut VPC'leri listele
aws ec2 describe-vpcs
--query 'Vpcs[*].{ID:VpcId,CIDR:CidrBlock,Name:Tags[?Key==`Name`].Value|[0]}'
--output table
# Subnet'leri AZ bazında listele
aws ec2 describe-subnets
--filters "Name=vpc-id,Values=vpc-xxxxxxxxx"
--query 'Subnets[*].{ID:SubnetId,AZ:AvailabilityZone,CIDR:CidrBlock,Public:MapPublicIpOnLaunch}'
--output table
Şimdi load balancer için güvenlik grubu oluşturalım. Bu güvenlik grubu, dışarıdan gelen trafiği load balancer’a izin verecek:
# Load balancer güvenlik grubu oluştur
aws ec2 create-security-group
--group-name "alb-sg"
--description "Application Load Balancer Security Group"
--vpc-id vpc-xxxxxxxxx
# HTTP ve HTTPS trafiğine izin ver
aws ec2 authorize-security-group-ingress
--group-id sg-alb-xxxxxxxxx
--protocol tcp
--port 80
--cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress
--group-id sg-alb-xxxxxxxxx
--protocol tcp
--port 443
--cidr 0.0.0.0/0
# EC2 instance güvenlik grubunu oluştur
# Sadece ALB'den gelen trafiğe izin ver
aws ec2 create-security-group
--group-name "ec2-backend-sg"
--description "EC2 Backend Instances Security Group"
--vpc-id vpc-xxxxxxxxx
aws ec2 authorize-security-group-ingress
--group-id sg-ec2-xxxxxxxxx
--protocol tcp
--port 8080
--source-group sg-alb-xxxxxxxxx
Bu yapıda EC2 instance’larına doğrudan internet erişimi kapalı. Tüm trafik ALB üzerinden geçmek zorunda. Üretim ortamı için bu yaklaşım güvenlik açısından kritik.
Target Group Oluşturma
Target group, load balancer’ın trafiği yönlendireceği hedeflerin grubudur. EC2 instance’ları, Lambda fonksiyonları veya IP adresleri hedef olabilir.
# Target group oluştur
aws elbv2 create-target-group
--name "my-app-tg"
--protocol HTTP
--port 8080
--vpc-id vpc-xxxxxxxxx
--health-check-protocol HTTP
--health-check-path "/health"
--health-check-interval-seconds 30
--health-check-timeout-seconds 5
--healthy-threshold-count 2
--unhealthy-threshold-count 3
--target-type instance
# Oluşturulan target group ARN'ini al
aws elbv2 describe-target-groups
--names "my-app-tg"
--query 'TargetGroups[0].TargetGroupArn'
--output text
Health check ayarları son derece önemli. /health endpoint’iniz hızlı yanıt vermeli, 200 dışında bir kod dönmemeli. Eğer uygulamanızın health check endpoint’i yoksa basit bir tane ekleyin:
# Nginx üzerinde basit health check
cat > /etc/nginx/conf.d/health.conf << 'EOF'
server {
listen 8080;
location /health {
access_log off;
return 200 "healthyn";
add_header Content-Type text/plain;
}
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
EOF
nginx -t && systemctl reload nginx
Application Load Balancer Oluşturma
Artık ALB’yi oluşturabiliriz. En az iki farklı AZ’deki public subnet’i belirtmeniz gerekiyor:
# ALB oluştur
aws elbv2 create-load-balancer
--name "my-app-alb"
--subnets subnet-public-1a subnet-public-1b subnet-public-1c
--security-groups sg-alb-xxxxxxxxx
--scheme internet-facing
--type application
--ip-address-type ipv4
--tags Key=Environment,Value=production Key=Project,Value=myapp
# ALB DNS adresini öğren
aws elbv2 describe-load-balancers
--names "my-app-alb"
--query 'LoadBalancers[0].{DNS:DNSName,State:State.Code,AZ:AvailabilityZones[*].ZoneName}'
--output json
Şimdi listener ekleyelim. HTTP trafiğini HTTPS’e yönlendireceğiz, bu üretim ortamı için standart yaklaşım:
# HTTPS listener oluştur (443)
aws elbv2 create-listener
--load-balancer-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:loadbalancer/app/my-app-alb/xxxxx
--protocol HTTPS
--port 443
--ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06
--certificates CertificateArn=arn:aws:acm:eu-west-1:123456789:certificate/xxxxx
--default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:eu-west-1:123456789:targetgroup/my-app-tg/xxxxx
# HTTP listener - HTTPS'e redirect
aws elbv2 create-listener
--load-balancer-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:loadbalancer/app/my-app-alb/xxxxx
--protocol HTTP
--port 80
--default-actions Type=redirect,RedirectConfig="{Protocol=HTTPS,Port=443,StatusCode=HTTP_301}"
EC2 Instance’larını Target Group’a Ekleme
Instance’ları target group’a ekleyelim:
# Instance'ları target group'a kaydet
aws elbv2 register-targets
--target-group-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:targetgroup/my-app-tg/xxxxx
--targets Id=i-0123456789abcdef0 Id=i-0abcdef1234567890 Id=i-0fedcba9876543210
# Target'ların sağlık durumunu kontrol et
aws elbv2 describe-target-health
--target-group-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:targetgroup/my-app-tg/xxxxx
--query 'TargetHealthDescriptions[*].{Instance:Target.Id,Port:Target.Port,State:TargetHealth.State,Reason:TargetHealth.Reason}'
--output table
Health check sonuçlarında healthy görmelisiniz. unhealthy geliyorsa şunları kontrol edin:
- EC2 instance güvenlik grubunda ALB’den gelen trafiğe izin var mı?
- Uygulama doğru port’ta çalışıyor mu?
- Health check path’i doğru mu?
- Instance içinde uygulamanın log’larına bakın
Gerçek Dünya Senaryosu: Path Bazlı Yönlendirme
Diyelim ki tek bir load balancer altında birden fazla mikroservis çalıştırıyorsunuz. API isteklerini farklı servis gruplarına yönlendirmeniz gerekiyor. ALB’nin path bazlı yönlendirme özelliği burada devreye giriyor.
# Kullanıcı servisi için ayrı target group
aws elbv2 create-target-group
--name "users-service-tg"
--protocol HTTP
--port 8081
--vpc-id vpc-xxxxxxxxx
--health-check-path "/api/users/health"
# Sipariş servisi için ayrı target group
aws elbv2 create-target-group
--name "orders-service-tg"
--protocol HTTP
--port 8082
--vpc-id vpc-xxxxxxxxx
--health-check-path "/api/orders/health"
# Path bazlı routing kuralları ekle
# /api/users/* -> users-service-tg
aws elbv2 create-rule
--listener-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:listener/app/my-app-alb/xxxxx/xxxxx
--priority 10
--conditions Field=path-pattern,Values='/api/users/*'
--actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:eu-west-1:123456789:targetgroup/users-service-tg/xxxxx
# /api/orders/* -> orders-service-tg
aws elbv2 create-rule
--listener-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:listener/app/my-app-alb/xxxxx/xxxxx
--priority 20
--conditions Field=path-pattern,Values='/api/orders/*'
--actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:eu-west-1:123456789:targetgroup/orders-service-tg/xxxxx
Bu yapıyla tek bir ALB üzerinden tüm mikroservislerinizi yönetebilirsiniz. Maliyet açısından da avantajlı çünkü her servis için ayrı load balancer oluşturmuyorsunuz.
Sticky Sessions (Oturum Yapışkanlığı) Yapılandırması
Bazı uygulamalar, özellikle eski monolitik yapılar, session bilgisini sunucu tarafında tutuyor. Bu durumda aynı kullanıcının isteklerinin aynı instance’a gitmesi gerekiyor. Buna sticky sessions deniyor.
# Target group'ta sticky sessions'ı etkinleştir
aws elbv2 modify-target-group-attributes
--target-group-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:targetgroup/my-app-tg/xxxxx
--attributes
Key=stickiness.enabled,Value=true
Key=stickiness.type,Value=lb_cookie
Key=stickiness.lb_cookie.duration_seconds,Value=86400
# Diğer faydalı target group ayarları
aws elbv2 modify-target-group-attributes
--target-group-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:targetgroup/my-app-tg/xxxxx
--attributes
Key=deregistration_delay.timeout_seconds,Value=30
Key=load_balancing.algorithm.type,Value=least_outstanding_requests
deregistration_delay.timeout_seconds: Bir instance deregister edildiğinde ALB’nin mevcut bağlantıları kapatması için bekleme süresi. 300 saniye varsayılan, üretimde bunu 30-60 saniyeye indirmek deployment süreçlerini hızlandırıyor.
load_balancing.algorithm.type: round_robin varsayılan değer. least_outstanding_requests ise bekleyen istek sayısı en az olan instance’a yönlendiriyor. Farklı boyutlarda instance’lar kullanıyorsanız bu daha verimli.
Auto Scaling ile Entegrasyon
Load balancer’ın gücü Auto Scaling ile birleştiğinde ortaya çıkıyor. Trafik arttığında yeni instance’lar devreye giriyor, azaldığında kapanıyor.
# Launch Template oluştur
aws ec2 create-launch-template
--launch-template-name "my-app-lt"
--version-description "v1"
--launch-template-data '{
"ImageId": "ami-0xxxxxxxxxxxxxxxxx",
"InstanceType": "t3.medium",
"SecurityGroupIds": ["sg-ec2-xxxxxxxxx"],
"IamInstanceProfile": {"Name": "my-app-instance-profile"},
"UserData": "'"$(base64 -w 0 << 'USERDATA'
#!/bin/bash
yum update -y
yum install -y java-17-amazon-corretto
aws s3 cp s3://my-app-bucket/app.jar /opt/app/
systemctl start my-app
USERDATA
)"'",
"TagSpecifications": [{
"ResourceType": "instance",
"Tags": [{"Key": "Name", "Value": "my-app-instance"}]
}]
}'
# Auto Scaling Group oluştur ve target group ile ilişkilendir
aws autoscaling create-auto-scaling-group
--auto-scaling-group-name "my-app-asg"
--launch-template LaunchTemplateName=my-app-lt,Version='$Latest'
--min-size 2
--max-size 10
--desired-capacity 2
--target-group-arns arn:aws:elasticloadbalancing:eu-west-1:123456789:targetgroup/my-app-tg/xxxxx
--health-check-type ELB
--health-check-grace-period 300
--availability-zones eu-west-1a eu-west-1b eu-west-1c
--vpc-zone-identifier "subnet-private-1a,subnet-private-1b,subnet-private-1c"
--health-check-type ELB ayarına dikkat edin. Bu olmadan Auto Scaling sadece EC2 health check’ini kullanır. ELB health check aktifken, load balancer’ın unhealthy dediği instance’lar Auto Scaling tarafından da sonlandırılır ve yerine yenisi başlatılır.
ALB Access Logs ve Monitoring
Üretim ortamında access log’ları mutlaka açın. Hangi IP’den ne kadar istek geldiğini, hangi instance’ların yük aldığını, yanıt sürelerini görebiliyorsunuz.
# S3 bucket oluştur (log bucket'ının policy'si özel olmalı)
aws s3 mb s3://my-app-alb-logs-123456789
# ALB log bucket policy'si ekle
# AWS'nin ELB hesabının bucket'a yazabilmesi için
cat > /tmp/alb-log-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::156460612806:root"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-app-alb-logs-123456789/alb-logs/AWSLogs/123456789012/*"
}
]
}
EOF
aws s3api put-bucket-policy
--bucket my-app-alb-logs-123456789
--policy file:///tmp/alb-log-policy.json
# ALB'de access logging'i etkinleştir
aws elbv2 modify-load-balancer-attributes
--load-balancer-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:loadbalancer/app/my-app-alb/xxxxx
--attributes
Key=access_logs.s3.enabled,Value=true
Key=access_logs.s3.bucket,Value=my-app-alb-logs-123456789
Key=access_logs.s3.prefix,Value=alb-logs
Key=idle_timeout.timeout_seconds,Value=60
Key=routing.http2.enabled,Value=true
Key=drop_invalid_header_fields.enabled,Value=true
drop_invalid_header_fields.enabled: Güvenlik açısından önemli. HTTP request smuggling saldırılarına karşı koruma sağlıyor, mutlaka açın.
routing.http2.enabled: HTTP/2 desteği, özellikle çok sayıda küçük istek yapan uygulamalarda performansı artırıyor.
CloudWatch üzerinden ALB metriklerini takip etmek için alarm kurabilirsiniz:
# Yüksek 5xx error oranı için alarm
aws cloudwatch put-metric-alarm
--alarm-name "alb-high-5xx-errors"
--alarm-description "ALB 5xx error rate is too high"
--metric-name HTTPCode_ELB_5XX_Count
--namespace AWS/ApplicationELB
--dimensions Name=LoadBalancer,Value=app/my-app-alb/xxxxx
--statistic Sum
--period 300
--threshold 10
--comparison-operator GreaterThanThreshold
--evaluation-periods 2
--alarm-actions arn:aws:sns:eu-west-1:123456789:ops-alerts
--treat-missing-data notBreaching
WAF Entegrasyonu
ALB’yi AWS WAF ile entegre etmek, uygulamanızı SQL injection, XSS gibi yaygın web saldırılarına karşı koruyor. Üretim ortamında bu adımı atlamayın.
# WAF Web ACL oluştur
aws wafv2 create-web-acl
--name "my-app-waf"
--scope REGIONAL
--default-action Allow={}
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=my-app-waf
--rules '[
{
"Name": "AWSManagedRulesCommonRuleSet",
"Priority": 1,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet"
}
},
"OverrideAction": {"None": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "CommonRuleSet"
}
},
{
"Name": "RateLimitRule",
"Priority": 2,
"Statement": {
"RateBasedStatement": {
"Limit": 2000,
"AggregateKeyType": "IP"
}
},
"Action": {"Block": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "RateLimit"
}
}
]'
--region eu-west-1
# WAF'ı ALB ile ilişkilendir
aws wafv2 associate-web-acl
--web-acl-arn arn:aws:wafv2:eu-west-1:123456789:regional/webacl/my-app-waf/xxxxx
--resource-arn arn:aws:elasticloadbalancing:eu-west-1:123456789:loadbalancer/app/my-app-alb/xxxxx
--region eu-west-1
Rate limiting kuralı IP başına 5 dakikada 2000 istekten fazlasını engelliyor. Bu değeri uygulamanızın normal kullanım profiline göre ayarlayın.
Yaygın Sorunlar ve Çözümleri
504 Gateway Timeout: Genellikle uygulamanın ALB’nin bekleme süresinden uzun sürmesiyle oluşuyor. idle_timeout değerini artırabilirsiniz ama asıl sorunu uygulamanızda çözmelisiniz.
Sağlıksız target’lar: Health check endpoint’iniz 200 dönüyor mu kontrol edin. Instance’ın güvenlik grubunda ALB’den gelen trafiğe izin var mı bakın. CloudWatch’ta target health geçmişini inceleyin.
Dengesiz yük dağılımı: Bütün isteklerin tek bir instance’a gittiğini görüyorsanız büyük ihtimalle sticky sessions açık ve çok uzun süreli ayarlanmış. Ayrıca instance’larınız farklı kapasitelerde mi kontrol edin.
SSL handshake hataları: Sertifikanızın geçerlilik süresine, sertifika zincirinin tam olup olmadığına ve doğru bölgede ACM’e yüklendiğine bakın.
Maliyet Optimizasyonu
Load balancer maliyetleri, saat başı sabit ücret artı işlenen veri üzerinden hesaplanıyor. Maliyeti düşürmek için:
- Boşta kalan load balancer’ları silin. Test ortamları için ALB’yi gece saatlerinde kaldırıp sabah yeniden oluşturabilirsiniz.
- Birden fazla uygulama için ayrı ALB yerine, path veya host bazlı routing ile tek ALB kullanın.
- Cross-zone load balancing’in maliyetini göz önünde bulundurun. Aynı AZ içi trafik ücretsiz, AZ’ler arası veri transferi ücretli.
- ALB yerine uygulamanızın önüne CloudFront koymak, edge’de cache yaparak hem maliyeti hem de latency’i düşürebilir.
Sonuç
AWS ALB yapılandırması ilk bakışta karmaşık görünse de adım adım ilerlediğinizde mantıklı bir bütün oluşturuyor. Güvenlik grubu tasarımından başlayın, target group health check’lerini doğru ayarlayın, HTTPS redirect’i unutmayın ve WAF entegrasyonunu ihmal etmeyin. Access log’ları açık tutun, CloudWatch alarmlarını kurun. Auto Scaling ile birleştirdiğinizde gerçek anlamda ölçeklenebilir ve dayanıklı bir altyapıya kavuşuyorsunuz.
Üretim ortamına geçmeden önce mutlaka bir test senaryosu çalıştırın: birkaç instance’ı manuel olarak unhealthy hale getirin ve load balancer’ın bu instance’ları devre dışı bırakıp bırakmadığını gözlemleyin. Kaos mühendisliği yaklaşımını benimseyip sisteminizin ne zaman çökeceğini siz bulun, müşterileriniz bulmadan önce.
