본문으로 건너뛰기

Terraform Structure

3-Layer 구조로 공유 리소스(VPC, Data Stores)와 AZ별 리소스(EKS, NLB)를 분리합니다.

Directory Layout

terraform/environments/production/ap-northeast-2/
├── shared/ # Layer 1: VPC + Data Stores
│ ├── main.tf # VPC, SG, KMS, Aurora, DocumentDB, ElastiCache,
│ │ # MSK, OpenSearch, S3, Secrets Manager
│ ├── variables.tf
│ ├── outputs.tf # vpc_id, subnet_ids, sg_ids → remote state
│ ├── terraform.tfvars
│ └── backend.tf # S3 key: production/ap-northeast-2/shared/

├── eks-az-a/ # Layer 2: EKS + NLB for AZ-A
│ ├── main.tf # EKS(mall-apne2-az-a), ALB IRSA, NLB, OTel IRSA
│ ├── variables.tf
│ ├── terraform.tfvars
│ └── backend.tf # S3 key: production/ap-northeast-2/eks-az-a/

└── eks-az-c/ # Layer 3: EKS + NLB for AZ-C
├── main.tf # EKS(mall-apne2-az-c), ALB IRSA, NLB, OTel IRSA
├── variables.tf
├── terraform.tfvars
└── backend.tf # S3 key: production/ap-northeast-2/eks-az-c/
State 참조

eks-az-a/c는 terraform_remote_state.shared를 통해 Layer 1의 VPC ID, Subnet IDs, SG IDs를 참조합니다. 3개의 독립 state file로 blast radius를 최소화합니다.

Layer 1: Shared

공유 VPC, 보안, 데이터 스토어를 관리합니다.

ModuleResource특이사항
vpcVPC, 2 AZ subnets (Public/Private/Data)Private /20 (4,096 IPs for Karpenter)
security_groupsALB, NLB, EKS, Data SGsVPC CIDR에서만 접근
kms5 CMKs (aurora, docdb, cache, msk, s3)
aurora1 Writer + 2 Reader (AZ-A, AZ-C)is_primary=true (독립 클러스터)
documentdb2 instances (Global Cluster secondary)is_primary=false, source: us-east-1
elasticache1 shard, 1 replica (Standalone)Global Datastore 미참여 (독립)
msk4 brokers (2+2 per AZ)Independent cluster
opensearch3 Master + 2 Data (2-AZ)create_service_linked_role=false
s3Static + Analytics bucketsSecondary (no replication)

Key Configuration (terraform.tfvars)

environment = "production"
region = "ap-northeast-2"

vpc_cidr = "10.2.0.0/16"
availability_zones = ["ap-northeast-2a", "ap-northeast-2c"]

public_subnet_cidrs = ["10.2.1.0/24", "10.2.3.0/24"]
private_subnet_cidrs = ["10.2.16.0/20", "10.2.32.0/20"] # /20 for Karpenter!
data_subnet_cidrs = ["10.2.48.0/24", "10.2.49.0/24"]

eks_az_a_cluster_name = "mall-apne2-az-a"
eks_az_c_cluster_name = "mall-apne2-az-c"

docdb_global_cluster_identifier = "multi-region-mall-docdb"

Data Store Configuration

# Aurora: 독립 클러스터 (Global Cluster 미참여)
module "aurora" {
is_primary = true
global_cluster_identifier = "" # NOT joining global cluster
reader_count = 2
reader_availability_zones = ["ap-northeast-2a", "ap-northeast-2c"]
}

# DocumentDB: Global Cluster secondary
module "documentdb" {
is_primary = false # Global secondary
global_cluster_identifier = "multi-region-mall-docdb"
source_region = "us-east-1"
instance_count = 2
}

# ElastiCache: Standalone (NOT global)
module "elasticache" {
is_primary = true
global_replication_group_id = "" # NOT joining global datastore
}

# MSK: 4 brokers for 2+2 AZ distribution
module "msk" {
number_of_broker_nodes = 4
broker_instance_type = "kafka.m5.large"
}

Layer 2/3: EKS per AZ

각 AZ에 독립 EKS 클러스터, NLB, IRSA 역할을 배포합니다.

AZ-A (eks-az-a)

ResourceValue
Clustermall-apne2-az-a
Subnetprivate_subnet_ids[0] (AZ-A only)
NLBpublic_subnet_ids[0] (AZ-A only)
Role Suffix-apne2-az-a
IRSAALB Controller, OTel Collector, Tempo

AZ-C (eks-az-c)

ResourceValue
Clustermall-apne2-az-c
Subnetprivate_subnet_ids[1] (AZ-C only)
NLBpublic_subnet_ids[1] (AZ-C only)
Role Suffix-apne2-az-c
IRSAALB Controller, OTel Collector, Tempo

Remote State Reference

# eks-az-a/main.tf
data "terraform_remote_state" "shared" {
backend = "s3"
config = {
bucket = "multi-region-mall-terraform-state"
key = "production/ap-northeast-2/shared/terraform.tfstate"
region = "us-east-1"
}
}

module "eks" {
cluster_name = "mall-apne2-az-a"
vpc_id = data.terraform_remote_state.shared.outputs.vpc_id
private_subnet_ids = [data.terraform_remote_state.shared.outputs.private_subnet_ids[0]]
# Single subnet = single AZ isolation
}

State Management

StateS3 KeyResources
Sharedproduction/ap-northeast-2/shared/terraform.tfstateVPC, Data Stores
EKS AZ-Aproduction/ap-northeast-2/eks-az-a/terraform.tfstateEKS, NLB, IRSA
EKS AZ-Cproduction/ap-northeast-2/eks-az-c/terraform.tfstateEKS, NLB, IRSA
Apply 순서

반드시 sharedeks-az-aeks-az-c 순서로 apply하세요. EKS 레이어가 shared의 outputs를 참조합니다.