Post

[Terraform] ASG를 통한 웹 서버 클러스터 배포

[Terraform] ASG를 통한 웹 서버 클러스터 배포

실제 운영 환경에서 서버가 하나뿐이라면 매우 불안할 것이다. 단일 장애점(Single Point of Failure, SPOF)으로 충돌하거나 트래픽 과부하가 발생하면 사용자는 사이트에 액세스할 수 없다. 이를 해결하기 위해 단일 서버가 아닌 서버 클러스터를 구성해서 트래픽을 분산시키고, 트래픽의 양에 따라 클러스터의 크기를 늘리거나 줄여야 한다.

이를 오토 스케일링 그룹(ASG, Auto Scaling Group)을 통해 해결할 수 있다.

1. ASG를 만드는 순서

1) 시작 구성(launch configuration) 생성

각 EC2 인스턴스를 어떻게 구성할 것인지 설정하는 것이다. aws_instance 리소스와 거의 동일하지만 ami는 image_id로, vpc_security_group_ids는 security_groups로 사용한다.

1
2
3
4
5
6
7
8
9
10
11
resource "aws_launch_configuration" "example" {
  image_id = "ami-0deb35a8202ca99c1"
  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 ${var.server_port} &
              EOF
}

2) 오토 스케일링 그룹(ASG) 생성

1
2
3
4
5
6
7
8
9
10
11
12
resource "aws_autoscaling_group" "example" {
  launch_configuration = aws_launch_configuration.example.name

  min_size = 2
  max_size = 5

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

이 ASG는 2~5개의 EC2 인스턴스 사이에서 실행되며 각각 terraform-asg-example이라는 이름으로 태그가 지정된다. 시작 구성 정보(launch configuration)를 참고하여 인스턴스를 생성한다. 

3) 시작 구성(launch configuration)의 불변

일반적으로 리소스를 교체할 때 테라폼은 이전 리소스를 먼저 삭제한 다음 대체 리소스를 생성한다. 하지만 ASG에는 삭제한 이전 리소스에 대한 참조가 있기 때문에 테라폼이 해당 리소스를 삭제할 수 없다.

4) 수명 주기 설정

테라폼 리소스는 리소스 생성, 업데이트 및 삭제 방법을 구성하는 몇 가지 수명 주기(lifecycle) 설정을 지원한다.

create_before_destroy는 유용하게 사용된다. create_before_destroy를 true로 설정해 리소스를 교체하는 순서를 반대로 하여 교체 리소스를 먼저 생성하고(이전 리소스를 가리키고 있던 참조를 업데이트하여 교체한 리소스를 가리킴) 기존 리소스를 삭제한다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
resource "aws_launch_configuration" "example" {
  image_id = "ami-0deb35a8202ca99c1"
  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 ${var.server_port} &
              EOF
  // ASG에서 시작 구성을 사용할 때 필요
  lifecycle {
    create_before_destroy = true
  }
}

aws_launch_configuration 리소스에 추가

5) ASG에 subnet_ids 매개 변수 추가

ASG가 어느 VPC의 서브넷에 EC2를 배포할지 지정하는 매개 변수를 지정해줘야 한다.

각 서브넷은 AWS AZ(가용영역)에 있으므로 여러 서브넷에 배포하면 일부 데이터 센터가 중단되어도 서비스를 계속 실행할 수 있다. 서브넷 목록을 하드코딩할 수 있지만 유지 관리가 어렵고 이식이 불가능하므로, 데이터 소스를 사용하여 AWS 계정에서 서브넷 목록을 얻어오는 것이 더 적절한 방법이다.

데이터 소스는 테라폼을 실행할 때마다 공급자에서 가져온 읽기 전용 정보를 나타낸다. 단순히 데이터 공급자의 API만 물어보고 해당 데이터를 나머지 테라폼 코드에서 사용할 수 있도록 하는 방법이다.

ex) AWS의 경우 VPC 데이터, 서브넷 데이터, AMI ID, IP 주소 범위, 현재 사용자의 자격 증명 등을 조회하는 데이터 소스가 포함되어 있다.

  1. 기본 VPC를 찾도록 지시
    1
    2
    3
    4
    
     // default VPC 탐색
     data "aws_vpc" "default" {
     default = true
     }
    
  2. 추가 정보
    1) aws_subnets 데이터 소스를 사용하여 서브넷 정보를 가져오겠다라는 것을 의미한다.
    2) 필터링할 값을 리스트의 key-value 형태로 지정 -> data.aws_vpc.default.id를 통해 가져온 default VPC의 ID를 값으로 한다.
    1
    2
    3
    4
    5
    6
    7
    
     // default VPC에 속하는 모든 서브넷을 필터링하여 저장
     data "aws_subnets" "default" {
     filter {
         name = "vpc-id"
         values = [data.aws_vpc.default.id]
     }
     }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
     resource "aws_autoscaling_group" "example" {
     launch_configuration = aws_launch_configuration.example.name
        
     // EC2를 생성할 VPC, 서브넷 정보
     vpc_zone_identifier = data.aws_subnets.default.ids
    
     min_size = 2
     max_size = 5
    
     tag {
         key = "Name"
         value = "terraform-asg-example"
         propagate_at_launch = true
     }
     }
    

6) 결과 확인

  1. terraform apply image

  2. 시작 구성(launch configuration) image

  3. default VPC에서 가져온 서브넷 정보 정상 입력 image

  4. 지정한 min 2, max 5 image

  5. 마지막 terraform destroy로 꼭 삭제하기!

This post is licensed under CC BY 4.0 by the author.