- 개발자가 새로운 버전을 릴리즈하면 Git Action을 통해 자동화되어 진행됩니다. ECR 이미지 Push, 새 태스크 정의 생성, ECS 서비스 업데이트가 포함됩니다.
- Route 53을 통해 지정한 도메인으로 사용자가 api 요청을 보냅니다.
- DynamoDB에 접근하여 CRUD 요청을 처리합니다.
전체 파일 구성은 다음과 같다.
관리를 위해 서비스 별로 파일을 나누어 구성하는 것을 선호한다.
main.tf
provider "aws" {
region = "ap-northeast-2"
}
vpc.tf
# vpc 생성
resource "aws_vpc" "mb_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "mb_vpc"
}
}
# 퍼블릭 서브넷 생성
resource "aws_subnet" "public_subnet_1" {
vpc_id = aws_vpc.mb_vpc.id
cidr_block = "10.0.0.0/20"
availability_zone = "ap-northeast-2a"
map_public_ip_on_launch = true
tags = {
Name = "mb-pub-sub-1"
}
}
resource "aws_subnet" "public_subnet_2" {
vpc_id = aws_vpc.mb_vpc.id
cidr_block = "10.0.16.0/20"
availability_zone = "ap-northeast-2c"
map_public_ip_on_launch = true
tags = {
Name = "mb-pub-sub-2"
}
}
# 프라이빗 서브넷 생성
resource "aws_subnet" "private_subnet_1" {
vpc_id = aws_vpc.mb_vpc.id
cidr_block = "10.0.128.0/20"
availability_zone = "ap-northeast-2a"
tags = {
Name = "mb-prv-sub-1-by-tf"
}
}
resource "aws_subnet" "private_subnet_2" {
vpc_id = aws_vpc.mb_vpc.id
cidr_block = "10.0.144.0/20"
availability_zone = "ap-northeast-2c"
tags = {
Name = "mb-prv-sub-2-by-tf"
}
}
# 서브넷 그룹 설정
resource "aws_db_subnet_group" "mb_subnet_group" {
name = "mb_subnet_group"
subnet_ids = [aws_subnet.private_subnet_1.id, aws_subnet.private_subnet_2.id]
}
# IGW 생성
resource "aws_internet_gateway" "mb-igw" {
vpc_id = aws_vpc.mb_vpc.id
tags = {
Name = "mb-igw"
}
}
# 라우팅 테이블 생성
resource "aws_route_table" "pubroutetable" {
vpc_id = aws_vpc.mb_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.mb-igw.id
}
tags = {
Name = "mb-public-route-table"
}
}
# 라우팅 테이블 연결
resource "aws_route_table_association" "pubassociation1" {
subnet_id = aws_subnet.public_subnet_1.id
route_table_id = aws_route_table.pubroutetable.id
}
resource "aws_route_table_association" "pubassociation2" {
subnet_id = aws_subnet.public_subnet_2.id
route_table_id = aws_route_table.pubroutetable.id
}
# NGW 생성
resource "aws_eip" "eip" {
vpc = true
lifecycle {
create_before_destroy = true
}
tags = {
Name = "eip"
}
}
resource "aws_nat_gateway" "ngw" {
allocation_id = aws_eip.eip.id
subnet_id = aws_subnet.public_subnet_1.id
tags = {
Name = "mb-ngw"
}
}
# 라우팅 테이블 생성
resource "aws_route_table" "prvroutetable-1" {
vpc_id = aws_vpc.mb_vpc.id
tags = {
Name = "mb-prv-route-table-1"
}
}
resource "aws_route_table" "prvroutetable-2" {
vpc_id = aws_vpc.mb_vpc.id
tags = {
Name = "mb-prv-route-table-2"
}
}
# 라우팅 테이블 연결
resource "aws_route_table_association" "prvassociation1" {
subnet_id = aws_subnet.private_subnet_1.id
route_table_id = aws_route_table.prvroutetable-1.id
}
resource "aws_route_table_association" "prvassociation2" {
subnet_id = aws_subnet.private_subnet_2.id
route_table_id = aws_route_table.prvroutetable-2.id
}
resource "aws_route" "prvroute-1" {
route_table_id = aws_route_table.prvroutetable-1.id
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.ngw.id
}
resource "aws_route" "prvroute-2" {
route_table_id = aws_route_table.prvroutetable-2.id
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.ngw.id
}
# 엔드포인트
resource "aws_vpc_endpoint" "endpoint_s3" {
vpc_id = aws_vpc.mb_vpc.id
service_name = "com.amazonaws.ap-northeast-2.s3"
}
resource "aws_vpc_endpoint" "endpoint_ecr_dkr" {
vpc_id = aws_vpc.mb_vpc.id
service_name = "com.amazonaws.ap-northeast-2.ecr.dkr"
vpc_endpoint_type = "Interface"
}
resource "aws_vpc_endpoint" "endpoint_ecr_api" {
vpc_id = aws_vpc.mb_vpc.id
service_name = "com.amazonaws.ap-northeast-2.ecr.api"
vpc_endpoint_type = "Interface"
}
resource "aws_vpc_endpoint" "endpoint_log" {
vpc_id = aws_vpc.mb_vpc.id
service_name = "com.amazonaws.ap-northeast-2.logs"
vpc_endpoint_type = "Interface"
}
resource "aws_vpc_endpoint" "endpoint_ssm" {
vpc_id = aws_vpc.mb_vpc.id
service_name = "com.amazonaws.ap-northeast-2.ssm"
vpc_endpoint_type = "Interface"
}
security_gruop.tf
resource "aws_security_group" "mb_security_gruop" {
vpc_id = aws_vpc.mb_vpc.id
name = "mb_security_gruop"
description = "mb_security_gruop"
tags = {
Name = "final-sg-by-tf"
}
ingress {
from_port = 22
to_port = 22
protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 9000
to_port = 9000
protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
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"]
}
}
iam.tf
resource "aws_iam_role" "mb_ecsIAM" {
name = "mb_ecsIAM"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
variable "policy_arn" {
default = [
"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
"arn:aws:iam::aws:policy/SecretsManagerReadWrite"
]
}
resource "aws_iam_role_policy_attachment" "role_policy_attachment" {
role = aws_iam_role.mb_ecsIAM.name
count = length(var.policy_arn)
policy_arn = var.policy_arn[count.index]
}
alb.tf
resource "aws_lb_target_group" "mb-target-group" {
name = "mb-target-group"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.mb_vpc.id
target_type = "ip"
}
resource "aws_lb" "mb-alb" {
name = "mb-alb"
load_balancer_type = "application"
subnets = [aws_subnet.public_subnet_1.id, aws_subnet.public_subnet_2.id]
security_groups = [aws_security_group.mb_security_gruop.id]
}
resource "aws_lb_listener" "mb_listener" {
load_balancer_arn = aws_lb.mb-alb.arn
port = 80
protocol = "HTTP"
default_action {
target_group_arn = aws_lb_target_group.mb-target-group.arn
type = "forward"
}
}
cloudwatch.tf
resource "aws_cloudwatch_log_group" "mb_log" {
name = "/ecs/mb_container"
retention_in_days = 7
}
dynamodb.tf
resource "aws_dynamodb_table" "marketboro" {
name = "marketboro"
billing_mode = "PROVISIONED"
read_capacity= "30"
write_capacity= "30"
attribute {
name = "id"
type = "N"
}
hash_key = "id"
}
task_definition.tf
resource "aws_ecs_task_definition" "mb_definition" {
family = "mb_definition"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = 1024
memory = 2048
execution_role_arn = aws_iam_role.mb_ecsIAM.arn
task_role_arn = aws_iam_role.mb_ecsIAM.arn
container_definitions = jsonencode([{
essential = true
name = "mb_container"
image = "177938377658.dkr.ecr.ap-northeast-2.amazonaws.com/marketboro:latest"
cpu = 0
portMappings = [
{
name = "mb_container-9000-tcp"
protocol = "tcp"
appProtocol = "http"
containerPort = 9000
hostPort = 9000
}
]
logConfiguration = {
logDriver = "awslogs",
options = {
awslogs-group = "/ecs/mb_container"
awslogs-region = "ap-northeast-2"
awslogs-stream-prefix = "ecs"
}
}
secrets= [
{
name= "AWS_ACCESS_KEY_ID",
valueFrom= "arn:aws:secretsmanager:ap-northeast-2:177938377658:secret:access_key-CCfz3S:ACCESS_KEY::"
secretOptions = [
{
name = "AutomationLambdaInvoke"
value = "Disabled"
}
]
},
{
name= "AWS_SECRET_ACCESS_KEY",
valueFrom= "arn:aws:secretsmanager:ap-northeast-2:177938377658:secret:access_key-CCfz3S:SECRET_KEY::"
secretOptions = [
{
name = "AutomationLambdaInvoke"
value = "Disabled"
}
]
}
]
}
]
)
}
ecs.tf
resource "aws_ecs_cluster" "mb_cluster" {
name = "mb_cluster"
}
resource "aws_ecs_service" "mb_service" {
name = "mb-service"
cluster = aws_ecs_cluster.mb_cluster.id
task_definition = aws_ecs_task_definition.mb_definition.id
desired_count = 1
launch_type = "FARGATE"
enable_execute_command = true
network_configuration {
subnets = [aws_subnet.public_subnet_1.id, aws_subnet.public_subnet_2.id]
security_groups = [aws_security_group.mb_security_gruop.id]
assign_public_ip = true
}
load_balancer {
target_group_arn = aws_lb_target_group.mb-target-group.arn
container_name = "mb_container"
container_port = 9000
}
depends_on = [ aws_lb_listener.mb_listener ]
}