Terraform İle AWS Kullanımı ve Load Balancer Deploy
9 min read

Terraform İle AWS Kullanımı ve Load Balancer Deploy

Terraform ile AWS kullanarak yüksek düzeyde kullanılabilir ve ölçeklenebilir bir Load Balancer deploy edebilirsiniz.
Terraform İle AWS Kullanımı ve Load Balancer Deploy

Terraform ile AWS kullanarak yüksek düzeyde kullanılabilir ve ölçeklenebilir bir Load Balancer deploy edebilirsiniz. AWS Load Balancer deploy etmek için neler yapmamız gerektiğini bu yazıda inceliyeceğiz.

Önceki yazımız "Terraform İle AWS Kullanımı ve EC2 Web Server Cluster Deploy" da ASG'mizi deploy etmiştik. Ancak küçük bir sorunumuz var: Artık her biri kendi IP adresine sahip birden çok sunucunuz var, fakat genellikle son kullanıcılarınıza kullanmaları için yalnızca tek bir IP vermeniz gerekir. Bu sorunu çözmenin bir yolu, trafiği sunucularınız arasında dağıtmak için bir yük dengeleyici (load balancer) dağıtmak ve tüm kullanıcılarınıza yük dengeleyicinin IP'sini (aslında DNS adı) vermektir. Yüksek düzeyde kullanılabilir ve ölçeklenebilir bir yük dengeleyici oluşturmak çok fazla iş yüküdür. Bir kez daha, Şekil 1'de gösterildiği gibi Amazon'un Elastic Load Balancer (ELB) hizmetini kullanarak AWS'nin bu işi sizin için halletmesine izin verebilirsiniz.

Asıl konuya geçmeden önce EC2 Instance cluster'ı nasıl deploy ettiğimizi hatırlamak isterseniz aşağıdaki bağlantıyı kullanabilirsiniz.

Terraform İle AWS Kullanımı ve EC2 Web Server Cluster Deploy
Terraform ile AWS kullanarak EC2 Instance web server cluster nasıl oluşturulur ve nasıl deploy edilir detaylıca gösteriyoruz.
Şekil 1: Auto Scaling Group genelinde trafiği dağıtmak için Amazon ELB'yi kullanma şeması

AWS, üç farklı load balancer türü sunar:

  • Application Load Balancer (ALB): HTTP ve HTTPS trafiğinin yük dengelemesi için en uygunudur. OSI modelinin uygulama katmanında (Katman 7) çalışır.
  • Network Load Balancer (NLB): TCP, UDP ve TLS trafiğinin yük dengelemesi için en uygunudur. ALB'den daha hızlı yüklenmeye yanıt olarak yukarı ve aşağı ölçeklenebilir (NLB, saniyede on milyonlarca isteğe ölçeklenecek şekilde tasarlanmıştır). OSI modelinin taşıma katmanında (Katman 4) çalışır.
  • Classic Load Balancer (CLB): Bu, hem ALB'den hem de NLB'den önce gelen "legacy" yük dengeleyicidir. HTTP, HTTPS, TCP ve TLS trafiğini işleyebilir, ancak ALB veya NLB'den çok daha az özelliğe sahiptir. OSI modelinin hem uygulama katmanında (L7) hem de taşıma katmanında (L4) çalışır.

Bugünlerde çoğu uygulama ALB veya NLB kullanmalıdır. Üzerinde çalıştığınız basit web sunucusu örneği, aşırı performans gereksinimleri olmayan bir HTTP uygulaması olduğundan, ALB en uygunu olacaktır.

ALB, Şekil 2'de gösterildiği gibi birkaç parçadan oluşur:

  • Listener: Belirli bir bağlantı noktasını (ör. 80) ve protokolü (ör. HTTP) dinler.
  • Listener rule: Bir listener'a gelen istekleri alır ve belirli yollarla (örneğin, /foo ve /bar) veya ana bilgisayar adlarıyla (örneğin, foo.example.com ve bar.example.com) eşleşenleri belirli hedef gruplara gönderir.
  • Target groups: Yük dengeleyiciden istek alan bir veya daha fazla sunucu. Hedef grup ayrıca bu sunucularda sağlık kontrolleri gerçekleştirir ve yalnızca sağlıklı node'lara istek gönderir.
Şekil 2: ALB'ye genel bakış

Terraform kısmına geçersek, ilk adım, kullanacağımız provider'ı eklemek olacaktır.

provider "aws" {
  region = "us-east-2"
}

Ardından aws_lb kaynağını kullanarak ALB'nin kendisini oluşturmaktır:

resource "aws_lb" "example" {
  name               = "terraform-asg-example"
  load_balancer_type = "application"
  subnets            = data.aws_subnets.default.ids
}

Sayfanın başında verdiğimiz önceki yazıda data konusunu anlatmıştık. Burada hızlıca subnet bilgisini alacak data referansı ekleyelim.

data "aws_vpc" "default" {
  default = true
}

data "aws_subnets" "default" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]
  }
}

subnets parametresinin, aws_subnets veri kaynağını kullanarak default VPC'nizdeki tüm subnetleri kullanacak şekilde load balancer'ı yapılandırdığını unutmayın. AWS yük dengeleyicileri tek bir sunucudan değil, ayrı subnetlerde (ve dolayısıyla , ayrı veri merkezlerinde) çalışabilen birden çok sunucudan oluşur. AWS, load balancer sunucuların sayısını trafiğe göre otomatik olarak yukarı ve aşağı ölçeklendirir ve bu sunuculardan biri arızalanırsa yük devretmeyi yönetir. Böylece kutudan çıkar çıkmaz ölçeklenebilirlik ve yüksek kullanılabilirlik elde edersiniz.

Sonraki adım, aws_lb_listener kaynağını kullanarak bu ALB için bir listener tanımlamaktır:

resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.example.arn
  port              = 80
  protocol          = "HTTP"

  # By default, return a simple 404 page
  default_action {
    type = "fixed-response"

    fixed_response {
      content_type = "text/plain"
      message_body = "404: page not found"
      status_code  = 404
    }
  }
}

Bu listener, ALB'yi; varsayılan HTTP port olan 80 numaralı portu dinleyecek, protokol olarak HTTP kullanacak ve herhangi bir listener rule ile eşleşmeyen istekler için varsayılan response olarak basit bir 404 sayfası gönderecek şekilde yapılandırır.

Varsayılan olarak, ALB'ler dahil tüm AWS kaynaklarının gelen veya giden trafiğe izin vermediğini, dolayısıyla özellikle ALB için yeni bir güvenlik grubu oluşturmanız gerektiğini unutmayın. Bu güvenlik grubu, HTTP üzerinden load balancer'a erişebilmeniz için 80 numaralı portu gelen isteklere ve load balancer'ın sağlık kontrollerini gerçekleştirebilmesi için tüm portlara giden isteklere izin vermelidir:

resource "aws_security_group" "alb" {
  name = "terraform-example-alb"

  # Allow inbound HTTP requests
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Allow all outbound requests
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

aws_lb kaynağına, security_groups değişkeni aracılığıyla bu güvenlik grubunu kullanmasını söylemeniz gerekir:

resource "aws_lb" "example" {
  name               = "terraform-asg-example"
  load_balancer_type = "application"
  subnets            = data.aws_subnets.default.ids
  security_groups    = [aws_security_group.alb.id]
}

Ardından, aws_lb_target_group kaynağını kullanarak ASG'niz için bir hedef grup oluşturmanız gerekir:

resource "aws_lb_target_group" "asg" {
  name     = "terraform-asg-example"
  port     = 8080
  protocol = "HTTP"
  vpc_id   = data.aws_vpc.default.id

  health_check {
    path                = "/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = 15
    timeout             = 3
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}

Bu hedef grup, her bir Instance için periyodik olarak bir HTTP isteği göndererek Instance'ların durumunu kontrol edecek ve Instance'ın yalnızca yapılandırılmış matcher ile eşleşen bir yanıt döndürmesi durumunda (ör. 200) o Instance'ı sağlıklı olarak işaretleyecek. Bir Instance bozulduğu veya aşırı yüklendiği için yanıt vermezse, "sağlıksız" olarak işaretlenir ve hedef grup, kullanıcılarınızın kesintiye uğramasını en aza indirmek için otomatik olarak ona trafik göndermeyi durdurur.

Hedef grup, hangi EC2 Instance'lara istek göndereceğini nasıl biliyor? aws_lb_target_group_attachment kaynağını kullanarak hedef gruba statik bir EC2 Instance listesi ekleyebilirsiniz, ancak bir ASG ile Instance'lar herhangi bir zamanda başlatılabilir veya sonlandırılabilir, bu nedenle statik bir liste çalışmaz. Bunun yerine, ASG ve ALB arasındaki birinci sınıf bir entegrasyondan yararlanabilirsiniz. aws_autoscaling_group kaynağına ekleyin ve target_group_arns bağımsız değişkenini yeni hedef grubunuza işaret edecek şekilde ayarlayın:

💡
Bu bölümü "Terraform İle AWS Kullanımı ve EC2 Web Server Cluster Deploy" başlıklı yazıda anlattığımız için tekrar amaçlı geri dönüp yazıyı okuyabilirsiniz. Unutmayınız ki bu yazı da anlatılan Load Balancer, bir önceki ilgili yazıda anlattığımız ASG cluster ile çalışmaktadır.

Lauch configuration kaynağını ve güvenlik grubunu ekleyelim.

resource "aws_launch_configuration" "example" {
  image_id        = "ami-0fb653ca2d3203ac1"
  instance_type   = "t2.micro"
  security_groups = [aws_security_group.instance.id]

  user_data = <<-EOF
              #!/bin/bash
              echo "Hello, World" > index.html
              nohup busybox httpd -f -p 8080 &
              EOF
}
resource "aws_security_group" "instance" {
  name = "terraform-example-instance"

  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

Ardından ASG kaynağını ekleyelim.

resource "aws_autoscaling_group" "example" {
  launch_configuration = aws_launch_configuration.example.name
  vpc_zone_identifier  = data.aws_subnets.default.ids

  target_group_arns = [aws_lb_target_group.asg.arn]
  health_check_type = "ELB"

  min_size = 2
  max_size = 10

  tag {
    key                 = "Name"
    value               = "terraform-asg-example"
    propagate_at_launch = true
  }
}

health_check_type'ı da "ELB" olarak güncellemelisiniz. Varsayılan health_check_type tipi "EC2" dir. EC2 tipi, yalnızca AWS hipervizörü sanal makinenin tamamen kapalı veya erişilemez olduğunu söylediğinde bir Instance'ı sağlıksız olarak değerlendiren minimum bir durum denetimidir. "ELB" durum denetimi daha sağlamdır, çünkü ASG'ye bir Instance'ın sağlıklı olup olmadığını belirlemek için hedef grubun durum denetimini kullanma ve hedef grup bunları sağlıksız olarak bildirirse Instance'ları otomatik olarak değiştirme talimatı verir. Bu şekilde, Instance'lar yalnızca tamamen kapalı olduklarında değil, örneğin bellekleri tükendiği veya kritik bir işlem çöktüğü için isteklere cevap vermeyi durdurduklarında da değiştirilir.

Son olarak, aws_lb_listener_rule kaynağını kullanarak listener rule'ları oluşturup tüm bu parçaları birbirine bağlamanın zamanı geldi:

resource "aws_lb_listener_rule" "asg" {
  listener_arn = aws_lb_listener.http.arn
  priority     = 100

  condition {
    path_pattern {
      values = ["*"]
    }
  }

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.asg.arn
  }
}

Önceki kod, ASG'nizi içeren hedef gruba herhangi bir yolla (*) eşleşen istekler gönderen bir listener rule ekler.

Load balancer'ı dağıtmadan önce yapmanız gereken son bir şey var: Daha önce sahip olduğunuz tek EC2 Instance'ın eski public_ip çıktısını ALB'nin DNS adını gösteren bir çıktıyla değiştirmek:

output "alb_dns_name" {
  value       = aws_lb.example.dns_name
  description = "The domain name of the load balancer"
}

Şimdi terraform init ve terraform plan komutlarını çalıştırın ve plan komutu çıktısını okuyun. Orijinal tek EC2 Instance'ınızın kaldırıldığını ve onun yerine Terraform'un bir launch configuration, ASG, ALB ve bir güvenlik grubu oluşturacağını görmelisiniz. Plan iyi görünüyorsa, yes yazın ve Enter'a basın. Uygulama tamamlandığında, alb_dns_name çıktısını görmelisiniz:

Outputs:
alb_dns_name = "terraform-asg-example-123.us-east-2.elb.amazonaws.com"

Bu URL'yi kopyalayın. EC2 Instance'ların önyüklenmesi ve ALB'de sağlıklı görünmesi birkaç dakika sürer. Bu arada, ne dağıttığınızı inceleyebilirsiniz. EC2 konsolunun ASG bölümünü açın ve Şekil 3'te gösterildiği gibi ASG'nin oluşturulduğunu görmelisiniz.

Şekil 3: EC2 ASG paneli

Instances sekmesine geçerseniz, Şekil 4'te gösterildiği gibi iki EC2 Instance'ın başlatıldığını görürsünüz.

Şekil 4: ASG'deki EC2 Instancel'ları çalışıyor

Eğer Load Balancers sekmesini tıklarsanız, Şekil 5'te gösterildiği gibi ALB'nizi görürsünüz.

Şekil 5: Oluşturduğumuz Application Load Balancer (ALB)

Son olarak, Target Groups sekmesine tıklarsanız, Şekil 6'da gösterildiği gibi hedef grubunuzu ve detaylarını bulabilirsiniz.

Şekil 6: Hedef gruplar

Target Groups sayfasında ekranın alt yarısında Targets sekmesini bulursanız, Instance'larınızın hedef gruba kaydolduğunu ve sağlık kontrollerinden geçtiğini görebilirsiniz. Durum göstergesinin her ikisi için de "healthy" olduğunu göstermesini bekleyin. Bu genellikle bir ila iki dakika sürer. Gördüğünüzde de, daha önce kopyaladığınız alb_dns_name adresine gidip sayfanızı test edin:

Şekil 7: Load balancer DNS adresini ziyaret ettiğimizde web server çıktımız resimdeki gibi olmalıdır.

Tebrikler! ALB, trafiği EC2 Instance'larınıza yönlendiriyor. URL'ye her eriştiğinizde, isteği işlemek için farklı bir Instance seçecektir. Artık tamamen çalışan bir web sunucuları kümeniz var!

Artık bu noktada, kümenizin yeni Instance'ları başlatmaya veya eskilerini kapatmaya nasıl tepki verdiğini görebilirsiniz. Örneğin, Instance sekmesine gidin ve onay kutusunu seçip üstteki Eylemler düğmesini tıklatarak ve ardından Instance Durumu'nu Sonlandır olarak ayarlayarak Instance'lardan birini terminate edin. ALB URL'sini test etmeye devam edin ve bir Instance'ı sonlandırırken bile her istek için 200 OK almanız gerekir, çünkü ALB, Instance'ın kapalı olduğunu otomatik olarak algılayacak ve ona yönlendirmeyi durduracaktır. Daha da ilginç olanı, Instance kapandıktan kısa bir süre sonra ASG, ikiden az Bulut Sunucusunun çalıştığını algılayacak ve yerine yenisini otomatik olarak başlatacaktır (kendi kendini iyileştiren!). Ayrıca, Terraform kodunuza desired_capacity parametresini ekleyerek ve uygulamayı yeniden çalıştırarak ASG'nin kendisini nasıl yeniden boyutlandırdığını görebilirsiniz.