tf/autoscale/

Esse módulo é responsável pela criação de um grupo de auto escalonamento de instâncias EC2 para um serviço de alta disponibilidade (HA).

Para este projeto, resolvi que seria interessante utilizar um projeto que fiz há aproximadamente um ano para a disciplina de Tecnologias Web do 4º período do curso de Engenharia de Computação no Insper.

Então para isso, precisei primeiramente criar três instâncias EC2, uma para o banco de dados, uma para o frontend e uma para o backend, e instalar todas as dependências necessárias para que o projeto funcionasse.

Tendo as instâncias criadas, utilizei a ferramenta de criação de imagens do EC2 para criar uma imagem da instância que contém o backend, para que eu pudesse utilizar essa imagem para criar as Instâncias do Auto Scaling Group.

⚠️

Para que o Auto Scaling Group funcione não será necessário utilizar atributos de repetição como o que foi usado nos outros módulos (for_each), pois o Auto Scaling Group já é uma estrutura de repetição.

Criação de Chaves Públicas

O primeiro passo para a criação do Auto Scaling Group é a criação de uma chave pública para que seja possível acessar as instâncias EC2 que serão criadas.

⚠️

As chaves serão salvada no diretório keys.

resource "tls_private_key" "pk" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "aws_key_pair" "kp" {
key_name = "backendKey"
public_key = tls_private_key.pk.public_key_openssh
provisioner "local-exec" {
command = "echo '${tls_private_key.pk.private_key_pem}' > '${path.module}/keys/backendKey.pem'"
}
}

Criação do Security Group

Como no módulo ec2 o Security Group é criado para cada instância EC2, no Auto Scaling Group o Security Group será criado apenas uma vez, pois todas as instâncias EC2 que serão criadas terão o mesmo Security Group.

resource "aws_security_group" "websg" {
name = "security_group_for_web_server"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
lifecycle {
create_before_destroy = true
}
}

O security group criado permite que as instâncias EC2 criadas tenham acesso a porta 80 e 22.

Criação do Launch Configuration

O primeiro passo para criação do Auto Scaling Group é bem parecida com a criação de uma instância EC2, porém, ao invés de utilizar o recurso aws_instance, utilizamos o recurso aws_launch_configuration.

resource "aws_launch_configuration" "webcluster" {
image_id = "ami-xxxxxxxxxxxxxxxxx"
instance_type = "t2.micro"
security_groups = ["${aws_security_group.websg.id}"]
key_name = aws_key_pair.kp.key_name
lifecycle {
create_before_destroy = true
}
}
⚠️

O lifecycle é utilizado para que o Terraform crie uma nova instância antes de destruir a antiga.

Criação do Auto Scaling Group

A criação do Auto Scaling Group é bem simples, basta utilizar o recurso aws_autoscaling_group e passar os parâmetros necessários.

resource "aws_autoscaling_group" "scalegroup" {
launch_configuration = aws_launch_configuration.webcluster.name
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
min_size = 1
max_size = 4
enabled_metrics = ["GroupMinSize", "GroupMaxSize", "GroupDesiredCapacity", "GroupInServiceInstances", "GroupTotalInstances"]
metrics_granularity = "1Minute"
load_balancers = ["${aws_elb.elb1.id}"]
health_check_type = "ELB"
tag {
key = "Name"
value = "backend"
propagate_at_launch = true
}
}

O Auto Scaling Group foi criado com o mínimo de 1 instância e o máximo de 4 instâncias.

Criação das Políticas de Escala

Para que o Auto Scaling Group funcione, é necessário criar uma política de escala e associá-la ao Auto Scaling Group.

resource "aws_autoscaling_policy" "autopolicy" {
name = "terraform-autoplicy"
scaling_adjustment = 1
adjustment_type = "ChangeInCapacity"
cooldown = 300
autoscaling_group_name = aws_autoscaling_group.scalegroup.name
}
resource "aws_autoscaling_policy" "autopolicy-down" {
name = "terraform-autoplicy-down"
scaling_adjustment = -1
adjustment_type = "ChangeInCapacity"
cooldown = 300
autoscaling_group_name = aws_autoscaling_group.scalegroup.name
}

Criação do Alarme de CPU

Para que o Auto Scaling Group funcione, além das políticas de escala, é necessário criar um alarme que será acionado quando a CPU estiver acima de 70% por 2 minutos, e outro alarme que será acionado quando a CPU estiver abaixo de 10% por 2 minutos.

resource "aws_cloudwatch_metric_alarm" "cpualarm" {
alarm_name = "terraform-alarm"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "120"
statistic = "Average"
threshold = "70"
dimensions = {
AutoScalingGroupName = aws_autoscaling_group.scalegroup.name
}
alarm_description = "This metric monitor EC2 instance cpu utilization"
alarm_actions = ["${aws_autoscaling_policy.autopolicy.arn}"]
}
resource "aws_cloudwatch_metric_alarm" "cpualarm-down" {
alarm_name = "terraform-alarm-down"
comparison_operator = "LessThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "120"
statistic = "Average"
threshold = "10"
dimensions = {
AutoScalingGroupName = aws_autoscaling_group.scalegroup.name
}
alarm_description = "This metric monitor EC2 instance cpu utilization"
alarm_actions = ["${aws_autoscaling_policy.autopolicy-down.arn}"]
}

Criação do Security Group para o Load Balancer

O Security Group do Load Balancer é bem parecido com o Security Group das instâncias EC2, porém, não é necessário liberar a porta 22, pois o acesso ao Load Balancer será feito apenas pela porta 80.

resource "aws_security_group" "elbsg" {
name = "security_group_for_elb"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
lifecycle {
create_before_destroy = true
}
}

Criação do Load Balancer

A criação do Load Balancer é bem simples, basta utilizar o recurso aws_elb e passar os parâmetros necessários.

resource "aws_elb" "elb1" {
name = "terraform-elb"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
security_groups = ["${aws_security_group.elbsg.id}"]
listener {
instance_port = 80
instance_protocol = "http"
lb_port = 80
lb_protocol = "http"
}
health_check {
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 3
target = "HTTP:80/checkserver/"
interval = 30
}
cross_zone_load_balancing = true
idle_timeout = 400
connection_draining = true
connection_draining_timeout = 400
}

Criar o Load Balancer é necessário para que o Auto Scaling Group funcione, já que ele conecta as instâncias EC2 a um mesmo IP, permitindo que o tráfego seja balanceado entre as elas.

Criação da Política de Cookie

O recurso aws_lb_cookie_stickiness_policy é utilizado para criar uma política de cookie para o Load Balancer. Essa política é utilizada para que o tráfego seja direcionado para a mesma instância EC2, caso o usuário tenha um cookie de sessão.

resource "aws_lb_cookie_stickiness_policy" "cookie_stickness" {
name = "cookiestickness"
load_balancer = aws_elb.elb1.id
lb_port = 80
cookie_expiration_period = 600
}

Testando o Auto Scale

Para testar o Auto Scale, basta acessar o IP do Load Balancer e executar o comando abaixo:

curl http://terraform-elb-590342385.us-east-1.elb.amazonaws.com/checkserver/

O resultado será algo parecido com isso:

"Server is live, current time is: 27/11/2022 20:16:29"

Outro método de testar o Auto Scale é acessar o console do Auto Scaling Group e verificar se a página admin da API está disponível. Para isso, basta visitar esta url

⚠️

Caso queira realizar login na página de administração, me peça para criar um novo usuário no banco de dados.

Acesse também esta url para ver o site hospedado no servidor EC2 utilizando a API presente nas instâncias do Auto Scaling Group. Sinta-se livre para explorar o site :)