연재 시리즈

테라폼 시리즈 19편. ALB와 Auto Scaling Group 연동

악분 2022. 10. 29. 01:27
반응형

목표

테라폼으로 auto scaling group, Application Load Balancer을 생성합니다.

 

요구사항

 

상세내용

auto scaling과 alb연결은 하이레벨 수준에서는 아래그림과 같습니다. auto scaling이 관리하는 EC2 Instance를 alb가 자동으로 인식하여 트래픽을 부하분산합니다.

 

테라폼 코드로 위 흐름을 구현하려면 세부과정을 알아야합니다. ALB는 외부 요청을 받는 Listener와 Target group으로 구성됩니다. 그리고 Auto Scaling group이 Target group으로 연결하면 구성이 끝납니다.

 

Auto scaling group에서 Targer group연결할때는 Load balancing과 Health checks필드를 설정합니다.

 

코드작성

gitbub링크: https://github.com/sungwook-practice/terraform-study/tree/main/week2/alb

vpc.tf, sg.tf, asg.tf, alb.tf파일로 분리했습니다. ami는 data block을 사용했습니다.

 

- vpc.tf

provider "aws" {
  region  = "ap-northeast-2"
}
 
resource "aws_vpc" "akbun-vpc" {
  cidr_block       = "10.10.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true
 
  tags = {
    Name = "t101-study"
  }
}
 
resource "aws_subnet" "akbun-subnet1" {
  vpc_id     = aws_vpc.akbun-vpc.id
  cidr_block = "10.10.1.0/24"
 
  availability_zone = "ap-northeast-2a"
 
  tags = {
    Name = "t101-subnet1"
  }
}
 
resource "aws_subnet" "akbun-subnet2" {
  vpc_id     = aws_vpc.akbun-vpc.id
  cidr_block = "10.10.2.0/24"
 
  availability_zone = "ap-northeast-2c"
 
  tags = {
    Name = "t101-subnet2"
  }
}
 
resource "aws_internet_gateway" "akbun-igw" {
  vpc_id = aws_vpc.akbun-vpc.id
 
  tags = {
    Name = "t101-igw"
  }
}
 
# route table 생성
resource "aws_route_table" "akbun-rt" {
  vpc_id = aws_vpc.akbun-vpc.id
 
  tags = {
    Name = "t101-rt"
  }
}
 
# route table과 subnet 연결
resource "aws_route_table_association" "akubun-rt-association1" {
  subnet_id      = aws_subnet.akbun-subnet1.id
  route_table_id = aws_route_table.akbun-rt.id
}
 
# route table과 subnet 연결
resource "aws_route_table_association" "akubun-rt-association2" {
  subnet_id      = aws_subnet.akbun-subnet2.id
  route_table_id = aws_route_table.akbun-rt.id
}
 
# route 규칙 추가
resource "aws_route" "mydefaultroute" {
  route_table_id         = aws_route_table.akbun-rt.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.akbun-igw.id
}

 

- sg.tf

resource "aws_security_group" "akbun-mysg" {
  vpc_id      = aws_vpc.akbun-vpc.id
  name        = "T101 SG"
  description = "T101 Study SG"
}
 
resource "aws_security_group_rule" "mysginbound" {
  type              = "ingress"
  from_port         = 0
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.akbun-mysg.id
}
 
resource "aws_security_group_rule" "mysgoutbound" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.akbun-mysg.id
}

 

- alb.tf

외부에서 HTTP프로토콜 80/tcp를 요청하면 target group으로 포워딩 될 수 있도록 규칙을 추가했습니다.

resource "aws_lb" "akbun-alb" {
  name               = "t101-alb"
  load_balancer_type = "application"
  subnets            = [aws_subnet.akbun-subnet1.id, aws_subnet.akbun-subnet2.id]
  security_groups = [aws_security_group.akbun-mysg.id]

  tags = {
    Name = "t101-alb"
  }
}

resource "aws_lb_listener" "myhttp" {
  load_balancer_arn = aws_lb.akbun-alb.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 - T101 Study"
      status_code  = 404
    }
  }
}

resource "aws_lb_target_group" "akbun-tg" {
  name = "t101-alb-tg"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.akbun-vpc.id

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

resource "aws_lb_listener_rule" "akbun-albrule" {
  listener_arn = aws_lb_listener.myhttp.arn
  priority     = 100

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

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.akbun-tg.arn
  }
}

output "akbunalb_dns" {
  value       = aws_lb.akbun-alb.dns_name
  description = "The DNS Address of the ALB"
}

 

- asg.tf

health 방식을 ELB로 설정하고 target group을 테라폼 코드에서 생성한 target group을 설정했습니다. 그리고 EC2 Instance최소 갯수를 2개로 설정했습니다. user_data는 인스턴스 정보를 출력하는 웹 애플리케이션을 실행합니다.

resource "aws_autoscaling_group" "akbun-asg" {
  name                 = "myasg"
  launch_configuration = aws_launch_configuration.akbun-launchconfig.name
  vpc_zone_identifier  = [aws_subnet.akbun-subnet1.id, aws_subnet.akbun-subnet2.id]

  # ELB 연결
  health_check_type = "ELB"
  target_group_arns = [aws_lb_target_group.akbun-tg.arn]

  min_size = 2
  max_size = 4

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

resource "aws_launch_configuration" "akbun-launchconfig" {
  name_prefix     = "t101-lauchconfig-"
  image_id        = data.aws_ami.my_amazonlinux2.id
  instance_type   = "t2.nano"
  security_groups = [aws_security_group.akbun-mysg.id]
  associate_public_ip_address = true

  user_data = <<-EOF
              #!/bin/bash
              wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64
              mv busybox-x86_64 busybox
              chmod +x busybox
              RZAZ=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone-id)
              IID=$(curl 169.254.169.254/latest/meta-data/instance-id)
              LIP=$(curl 169.254.169.254/latest/meta-data/local-ipv4)
              echo "<h1>RegionAz($RZAZ) : Instance ID($IID) : Private IP($LIP) : Web Server</h1>" > index.html
              nohup ./busybox httpd -f -p 80 &
              EOF

  # Required when using a launch configuration with an auto scaling group.
  lifecycle {
    create_before_destroy = true
  }
}

 

- data.tf

data "aws_ami" "my_amazonlinux2" {
  most_recent = true
  filter {
    name   = "owner-alias"
    values = ["amazon"]
  }

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-ebs"]
  }

  owners = ["amazon"]
}

 

코드 반영

terraform apply명령어로 테라폼 코드를 aws에 반영합니다.

terraform apply

 

로드밸런서가 잘 생성되었는지 확인합니다. 그리고 Listeners탭에서 테라폼 코드가 추가한 규칙을 클릭합니다.

 

규칙 중 모든 요청이 Target Group으로 포워딩되는지 확인합니다.

 

Auto Scaling Group에서 Target Group과 연결이 잘 되었는지 확인합니다.

 

Target Group에서 Auto Scaling이 관리하는 EC2 Instance가 보이는지 확인합니다. 테라폼 코드에서 min_size를 2개로 설정했으므로 EC2 Instance가 총 2개입니다.

 

자 이제 ALB로 요청하면 Auto Scaling Group이 관리하는 EC2 Instance로 부하 분산되는지 확인해봅시다. curl과 sort, uniq명령어로 부하 분산이 되는지 쉽게 확인할 수 있습니다. 거의 50:50 비율로 2개의 EC2 Instance로 부하 분산이 잘 되었습니다.

ALBDNS=$(terraform output -raw akbunalb_dns)
for i in {1..100}; do curl -s http://$ALBDNS/ ; done | sort | uniq -c | sort -nr

반응형