해당 아키텍처를 Terraform을 통해 멱등성을 보장하면서 배포가능하도록 구축
위와 같이 임의로 Admin Access 권한을 가진 사용자 생성
해당 사용자의 권한은 추후 IaC 작성 이후 변경할 예정
이후 해당 사용자에 대한 Access CMD CLI Access 키를 생성한다
$ aws configure
AWS Access Key ID [****************CE7M]:
AWS Secret Access Key [****************qscY]:
Default region name [ap-northeast-2]:
Default output format [json]:
이후 aws configure을 완료하여 Terraform을 사용할 준비를 마친다
main.tf에 aws provider 사용을 정의한다
# Use AWS Provider
provider "aws" {
region = "ap-northeast-2"
}
variables.tf에 아래와 같이 구현되어야 하는 리소스의 이름을 미리 정의한다
# Terraform Variables
# Local Values
locals {
vpc_name = "judemin-vnet"
internet_gateway_name = "judemin-internet-gateway"
subnet1_name = "judemin-subnet-1"
subnet2_name = "judemin-subnet-2"
web_route_table_name = "judemin-web-public-route-table"
app_route_table_name = "judemin-app-private-route-table"
nat_gateway_name = "judemin-nat-gateway"
alb_security_group_name = "judemin-alb-security-group"
...
}
위와 같이 전체 구조를 한번에 생성하지 않고 VPC, Subnet 하위의 EC2 인스턴스를 먼저 구축하고 Nginx를 각 인스턴스에 설치하여 라우팅 테이블로 접근을 확인한다
############# VPC ###############
# VPC resource
resource "aws_vpc" "goorm_vpc" {
cidr_block = "172.16.0.0/16"
tags = {
Name = "goorm_vpc"
}
}
# Subnet-a resource
resource "aws_subnet" "goorm_subnet_a" {
vpc_id = aws_vpc.goorm_vpc.id
cidr_block = "172.16.0.0/24"
availability_zone = "ap-northeast-2a"
tags = {
Name = "goorm_subnet_a"
}
}
# Subnet-c resource
resource "aws_subnet" "goorm_subnet_c" {
vpc_id = aws_vpc.goorm_vpc.id
cidr_block = "172.16.10.0/24"
availability_zone = "ap-northeast-2c"
tags = {
Name = "goorm_subnet_c"
}
}
이미지속 구조와 같이 VPC 하위에 subnet-a, subnet-c를 생성한다
############ EC2 Instance ##############
resource "aws_instance" "public_web_a" {
ami = "ami-01123b84e2a4fba05"
instance_type = "t2.micro"
subnet_id = aws_subnet.goorm_subnet_a.id
vpc_security_group_ids = [
aws_security_group.web_server_sg.id,
]
tags = {
Name = "public_web_a"
}
# for aws_instance only
# azure: custom_data
# gcp: meta_data
user_data = <<-EOF
#! /bin/bash
sudo yum update
sudo yum install nginx -y
sudo service nginx start
sudo chkconfig nginx on
sudo service nginx status
EOF
}
...
이후 EC2 인스턴스를 위와 같이 생성한다, 이때 AMI와 t2.micro로 설정하여 프리티어를 사용할 수 있게 설정한다.
또한 user_data
를 통해 최초 인스턴스 생성시에 nginx를 설치할 수 있도록 설정하고 subnet_id
를 통해 인스턴스에 서브넷을 지정해준다.
############ Instance SG ##############
resource "aws_security_group" "web_server_sg" {
name = "web_server_sg"
description = "allow 22, 80"
vpc_id = aws_vpc.goorm_vpc.id
}
resource "aws_security_group_rule" "websg_ssh" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.web_server_sg.id
description = "ssh"
}
resource "aws_security_group_rule" "websg_http" {
type = "ingress"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.web_server_sg.id
description = "http"
}
resource "aws_security_group_rule" "websg_outbound" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.web_server_sg.id
description = "outbound"
}
또한 마지막으로 각 인스턴스에 적용될 SGRule을 SG로 묶어준다.
creating EC2 Instance: InvalidParameter: Security group sg-06d87931xx
and subnet subnet-09b91ac926xx belong to different networks
이떄 위와 같이 terraform apply
시에 위와 같은 오류가 발생하게 되었는데
이는 인스턴스 subnet VPC외 SG의 VPC가 일치하지 않아서 발생하는 문제이다
SG 리소스의 vpc_id
에 인스턴스 서브넷의 VPC를 넣어주어 해결하면 아래와 같이 정상적으로 인스턴스가 생성되는 것을 볼 수 있다.
하지만 인스턴스에 퍼블릭 DNS 및 IP 주소가 할당되지 않은 것을 확인할 수 있다.
resource "aws_subnet" "goorm_subnet_a" {
...
map_public_ip_on_launch = true
tags = {
Name = "goorm_subnet_a"
}
}
map_public_ip_on_launch
설정을 통해 해당 서브넷 하위 리소스 모두 public IP를 가질 수 있도록 설정할 수 있다. 또한 리소스에 대한 SG 설정으로 이를 제어한다.
############ Gateway ##############
# Internet gateway
resource "aws_internet_gateway" "goorm_internet_gw" {
vpc_id = aws_vpc.goorm_vpc.id
tags = {
Name = "goorm_internet_gw"
}
}
# Route table
resource "aws_route_table" "goorm_route_table" {
vpc_id = aws_vpc.goorm_vpc.id
tags = {
Name = "goorm_route_table"
}
}
# Route
resource "aws_route" "goorm_route" {
route_table_id = aws_route_table.goorm_route_table.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.goorm_internet_gw.id
}
resource "aws_route_table_association" "goorm_rtb_sub_a_aasosiation" {
subnet_id = aws_subnet.goorm_subnet_a.id
route_table_id = aws_route_table.goorm_route_table.id
}
# Route table association
resource "aws_route_table_association" "goorm_rtb_sub_c_aasosiation" {
subnet_id = aws_subnet.goorm_subnet_c.id
route_table_id = aws_route_table.goorm_route_table.id
}
Internet Gateway와 라우트 테이블을 설정하고 VPC id를 입력한다.
이후 route_table의 route를 생성하여 연결하고 aws_route_table_association
를 통해 각 서브넷을 라우팅 하여 게이트웨이로 접속할 수 있게 만든다.
############ Security Group #############
# Application Load Balancer SG
resource "aws_security_group" "web_alb_security_group" {
name = "web_alb_security_group"
description = "ALB Security Group"
vpc_id = aws_vpc.goorm_vpc.id
ingress {
description = "HTTP from Internet"
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"]
}
tags = {
Name = "web_alb_security_group"
}
}
위와 같이 ALB의 SG를 생성한다, 이때 VPC 포함 및 HTTP 요청을 활성화한다
######## Application Load Balancer #########
resource "aws_lb" "web-alb" {
name = "web-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.web_alb_security_group.id]
subnets = [
aws_subnet.goorm_subnet_a.id,
aws_subnet.goorm_subnet_c.id
]
}
# Send HTTP request to target group
resource "aws_lb_listener" "web-alb-listener" {
load_balancer_arn = aws_lb.web-alb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.web-alb-target-group.arn
}
}
resource "aws_lb_target_group" "web-alb-target-group" {
name = "web-alb-target-group"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.goorm_vpc.id
health_check {
path = "/"
matcher = 200
}
}
이후 각 subnet을 포함하는 ALB를 생성한다.
이때 aws_lb_listener
는 특정 포트와 프로토콜을 수신하여 해당 요청을 aws_lb_target_group
, 즉 타겟 서버에 포워딩 해주어 요청을 처리한다.
######## Auto Scaling Group #########
resource "aws_launch_configuration" "goorm-web-launconfig" {
name = "goorm-web-launconfig"
image_id = "ami-01123b84e2a4fba05"
instance_type = "t2.micro"
security_groups = [aws_security_group.web_server_sg.id]
user_data = <<-EOF
#! /bin/bash
sudo yum update
sudo yum install nginx -y
sudo service nginx start
sudo chkconfig nginx on
sudo service nginx status
EOF
lifecycle {
create_before_destroy = true
}
}
resource "aws_autoscaling_group" "goorm-web-asg" {
name = "goorm-web-asg"
launch_configuration = aws_launch_configuration.goorm-web-launconfig.name
vpc_zone_identifier = [
aws_subnet.goorm_subnet_a.id,
aws_subnet.goorm_subnet_c.id
]
target_group_arns = [aws_lb_target_group.web-alb-target-group.arn]
health_check_type = "ELB"
min_size = 2
max_size = 5
tag {
key = "name"
value = "goorm-web-asg"
propagate_at_launch = true
}
}
기존에 사용했던 EC2 인스턴스 대신 aws_autoscaling_group
은 aws_launch_configuration
를 통해 자동적으로 스케일을 조정한다.
따라서 aws_launch_configuration
에 nginx를 설치하도록 정의하고 기존에 정의한 SG에 연결한다. 이후 ASG에 서브넷을 지정하고 health check type을 ELB로 지정한 이후 apply로 전체 인스턴스를 생성하면 아키텍처 구현이 완료된다.