[DevOps/Terraform/T101] 테라폼으로 AWS ASG & ALB 생성
ASG (Auto Scaling Group)
클라우드의 장점 중의 하나로 서버를 Scale Out해 주는 기능이 있다.
대용량 트래픽을 처리하기 위해, 단일 서버에 대한 장애 대처를 위해, 시스템 고가용성을 위해,,, 등등 일반적으로 ASG (Auto Scaling Group) 을 사용하여 해결한다.
ASG는 EC2 인스턴스 클러스터 시작, 각 인스턴스 상태 모니터링, 실패한 인스턴스 교체, 로드에 따른 클러스터 사이즈 조정 등 많은 작업을 자동으로 처리할 수 있다.
Launch Configuration (시작 구성)
ASG는 Launch Configuration (시작 구성) 을 참고하여 인스턴스를 생성한다. Launch Configuration은 ASG에서 각 EC2 인스턴스를 어떻게 구성할 것인지 설정하는 시작 구성을 의미한다! aws_launch_configuration
리소스로 정의하며 aws_instance
리소스와 거의 동일한 매개 변수를 사용한다!
Launch Configuration은 변경할 수 없고 매개 변수를 변경하면 테라폼이 이를 대체하려고 한다.
테라폼에서는 aws_autoscaling_group
리소스를 사용하여 ASG 자체를 생성할 수 있다.
resource "aws_autoscaling_group" "example" {
launch_configuration = aws_launch_configuration.example.name
vpc_zone_identifier = data.aws_subnets.default.ids
min_size = 2
max_size = 10
tag {
key = "Name"
value = "terraform-asg-example"
propagate_at_launch = true
}
}
vpc_zone_identifier
인수를 이용해 aws_subnet_ids
데이터 소스에서 Subnet ID를 가져와서 ASG가 이 Subnet을 사용하도록 지시할 수 있다
Lifecycle (생명 주기)
ASG는 최소 2개의 EC2 인스턴스로 시작하여 최대 10개의 인스턴스를 생성할 수 있다.
근데 여기서 문제는!
테라폼에서 일반적으로 리소스를 교체할 때는 이전 리소스를 먼저 삭제한 다음 대체 리소스를 생성한다. 근데 ASG에 이전 리소스에 대한 참조가 있기 때문에 해당 리소스를 삭제할 수 없게 된다.
이 때~! lifecycle 생명 주기 (리소스 생성, 업데이트 및 삭제 방법) 설정을 사용하여 해결할 수 있다 ㅎㅎ 생명 주기… 알아 두자!
aws_launch_configuration
에 lifecycle
블록을 아래와 같이 추가해 주면 된다.
resource "aws_launch_configuration" "example" {
image_id = "ami-0e9bfdb247cc8de84"
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
# Required when using a launch configuration with an auto scaling group.
lifecycle {
create_before_destroy = true
}
}
create_before_destroy
는 유용하게 사용한다는 생명 주기 설정인데 테라폼은 리소스 교체 순서를 반대로 하여 교체 리소스 생성하고 기존 리소스를 삭제하는 설정이다.
이제 ASG를 진짜진짜!
아래와 같이 생성한다!
aws_ami
를 아마존 리눅스로 설정하고
aws_launch_configuration
를 설정하고 aws_autoscaling_group
를 설정한다!
lifecycle은 꼬옥-!
data "aws_ami" "yooga_amazonlinux2" {
most_recent = true
filter {
name = "owner-alias"
values = ["amazon"]
}
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-ebs"]
}00
owners = ["amazon"]
}
resource "aws_launch_configuration" "yoogalauchconfig" {
name_prefix = "t101-lauchconfig-"
image_id = data.aws_ami.yooga_amazonlinux2.id
instance_type = "t2.micro"
security_groups = [aws_security_group.myasg.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
}
}
resource "aws_autoscaling_group" "yoogaasg" {
name = "yoogaasg"
launch_configuration = aws_launch_configuration.yoogalauchconfig.name
vpc_zone_identifier = [aws_subnet.yoogasubnet1.id, aws_subnet.yoogasubnet2.id]
min_size = 2
max_size = 10
tag {
key = "Name"
value = "terraform-asg"
propagate_at_launch = true
}
}
LB (Load Balancer)
ASG으로 인스턴스 서버 수를 Scale In/Out 하고 있다면?
앞단에 로드밸런서를 배포하여 서버 전체에 트래픽을 분산시키고 모든 사용자에게 하나의 DNS명을 제공해 줘야 한다. (하나의 로드밸런서 IP로!)
AWS LB의 종류는 아래와 같다.
- ALB (Application Load Balancer) : 7 Layer에 해당되는 HTTP 및 HTTPS 트래픽 처리
- NLB (Network Load Balancer) : 4 Layer에 해당되는 TCP, UDP, TLS 트래픽 처리
- CLB (Classic Load Balancer) : ALB, NLB에서처럼 트래픽 처리는 동일하지만 기능은 훨씬 적다
aws_lb
리소스를 사용하여 로드 밸런서를 구성할 것인데 이 포스팅에서는 ALB를 구성할 것이다!
resource "aws_lb" "example" {
name = "terraform-ash-example"
load_balancer_type = "application"
subnets = data.aws_subnet_ids.default.ids
}
load_balancer_type
을 application
으로 설정하면 ALB로 구성할 수 있다.
subnets
는 default로 구성해도 되지만 아래와 같이 내가 사전에 구성한 리소스로 설정해도 된다.
subnets = [aws_subnet.yoogasubnet1.id, aws_subnet.yoogasubnet2.id]
security_groups = [aws_security_group.yoogasg.id]
aws_lb_listener
리소스로 기본 80포트를 수신하고 HTTP 프로토콜을 사용하고 리스너 규칙에 일치하지 않은 요청에 대한 default 응답은 404로 반환할 것이다.
resource "aws_lb_listener" "yoogahttp" {
load_balancer_arn = aws_lb.yoogaalb.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
}
}
}
기본적으로 모든 AWS 리소스는 Inbound/Outbound 트래픽은 All Deny이므로 새로운 보안 그룹을 생성해줘야 수신이 가능하다!
resource "aws_security_group" "yooga-web-sg" {
vpc_id = aws_vpc.yooga-vpc.id
name = "T101 SG"
description = "T101 Study SG"
}
resource "aws_security_group_rule" "yoogasginbound" {
type = "ingress"
from_port = 0
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.yooga-web-sg.id
}
resource "aws_security_group_rule" "yoogasgoutbound" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.yooga-web-sg.id
}
Inbound로 들어 오는 HTTP 트래픽을 허용해 주고
Outbound로 나가는 모든 트래픽은 허용해 줬다!
그 다음 aws_lb_target_group
리소스를 사용하여 ASG의 대상 그룹을 생성해야 하는데!
resource "aws_lb_target_group" "yoogaalbtg" {
name = "t101-alb-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.yoogavpc.id
health_check {
path = "/"
protocol = "HTTP"
matcher = "200-299"
interval = 5
timeout = 3
healthy_threshold = 2
unhealthy_threshold = 2
}
}
matcher
와 일치하는 응답을 반환하는 경우에만 health check가 통과되어 인스턴스를 정상으로 간주한다. (healthy)
output "yoogaalb_dns" {
value = aws_lb.yoogaalb.dns_name
description = "The DNS Address of the ALB"
}
마지막으로 EC2 인스턴스의 Public IP 출력문을 ALB의 DNS 명 출력문으로 바꿔 주었다!
Leave a comment