상세 컨텐츠

본문 제목

Terraform으로 EC2에 백엔드 서버 배포 (with ECR) 5장 main.tf

DevOps/Terraform

by rakyun 2025. 9. 1. 20:48

본문

 

Terraform 모듈들을 조립하는 총괄 설계도
terraform.tfvars에 모든 변수들의 값을 저장해두고 각기 모듈들에서 필요한 변수들을 넣어주는 역할을 main.tf에서 한다.

 

# 프로덕션 환경을 위한 메인 Terraform 설정 파일
# 이 파일은 모든 모듈을 조합하여 전체 인프라를 구성합니다

terraform {
  # Terraform 버전 요구사항 - 1.0 이상 필요
  required_version = ">= 1.0"
  
  # 필요한 Provider 정의
  required_providers {
    aws = {
      source  = "hashicorp/aws"  # AWS Provider 소스
      version = "~> 5.0"          # 5.x 버전 사용 (5.0 이상, 6.0 미만)
    }
    tls = {
      source  = "hashicorp/tls"  # TLS Provider - 키 페어 생성용
      version = "~> 4.0"
    }
    local = {
      source  = "hashicorp/local" # Local Provider - 파일 저장용
      version = "~> 2.0"
    }
  }

  # Terraform State 원격 저장소 설정 (현재는 로컬 테스트용으로 주석 처리)
  # 프로덕션에서는 S3에 state 파일을 저장하는 것을 권장
  # 주석 해제하려면:
  # 1. S3 버킷을 먼저 생성
  # 2. bucket 이름을 고유한 값으로 변경
  # 3. terraform init -backend-config 명령 실행
  # backend "s3" {
  #   bucket = "project-terraform-state-YOUR-UNIQUE-ID"  # S3 버킷 이름 (전역적으로 고유해야 함)
  #   key    = "prod/terraform.tfstate"                  # State 파일 경로
  #   region = "ap-northeast-2"                          # 서울 리전
  #   encrypt = true                                     # State 파일 암호화
  # }
}

 

  • 테라폼 기본 설정 
    • Provider 정의: 이 코드가 어떤 클라우드 서비스와 상호작용할지 정의한다.  여기서는 aws, tls(키 페어 생성용), local(로컬 파일 저장용)이라는 세 가지 도구(Provider)를 사용하겠다고 선언했다.
      • 테라폼은 required_providers 블록을 읽고 명시된 프로바이더들을 자동으로 다운로드하여 설치한다.
    • 주석 처리 되어 있는 S3 버킷은 테라폼의 상태를 저장하는 공간으로 활용된다. 테라폼은 코드로 인프라를 정의하는데, 코드를 변경하면 인프라의 구조 또한 바뀐다. 그래서 현재 인프라의 상태를 State에 표현하게 되는데 그 State를 S3에 저장하여 로컬 환경과 프로덕션 환경을 비교하기 위한 목적으로 S3 버킷을 생성한다.
      (그러나 나는 혼자 테스트 하는 것이므로 주석처리)

# AWS Provider 설정
provider "aws" {
  profile = "default"       # AWS CLI profile 설정
  region  = var.aws_region # 사용할 AWS 리전 (ap-northeast-2 = 서울)

  # 모든 리소스에 자동으로 추가될 기본 태그
  default_tags {
    tags = {
      Environment = var.environment    # 환경 구분 (dev/prod)
      Project     = var.project_name   # 프로젝트 이름
      ManagedBy   = "Terraform"       # Terraform으로 관리됨을 표시
    }
  }
}

# ===== Data Sources: 기존 AWS 리소스 조회 =====

# 기본 VPC 조회 (AWS 계정에 자동으로 생성된 기본 VPC)
data "aws_vpc" "default" {
  default = true  # 기본 VPC를 사용 (별도 VPC 생성하지 않음)
}

# 기본 VPC의 모든 서브넷 조회
data "aws_subnets" "default" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]  # 위에서 조회한 기본 VPC의 ID 사용
  }
}

# t2.micro를 지원하는 가용 영역의 서브넷 필터링
data "aws_subnets" "available" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]
  }
  
  filter {
    name   = "availability-zone"
    values = ["ap-northeast-2a", "ap-northeast-2c"]  # t2.micro 지원 가용 영역
  }
}

# 첫 번째 사용 가능한 서브넷 선택 (EC2를 배치할 서브넷)
data "aws_subnet" "selected" {
  id = data.aws_subnets.available.ids[0]  # 사용 가능한 서브넷 중 첫 번째 선택
}

# 현재 AWS 계정 ID 조회 (ECR 권한 설정에 필요)
data "aws_caller_identity" "current" {}

 

  • data "aws_vpc" "default": AWS 계정을 처음 만들면 기본적으로 제공되는 가상 네트워크(VPC)의 정보를 찾아온다.
    default = true는 기존에 있는 VPC를 가져오라는 의미

  • data "aws_subnets" "default": 위에서 찾은 기본 VPC 안에 존재하는 모든 서브넷(VPC를 잘게 나눈 하위 네트워크)의 목록을 가져옴

  • data "aws_subnets" "available": 가져온 서브넷 목록 중에서 t2.micro 인스턴스 타입을 지원하는
    특정 가용 영역(ap-northeast-2a, ap-northeast-2c)에 속한 서브넷만 다시 한번 필터링 한다. 

  • data "aws_subnet" "selected": 필터링된 서브넷 목록 중, 첫 번째 서브넷(ids[0])을 최종적으로 선택한다. EC2 인스턴스는 이 서브넷에 배치됨

  • data "aws_caller_identity" "current": 현재 이 테라폼 코드를 실행하는 AWS 계정의 고유 ID(Account ID)를 조회함. 이 정보는 나중에 ECR(컨테이너 저장소)의 권한을 설정하는 등 다른 리소스에서 참조하기 위해 필요

 

# ===== 모듈 호출: 각 모듈을 조합하여 인프라 구성 =====

# 보안 그룹 모듈 - EC2 인스턴스의 방화벽 규칙 설정
module "security_group" {
  source = "../../modules/security_group"  # 모듈 경로

  # 모듈에 전달할 변수들
  project_name    = var.project_name       # 프로젝트 이름
  environment     = var.environment        # 환경 (prod)
  vpc_id          = data.aws_vpc.default.id # VPC ID
  ssh_allowed_ips = var.ssh_allowed_ips    # SSH 접속 허용 IP 목록
}

# IAM 역할 모듈 - EC2가 ECR과 CloudWatch에 접근할 수 있는 권한 설정
module "iam" {
  source = "../../modules/iam"

  project_name = var.project_name  # 프로젝트 이름
  environment  = var.environment   # 환경
  enable_ssm   = var.enable_ssm    # Systems Manager 활성화 여부
}

# ECR 모듈 - Docker 이미지를 저장할 컨테이너 레지스트리
module "ecr" {
  source = "../../modules/ecr"

  project_name        = var.project_name                              # 프로젝트 이름
  environment         = var.environment                               # 환경
  image_count_limit   = var.ecr_image_count_limit                    # 보관할 이미지 개수
  allowed_account_ids = [data.aws_caller_identity.current.account_id] # 접근 허용 계정
}

# EC2 모듈 - 실제 애플리케이션이 실행될 서버
module "ec2" {
  source = "../../modules/ec2"

  # AWS 설정
  aws_region        = var.aws_region                           # AWS 리전
  instance_type         = var.instance_type                     # 인스턴스 타입 (t2.micro 등)
  security_group_id     = module.security_group.security_group_id # 보안 그룹 ID
  instance_profile_name = module.iam.instance_profile_name      # IAM 인스턴스 프로파일
  subnet_id            = data.aws_subnet.selected.id            # 서브넷 ID
  volume_size          = var.volume_size                        # EBS 볼륨 크기
  use_elastic_ip       = var.use_elastic_ip                     # Elastic IP 사용 여부

  # 애플리케이션 관련 설정
  project_name        = var.project_name                          # 프로젝트 이름
  environment         = var.environment                           # 환경
  domain_name         = var.domain_name                           # 도메인 이름
  ecr_registry        = split("/", module.ecr.repository_url)[0]  # ECR 레지스트리 URL
  ecr_repository_name = module.ecr.repository_name                # ECR 리포지토리 이름
}
  • 앞서 만들었던 각 모듈들을 여기서 조립해서 사용한다.
  • var에 정의된 값들을 가져와서 각 모듈들에 넣어줌으로써 각 모듈들이 실제로 aws에 생성된다.

관련글 더보기