# 프리티어 가능 VPC: 10.0.16.0/20 Public Subnet 2개 DB Isolated Subnet 2개 EKS Cluster EKS Managed Node Group: t3.micro, 1대 NAT 없음 노드는 Public Subnet에 배치 1 ------------------------ cd mkdir 23 cd 23 cat <<'EOF' > main.tf terraform { required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" version = ">= 5.0" } } } provider "aws" { region = var.region } data "aws_availability_zones" "available" { state = "available" } variable "region" { type = string default = "ap-northeast-2" } variable "name" { type = string default = "ha-compact" } variable "vpc_cidr" { type = string default = "10.0.16.0/20" } variable "kubernetes_version" { type = string default = "1.34" } locals { az_a = data.aws_availability_zones.available.names[0] az_b = data.aws_availability_zones.available.names[1] tags = { Project = var.name Managed = "terraform" } } # -------------------------------------------------- # VPC # -------------------------------------------------- resource "aws_vpc" "main" { cidr_block = var.vpc_cidr enable_dns_support = true enable_dns_hostnames = true tags = merge(local.tags, { Name = "${var.name}-vpc" }) } resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.main.id tags = merge(local.tags, { Name = "${var.name}-igw" }) } # Public Subnets (EKS Node 배치) resource "aws_subnet" "public_a" { vpc_id = aws_vpc.main.id cidr_block = "10.0.16.0/24" availability_zone = local.az_a map_public_ip_on_launch = true tags = merge(local.tags, { Name = "${var.name}-public-a" "kubernetes.io/role/elb" = "1" "kubernetes.io/cluster/${var.name}-eks" = "shared" }) } resource "aws_subnet" "public_b" { vpc_id = aws_vpc.main.id cidr_block = "10.0.17.0/24" availability_zone = local.az_b map_public_ip_on_launch = true tags = merge(local.tags, { Name = "${var.name}-public-b" "kubernetes.io/role/elb" = "1" "kubernetes.io/cluster/${var.name}-eks" = "shared" }) } # DB Isolated Subnets resource "aws_subnet" "db_a" { vpc_id = aws_vpc.main.id cidr_block = "10.0.28.0/24" availability_zone = local.az_a tags = merge(local.tags, { Name = "${var.name}-db-a" }) } resource "aws_subnet" "db_b" { vpc_id = aws_vpc.main.id cidr_block = "10.0.29.0/24" availability_zone = local.az_b tags = merge(local.tags, { Name = "${var.name}-db-b" }) } # Route Tables resource "aws_route_table" "public" { vpc_id = aws_vpc.main.id tags = merge(local.tags, { Name = "${var.name}-rt-public" }) } resource "aws_route" "public_default" { route_table_id = aws_route_table.public.id destination_cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.igw.id } resource "aws_route_table_association" "public_a" { subnet_id = aws_subnet.public_a.id route_table_id = aws_route_table.public.id } resource "aws_route_table_association" "public_b" { subnet_id = aws_subnet.public_b.id route_table_id = aws_route_table.public.id } # DB RouteTable (격리: 기본 라우트 없음) resource "aws_route_table" "db" { vpc_id = aws_vpc.main.id tags = merge(local.tags, { Name = "${var.name}-rt-db" }) } resource "aws_route_table_association" "db_a" { subnet_id = aws_subnet.db_a.id route_table_id = aws_route_table.db.id } resource "aws_route_table_association" "db_b" { subnet_id = aws_subnet.db_b.id route_table_id = aws_route_table.db.id } # -------------------------------------------------- # IAM for EKS Cluster # -------------------------------------------------- resource "aws_iam_role" "eks_cluster_role" { name = "${var.name}-eks-cluster-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { Service = "eks.amazonaws.com" } Action = "sts:AssumeRole" } ] }) tags = local.tags } resource "aws_iam_role_policy_attachment" "eks_cluster_policy" { role = aws_iam_role.eks_cluster_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" } # -------------------------------------------------- # IAM for EKS Node Group # -------------------------------------------------- resource "aws_iam_role" "eks_node_role" { name = "${var.name}-eks-node-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } Action = "sts:AssumeRole" } ] }) tags = local.tags } resource "aws_iam_role_policy_attachment" "node_amazon_eks_worker" { role = aws_iam_role.eks_node_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" } resource "aws_iam_role_policy_attachment" "node_amazon_eks_cni" { role = aws_iam_role.eks_node_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" } resource "aws_iam_role_policy_attachment" "node_ecr_readonly" { role = aws_iam_role.eks_node_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly" } # -------------------------------------------------- # Security Group for EKS Cluster # -------------------------------------------------- resource "aws_security_group" "eks_cluster_sg" { name = "${var.name}-eks-cluster-sg" description = "EKS cluster security group" vpc_id = aws_vpc.main.id egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = merge(local.tags, { Name = "${var.name}-eks-cluster-sg" }) } # -------------------------------------------------- # EKS Cluster # -------------------------------------------------- resource "aws_eks_cluster" "main" { name = "${var.name}-eks" role_arn = aws_iam_role.eks_cluster_role.arn version = var.kubernetes_version vpc_config { subnet_ids = [aws_subnet.public_a.id, aws_subnet.public_b.id] endpoint_private_access = false endpoint_public_access = true security_group_ids = [aws_security_group.eks_cluster_sg.id] } depends_on = [ aws_iam_role_policy_attachment.eks_cluster_policy ] tags = local.tags } # -------------------------------------------------- # EKS Managed Node Group (최소 비용) # -------------------------------------------------- resource "aws_eks_node_group" "main" { cluster_name = aws_eks_cluster.main.name node_group_name = "${var.name}-nodegroup" node_role_arn = aws_iam_role.eks_node_role.arn subnet_ids = [aws_subnet.public_a.id, aws_subnet.public_b.id] ami_type = "AL2023_x86_64_STANDARD" capacity_type = "ON_DEMAND" instance_types = ["t3.micro"] scaling_config { desired_size = 1 min_size = 1 max_size = 1 } update_config { max_unavailable = 1 } depends_on = [ aws_iam_role_policy_attachment.node_amazon_eks_worker, aws_iam_role_policy_attachment.node_amazon_eks_cni, aws_iam_role_policy_attachment.node_ecr_readonly ] tags = local.tags } # -------------------------------------------------- # Outputs # -------------------------------------------------- output "vpc_id" { value = aws_vpc.main.id } output "eks_cluster_name" { value = aws_eks_cluster.main.name } output "eks_cluster_endpoint" { value = aws_eks_cluster.main.endpoint } output "public_subnet_ids" { value = [ aws_subnet.public_a.id, aws_subnet.public_b.id ] } output "db_subnet_ids" { value = [ aws_subnet.db_a.id, aws_subnet.db_b.id ] } EOF terraform init terraform apply -auto-approve 2 aws eks update-kubeconfig \ --region ap-northeast-2 \ --name ha-compact-eks 4 kubectl get nodes