현회사에서는 거의 대부분의 서비스를 테라폼으로 관리 생성한다. 이번에 컨슈머를 개발해 ECS로 배포해야 하는 상황이 왔는데, 테라폼을 써본적이 없어서 공부할겸 정리해본다.
Terraform 이란
•
인프라를 코드로 관리하는 도구(IaC: Infrastructure as Code)
•
클라우드나 온프레미스 환경에서 인프라를 생성/변경/삭제 가능
•
.tf 파일에 원하는 상태를 작성하면, Terraform이 현재 상태와 비교해 필요한 변경을 수행
왜 사용할까?
서버 하나 배포하려면 매번-
1.
EC2 생성
2.
보안 그룹 설정
3.
로드밸런서 + Target Group 연결
4.
Route53에서 레코드 생성
5.
IAM 권한 설정
6.
CodeDeploy/Autoscaling 구성
→ dev, stage, prod 별로 매번 반복
위 수동 과정을 자동화
장점
•
환경별 코드 재사용 (변수만 바꿔 배포 가능)
•
Git으로 변경 이력 관리 가능
•
코드 리뷰 가능
기본 명령어
•
init - 테라폼 작업을 위해 모듈/플러그인 설치 등 초기화
•
plan - 리소스 변경 정보 미리 확인
•
apply - 실제 리소스 반영
•
destroy - 리소스 제거
AWS 인프라 정보를 가져와야 하기 때문에 AWS 리소스에 접근 권한을 가진 유저 Profile 필요
주요 블록
사용할 수 있는 항목은 매우 많기 때문에 주요 항목과 예시만 간단히 정리 나머지는 공식문서 참조 -
Terraform Registry
terraform { ... }
•
프로젝트 메타데이터
◦
required_providers(플러그인 버전 고정)
◦
backend(상태 저장소) 등 프로젝트 메타 설정
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "tf-state-bucket"
key = "ecs/app/terraform.tfstate"
region = "ap-northeast-2"
}
}
HCL
복사
•
provider "aws" { ... }
◦
AWS 리전/자격 등 프로바이더 설정
provider "aws" {
region = "ap-northeast-2"
profile = "my-aws-profile"
}
HCL
복사
•
variable "..." { ... }
◦
외부에서 주입할 값 정의
◦
변수의 타입, 기본값, 설명 등 명시
variable "app_name" {
description = "애플리케이션 이름"
type = string
}
Bash
복사
•
locals { ... }
◦
여러 변수/값을 조합하거나 변환해 중간 계산 결과를 저장
◦
외부 주입 변수나 내부 로직을 합쳐 재활용 가능한 값을 만드는 용도
variable "app_name" {
description = "앱 기본 이름"
}
locals {
env = terraform.workspace
app_name = "${var.app_name}-${terraform.workspace}"
ecs_service_name = "${local.app_name}-service"
}
resource "aws_ecs_service" "this" {
name = local.ecs_service_name
}
Bash
복사
◦
.tfvars에서 app_name = "worker" 주입
◦
local.app_name = "worker-dev" (env가 dev 일때)
◦
local.ecs_service_name = "worker-dev-service"
•
data "..." "..." { ... }
◦
이미 존재하는 외부 리소스(또는 다른 Terraform state)에 접근해 정보 조회
data "aws_iam_role" "task_role" {
name = var.ecs_task_role
}
HCL
복사
◦
여기서 var.ecs_task_role은 .tfvars나 CLI로 주입된 값
◦
AWS에 이미 존재하는 IAM Role을 찾아서 ARN 등 속성값을 가져올 수 있음.
•
resource "..." "..." { ... }
◦
실제 리소스 생성/변경/삭제
◦
예시 (ECS Task Definition):
resource "aws_ecs_task_definition" "task_definition" {
family = var.ecs_service_name
container_definitions = file("container_definitions.json")
cpu = var.cpu
memory = var.memory
requires_compatibilities = ["EC2"]
network_mode = "awsvpc"
}
HCL
복사
◦
family: 태스크 정의 그룹 이름
◦
network_mode: 네트워크 모드 (awsvpc = ENI 직접 부여)
◦
requires_compatibilities: Fargate / EC2 모드 지정
◦
container_definitions: 실제 컨테이너 실행 스펙(JSON 파일로)
•
module "..." { ... }
◦
재사용 가능한 테라폼 코드 조각 가져와 실행
module "<모듈_이름>" {
source = "<모듈_위치>"
# 모듈이 요구하는 변수들
var_name_1 = "값"
var_name_2 = local.가공값
}
Bash
복사
◦
source
▪
모듈 코드의 위치를 지정
▪
로컬 경로(../modules/ecs_module), Git repo, Terraform Registry URL 모두 가능
◦
변수 전달
▪
모듈 내부의 variable 정의에 값을 주입
▪
var., local., data. 등 현재 프로젝트의 값을 전달할 수 있음
◦
출력값 사용
▪
모듈 내부에서 output "..."로 정의한 값은 module.<모듈_이름>.<output_이름> 으로 참조 가능
◦
다른 서비스에서 동일한 ECS 설정 재활용 가능
디렉토리 & 파일구조 (예시)
ECS의 경우 공통 리소스(infra/)와 애플리케이션 리소스(app/)를 분리하여 관리
<서비스명>/
├─ infra/
│ ├─ backend.tf # state 저장소(S3) & 락 설정
│ ├─ terraform.tf # required_providers, 버전 등
│ ├─ variables.tf
│ ├─ terraform.tfvars
│ └─ main.tf # 인프라 모듈 호출(출력: ECR URL, 시크릿 맵 등)
└─ app/
├─ backend.tf
├─ terraform.tf
├─ variables.tf # env별로 달라지는 값(리소스 스펙, 네트워크 등)
├─ env-dev.tfvars
├─ env-prod.tfvars
└─ main.tf # 원격 state(ECR/시크릿) + ECS 모듈 호출
Plain Text
복사
인프라(infra) 모듈
•
공통 리소스 생성:
◦
ECR: 이미지 저장소
◦
Secrets Manager: 환경별 시크릿 관리
◦
IAM User/Role: 배포 계정 권한
•
output으로 ECR URL, 환경별 시크릿 이름 맵 등을 노출 → 나중에 app/에서 원격 state(data "terraform_remote_state") 로 이 값을 받아 사용가능
앱(app) 모듈
•
ECS Task Definition: 컨테이너 이미지, 포트, 환경변수, 시크릿
•
ECS Service: 롤링 업데이트, 로드밸런서 연결, 오토스케일링
•
환경별 차이는 env-*.tfvars로 CPU/메모리/서브넷/이미지 태그 구분
.tvars 파일
•
Terraform 변수(variable "...")에 실제 값을 주입하는 파일
•
환경별(dev, prod 등)로 다른 값이 필요할 때 주로 사용
•
예시:
# env-dev.tfvars
app_name = "worker"
ecs_task_role = "ecsTaskRoleDev"
cpu = 256
memory = 512
desired_task_number = 1
Bash
복사
◦
위와 같은 파일이 있을때 아래와 같이 적용하면 dev 환경변수 값으로 실행
terraform apply -var-file=env-dev.tfvars
Bash
복사
Terraform 실행 흐름 요약
•
변수 주입 – .tfvars 파일에서 환경별 변수 값 로드
•
값 가공 – locals 블록에서 변수 조합·변환으로 재사용 가능한 형태로 준비
•
외부 정보 조회 – data 블록으로 기존 리소스나 원격 state에서 참조값 확보
•
리소스 생성·변경 – resource 블록으로 신규 인프라 생성 및 상태 반영