Terraform

Terraform - AutoScale, ALB 구현하기

본 포스트는, Terraform Up & Running 테라폼 - OREILLY를 참고했습니다.

이번 포스트에서는 Terraform을 이용해서 AutoScale group을 만들고, 이를 연결해주는 Application Loadbalancer를 생성하려고 합니다.

이전 단계에서 사용했던 내용보다 조금 더 깊이 들어가서 따라가기 힘드니, 천천히 따라와 주세요.. ( 절대 제가 힘들어서 그런게 아닙니다. )

data

이전에서 var, output을 사용했다면, 이번에는 data 입니다.

data는 기존에 있는 리소스의 정보를 가져온다고 생각하면 됩니다.

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

위와 같이, 설정하면 default로 설정한 vpc의 정보를 가져오게 됩니다.

이를 terraform에 적용해서 terraform으로 생성한 리소스처럼 사용할 수 있게 됩니다.

data "aws_subnet_ids" "default" {
  vpc_id = data.aws_vpc.default.id
}

이번 포스트에서는 2개의 data를 사용합니다.

하나는 vpc, 다른 하나는 vpc에 생성되어 있는 subnet정보입니다.


launch_configuration 정의하기

Launch_configuration은 생성될 ec2에 대한 정의입니다.

resource "aws_launch_configuration" "example" {
  image_id      = "ami-0ea5eb4b05645aa8a"
  instance_type = "t3.nano"
  security_groups = [aws_security_group.instance.id]

  user_data = <<-EOF
              #!/bin/bash
              echo "Hello, world" > index.html
              nohup busybox httpd -f -p 8080 &
              EOF

  lifecycle {
    create_before_destroy = true
  }
}

기존에 정의했던 ec2에서 lifecycle이 추가되는데, 이는 lifecycle을 위와 같이 설정하지 않을 경우, 생성되어있는 리소스에 대한 참조가 있기 때문에 리소스를 수정, 삭제 할 수 없습니다.

이를 방지 하기 위해 lifecycle을 설정해서 삭제가능하게 합니다.


autoscaling_group 정의하기

resource "aws_autoscaling_group" "example" {
  min_size = 2
  max_size = 10

  launch_configuration = aws_launch_configuration.example.name
  vpc_zone_identifier = data.aws_subnet_ids.default.ids

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

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

위에서 설정한 launch_configuration을 이용해서 autoscaling_group을 생성합니다.

최소 사이즈와 최대 사이즈를 설정하고 data를 통해 받아온 vpc_zone_identifier를 설정합니다.

여기서 vpc의 subnet은 서로 다른 두개의 가용지역으로 구성되어야 합니다. (만약 2개 이상의 subnet이 없다면 생성해주세요)

target_group_arns 이라는게 있는데, 이는 이후에 생성하게 될 loadbalancer의 arn입니다.

arn이란 Amazon Resource Number로, AWS에서 생성되는 리소스에 대한 일련번호라고 이해하시면 됩니다.

Health_check_type의 경우 aws loadbalancer를 칭하는 ELB로 설정했습니다.


Load Balancer 정의하기

이 부분부터 혼동이 많이옵니다…

설정해야 할 내용은 크게 4개입니다.

  • aws_lb
  • aws_lb_listener
  • aws_lb_target_group
  • aws_lb_listener_rule

위에서 부터 천천히 진행하도록 합니다.


aws_lb

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

aws_lb의 경우 어떤 타입의 로드밸런서를 어느 서브넷에 어떤 보안규칙으로 설정할 지 정의합니다.


aws_lb_listener

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

  default_action {
    type = "fixed-response"

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

Lb_listener를 위와 같이 설정하면, 80번 포트를 통해서 수신하고, HTTP 프로토콜을 사용하며, 설정한 내용으로 응답을 보내지 않았을 경우, fixed_response로 설정한 404 메세지를 보내도록 액션을 취합니다.


aws_lb_target_group

resource "aws_lb_target_group" "asg" {
  name = "terraform-asg-example"
  port = var.server_port
  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
  }
}

target_group의 경우, 어떤 규칙을 이용해서 target을 정하는지를 정의합니다.

여기선 변수로 받을 sever_port를 이용해서 통신하고, HTTP프로토콜을 사용하도록 구성합니다.

이후, data를 통해 받은 vpc_id를 설정합니다.

또한 health_check 규칙이 있는데, 어떤 방법으로 health check를 할지 정의합니다.


aws_lb_listener_rule

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

  action {
    type = "forward"
    target_group_arn = aws_lb_target_group.asg.arn
  }
  condition {
    path_pattern {
      values = ["*"]
    }
  }
}

마지막으로 listener rule을 구성해서 생성한 target_group과 load balancer를 연결해줍니다.


security group

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

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

  egress {
    from_port = 0
    protocol  = "-1"
    to_port   = 0
    cidr_blocks = ["0.0.0.0/0"]
  }
}

이전에 설정한 security group과 다르게, ingress와 egress를 설정해줘야 합니다.

Health check를 통해 결과를 받아 들여야 하기 때문에, egress를 추가합니다.

여기서 egress는 포트와 상관없이 허용(0)하도록 설계 했습니다.


Output 설정하기

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

이 부분은 필수는 아니지만, 편의를 위해 설정합니다.

정상적으로 alb 및 autoscaling이 완성되면 alb의 dns를 출력합니다.

terraform apply -parallelism=30

모든 리소스 코드가 준비되었다면 apply해줍니다.

여기서 -parallelism값을 설정했는데, 병렬처리처럼 더 빠르게 생성하도록 설정했습니다.

curl http://[alb_dns_name]

완료되었다면, output으로 나온 값을 이용해서 테스트해보세요.

terraform destroy

실습을 마쳤다면 부셔주세요… 과금을 막을 방법입니다.