본격적으로 조금 더 복잡한 내용으로 들어가보도록한다.
많이 사용되는 WEB, WAS, DB 구조인 3-tier 아키텍쳐를 Terraform Code로 구성해보도록한다.
아키텍쳐 구성도
구성할 요소가 상당히 많은 것을 볼 수 있다.
이번 글에서는 네트워킹 요소(VPC)부터 구성하고, 그 다음으로 Application(WEB, WAS, DB)를 구축해보도록 한다.
Terraform 코드 작성
전체적인 프로젝트는 module화 시켜 최대한 가독성있게 제작했다.
(모듈화를 시킴으로써 각 모듈에서 필요한 요소들을 가져오고 내보내는 과정을 익힐 수 있었다. [output / variables])
├── main.tf
├── module
│ ├── application # EC2, ALB 등의 application 요소
│ │ ├── main.tf
│ │ ├── output.tf
│ │ └── variables.tf
│ ├── db # RDS 요소
│ │ ├── main.tf
│ │ ├── output.tf
│ │ └── variables.tf
│ └── vpc # 네트워킹 요소
│ ├── main.tf
│ ├── output.tf
│ └── variables.tf
├── output.tf
├── provider.tf
└── variables.tf
네트워킹 요소에서 생성할 리소스 목록은 대략 아래와 같다.
- VPC
- 서브넷 8개 (퍼블릭 2개, 프라이빗 6개)
- 라우팅 테이블 2개 (퍼블릭, 프라이빗)
- 인터넷 게이트웨이
- NAT 게이트웨이
- EIP (NAT 게이트웨이에 연결)
먼저 VPC와 서브넷을 구성해본다.
VPC와 서브넷의 CIDR 범위는 variable로 입력을 받도록 구성한다.
추가로 서브넷이 생성될 AZ도 일단은 variable로 처리를 해주었다.
## module/vpc/variables.tf
variable "vpc_cidr" {
default = "192.168.0.0/16"
}
variable "subnet_cidr" {
default = "192.168.x.0/24"
}
variable "availability_zone_list" {
type = list(string)
default = [ "ap-northeast-2a", "ap-northeast-2c" ]
}
다음으로 이 variable들을 바탕으로 VPC와 서브넷을 구성한다.
여기서 서브넷을 통 8개를 생성해야하는데, 하나씩 생성하게되면 코드가 불필요하게 길어지게 된다.
이 부분을 완화해보기 위해 count를 사용해보았다.
## module/vpc/main.tf
resource "aws_vpc" "simple-3tier-vpc" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
}
# subnet
resource "aws_subnet" "simple-3tier-public-subnet" {
count = 2
vpc_id = aws_vpc.simple-3tier-vpc.id
cidr_block = replace(var.subnet_cidr, "x", 1 + count.index) # 192.168.1.0/24, 192.168.2.0/24
availability_zone = element(var.availability_zone_list, count.index)
}
resource "aws_subnet" "simple-3tier-application-subnet" {
count = 4
vpc_id = aws_vpc.simple-3tier-vpc.id
cidr_block = replace(var.subnet_cidr, "x", 3 + count.index) # 192.168.3.0/24, 192.168.4.0/24, 192.168.5.0/24, 192.168.6.0/24
availability_zone = element(var.availability_zone_list, count.index)
}
resource "aws_subnet" "simple-3tier-db-subnet" {
count = 2
vpc_id = aws_vpc.simple-3tier-vpc.id
cidr_block = replace(var.subnet_cidr, "x", 7 + count.index) # 192.168.7.0/24, 192.168.8.0/24
availability_zone = element(var.availability_zone_list, count.index)
}
CIDR 범위를 x가 포함된 문자열로 받아 서브넷을 생성하는 부분에서 이 x를 count.index 값으로 치환시켜 3종류의 서브넷을 각각 생성할 수 있었다.
물론 모든 CIDR에 대응할 수 있는 완벽한 방법은 아니나, Simple하게 구성하는 과정이므로 이렇게 적용을 시켜보았다.
그리고 서브넷의 AZ도 2종류(ap-northeast-2a, ap-northeast-2c)로 나누어서 생성을 했는데, 여기서는 element를 사용했다.
element는 리스트로부터 하나의 원소를 추출하는 함수로, 리스트와 추출하고자 하는 인덱스 값으로 해당 인덱스의 값을 추출할 수 있다.
각각의 공식 Docs는 아래에 첨부
다음으로 NAT 게이트웨이와 IGW를 생성해보도록 한다.
## module/vpc/main.tf
# IGW
resource "aws_internet_gateway" "simple-3tier-igw" {
vpc_id = aws_vpc.simple-3tier-vpc.id
}
# NAT GW - EIP
resource "aws_eip" "simple-3tier-natgw-eip" {
domain = "vpc"
}
# NAT GW - natgw
resource "aws_nat_gateway" "simple-3tier-natgw" {
allocation_id = aws_eip.simple-3tier-natgw-eip.id
subnet_id = aws_subnet.simple-3tier-public-subnet.*.id[1]
}
NAT 게이트웨이와 연결할 EIP를 같이 생성하고 연결해주었다. 여기서 NAT 게이트웨이는 퍼블릭 서브넷에 생성해주어야한다.
이제 생성한 NAT 게이트웨이와 인터넷 게이트웨이를 라우팅 테이블에 연결하고, 라우팅 테이블을 각각 해당하는 서브넷에 연결해주도록 한다.
# Route Table
resource "aws_route_table" "simple-3tier-pub-rt" {
vpc_id = aws_vpc.simple-3tier-vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.simple-3tier-igw.id
}
}
resource "aws_route_table" "simple-3tier-priv-rt" {
vpc_id = aws_vpc.simple-3tier-vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_nat_gateway.simple-3tier-natgw.id
}
}
# Route table Associate
resource "aws_route_table_association" "simple-3tier-pub-asso" {
count = 2
subnet_id = aws_subnet.simple-3tier-public-subnet.*.id[count.index]
route_table_id = aws_route_table.simple-3tier-pub-rt.id
}
resource "aws_route_table_association" "simple-3tier-application-asso" {
count = 4
subnet_id = aws_subnet.simple-3tier-application-subnet.*.id[count.index]
route_table_id = aws_route_table.simple-3tier-priv-rt.id
}
resource "aws_route_table_association" "simple-3tier-db-asso" {
count = 2
subnet_id = aws_subnet.simple-3tier-db-subnet.*.id[count.index]
route_table_id = aws_route_table.simple-3tier-priv-rt.id
}
여기서도 count를 사용해서 반복되는 코드를 줄일 수 있다.
퍼블릭 서브넷에 사용할 라우팅 테이블에는 인터넷 게이트웨이를 바라보도록 연결하고, 프라이빗 서브넷에 사용할 라우팅 테이블에는 NAT 게이트웨이를 바라보도록 연결해주었다.
마지막으로 VPC 모듈에서 생성한 리소스 중 다른 모듈에서 사용하기 위해 output으로 처리하도록 한다.
## module/vpc/output.tf
output "vpc_id" {
value = aws_vpc.simple-3tier-vpc.id
}
output "public_subnet_id" {
value = aws_subnet.simple-3tier-public-subnet.*.id
}
output "application_subnet_id" {
value = aws_subnet.simple-3tier-application-subnet.*.id
}
output "db_subnet_id" {
value = aws_subnet.simple-3tier-db-subnet.*.id
}
이렇게 3tier 프로젝트의 네트워킹 요소만 구성해보았다.
해당 프로젝트는 깃헙 레포에서 확인할 수 있다.