Elastic Load Balancer 실습
서비스를 위한 기본 구성 요소 생성
Load Balancer 생성
Load Balancer는 여러 인스턴스에 트래픽을 분배해주기 위해서 반드시 필요한 리소스입니다. EC2 위에 올라가 있는 대부분의 서비스는 LB를 앞 단에 두는 것이 보통인데, LB의 경우에는 설정할 것이 상당히 많아 코드로 한 번 정리해놓으면 편리하게 생성/관리하실 수 있습니다.
실습에서 생성할 리소스는 아래와 같습니다.
Load Balancer
Target Group
https(443) : redirect to instance
http(80) : redirect to 443
Route53 Record
A record for ELB
Module 구성
보통 서비스를 위한 리소스는 환경별로 동일하게 생성하는 경우가 많습니다. 따라서 같은 코드를 변수만 바꿔서 사용할 수 있도록 Module을 이용하여 생성합니다.
Module을 사용할 때는 최대한 고유 명사를 없애고 변수처리하는 것이 좋습니다. 고유 명사를 변수로 대체하면 이후에 다른 서비스를
_module
폴더의 구조는 아래와 같습니다.
outputs.tf : 모듈내에서의 output.
service.tf : 모든 리소스 생성 코드가 포함된 파일
var_lb.tf : Load Balancer 관련 변수 정의 파일
var_sg.tf : Security Group 관련 변수 정의 파일
variables.tf : 기타 변수 정의 파일
$ tree
.
└── hello
├── outputs.tf
├── service.tf
├── var_lb.tf
├── var_sg.tf
└── variables.tf
실제로 리소스를 생성하는 부분인 service.tf
를 확인해보도록 하겠습니다.
############ Security Group For External LB
resource "aws_security_group" "external_lb" {
name = "${var.service_name}-${var.vpc_name}-ext"
description = "${var.service_name} external LB SG"
vpc_id = var.target_vpc
# Only allow access from IPs or SGs you specifiy in ext_lb_ingress_cidrs variables
# If you don't want to use HTTPS then remove this block
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = var.ext_lb_ingress_cidrs
description = "External service https port"
}
# Allow 80 port
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = var.ext_lb_ingress_cidrs
description = "External service http port"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["10.0.0.0/8"]
description = "Internal outbound any traffic"
}
tags = var.sg_variables.external_lb.tags[var.shard_id]
}
################## Security Group for EC2
resource "aws_security_group" "ec2" {
name = "${var.service_name}-${var.vpc_name}"
description = "${var.service_name} Instance Security Group"
vpc_id = var.target_vpc
# Service Port will be passed via variable.
ingress {
from_port = var.service_port
to_port = var.service_port
protocol = "tcp"
# Allow external LB Only for ec2 instance
security_groups = [
aws_security_group.external_lb.id,
]
description = "Port Open for ${var.service_name}"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Internal outbound traffic"
}
tags = {
Name = "${var.service_name}-${var.vpc_name}-sg"
app = var.service_name
stack = var.vpc_name
}
}
#################### External ALB
resource "aws_lb" "external" {
name = "${var.service_name}-${var.shard_id}-ext"
subnets = var.public_subnets
internal = false
# For external LB,
# Home SG (Includes Office IPs) could be added if this service is internal service.
security_groups = [
aws_security_group.external_lb.id,
var.home_sg,
]
# For HTTP service, application LB is recommended.
# You could use other load_balancer_type if you want.
load_balancer_type = "application"
tags = var.lb_variables.external_lb.tags[var.shard_id]
}
#################### External LB Target Group
resource "aws_lb_target_group" "external" {
name = "${var.service_name}-${var.shard_id}-ext"
port = var.service_port
protocol = "HTTP"
vpc_id = var.target_vpc
slow_start = var.lb_variables.target_group_slow_start[var.shard_id]
deregistration_delay = var.lb_variables.target_group_deregistration_delay[var.shard_id]
# Change the health check setting
health_check {
interval = 15
port = var.healthcheck_port
path = "/"
timeout = 3
healthy_threshold = 3
unhealthy_threshold = 2
matcher = "200"
}
tags = var.lb_variables.external_lb_tg.tags[var.shard_id]
}
#################### Listener for HTTPS service
resource "aws_lb_listener" "external_443" {
load_balancer_arn = aws_lb.external.arn
port = "443"
protocol = "HTTPS"
# If you want to use HTTPS, then you need to add certificate_arn here.
certificate_arn = var.acm_external_ssl_certificate_arn
default_action {
target_group_arn = aws_lb_target_group.external.arn
type = "forward"
}
}
#################### Listener for HTTP service
resource "aws_lb_listener" "external_80" {
load_balancer_arn = aws_lb.external.arn
port = "80"
protocol = "HTTP"
# This is for redirect 80.
# This means that it will only allow HTTPS(443) traffic
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
# 301 -> Permanant Movement
status_code = "HTTP_301"
}
}
}
#################### Route53 Record
resource "aws_route53_record" "external_dns" {
zone_id = var.route53_external_zone_id
name = var.domain_name
type = "A"
set_identifier = var.aws_region
latency_routing_policy {
region = var.aws_region
}
alias {
name = aws_lb.external.dns_name
zone_id = aws_lb.external.zone_id
evaluate_target_health = true
}
}
환경 구분
_module
폴더와 같은 path에 환경별로 폴더를 만드시면 됩니다. 아래는 dev와 prod를 위한 예시입니다. 자세히 보시면 아시겠지만, 각 환경 내의 파일 구성은 완전히 동일합니다. (단, 변수 값은 당연히 다릅니다.) 이렇게 구성하면, 새로운 환경이 필요한 경우 손쉽게 동일한 구성의 리소스를 생성하실 수 있습니다.
.
├── _module
│ └── hello
│ ├── outputs.tf
│ ├── service.tf
│ ├── var_lb.tf
│ ├── var_sg.tf
│ └── variables.tf
├── dayoned_apnortheast2
│ ├── backend.tf
│ ├── output.tf -> ../output.tf
│ ├── provider.tf -> ../provider.tf
│ ├── remote_state.tf
│ ├── service.tf
│ ├── terraform.tfvars
│ ├── var_global.tf -> ../../../variables/var_global.tf
│ ├── var_lb.tf -> ../variables/var_lb.tf
│ ├── var_route53.tf -> ../../../variables/var_route53.tf
│ ├── var_sg.tf -> ../variables/var_sg.tf
│ └── variables.tf -> ../variables.tf
├── dayonep_apnortheast2
│ ├── backend.tf
│ ├── output.tf -> ../output.tf
│ ├── provider.tf -> ../provider.tf
│ ├── remote_state.tf
│ ├── service.tf
│ ├── terraform.tfvars
│ ├── var_global.tf -> ../../../variables/var_global.tf
│ ├── var_lb.tf -> ../variables/var_lb.tf
│ ├── var_route53.tf -> ../../../variables/var_route53.tf
│ ├── var_sg.tf -> ../variables/var_sg.tf
│ └── variables.tf -> ../variables.tf
├── output.tf
├── provider.tf
├── variables
│ ├── var_lb.tf
│ └── var_sg.tf
└── variables.tf
이 중에서 모듈을 사용하는 service.tf
파일을 살펴보도록 하겠습니다.
# Use module for service
module "hello" {
source = "../_module/hello"
# Name of service
service_name = "hello"
# Port for service and healthcheck
service_port = 8080
healthcheck_port = 8080
# VPC Information via remote_state
shard_id = data.terraform_remote_state.vpc.outputs.shard_id
public_subnets = data.terraform_remote_state.vpc.outputs.public_subnets
private_subnets = data.terraform_remote_state.vpc.outputs.private_subnets
aws_region = data.terraform_remote_state.vpc.outputs.aws_region
vpc_cidr_numeral = data.terraform_remote_state.vpc.outputs.cidr_numeral
route53_internal_domain = data.terraform_remote_state.vpc.outputs.route53_internal_domain
route53_internal_zone_id = data.terraform_remote_state.vpc.outputs.route53_internal_zone_id
target_vpc = data.terraform_remote_state.vpc.outputs.vpc_id
vpc_name = data.terraform_remote_state.vpc.outputs.vpc_name
billing_tag = data.terraform_remote_state.vpc.outputs.billing_tag
# Domain Name
# This will be the prefix of record
# e.g) hello.dayonedevops.com
domain_name = "hello"
# Route53 variables
acm_external_ssl_certificate_arn = var.r53_variables.prod.star_dayonedevops_com_acm_arn_apnortheast2
route53_external_zone_id = var.r53_variables.prod.dayonedevops_com_zone_id
# Resource LoadBalancer variables
lb_variables = var.lb_variables
# Security Group variables
sg_variables = var.sg_variables
# Home Security Group via remote_state
home_sg = data.terraform_remote_state.vpc.outputs.aws_security_group_home_id
# CIDR for external LB
# Control allowed IP for external LB
ext_lb_ingress_cidrs = [
"0.0.0.0/0"
]
}
생성이 완료된 후 Autoscaling만 target group에 붙이면 실제 서비스를 https://hello.dayonedevops.com
를 통해 운영하실 수 있습니다.
Last updated