Table of contents
- 콘솔을 클릭하다가 지치는 순간
- Infrastructure as Code란
- Terraform의 자리
- 선언형 vs 명령형
- Terraform이 동작하는 방식
- Terraform vs 다른 도구들
- Terraform이 풀지 않는 문제
- 첫걸음을 시작하기 전에
콘솔을 클릭하다가 지치는 순간
AWS 콘솔에 로그인해서 EC2 인스턴스를 만들어본 적이 있을 것이다. 리전을 고르고, AMI를 고르고, 인스턴스 타입을 고르고, 보안 그룹을 만들고, 키 페어를 붙이고, 드디어 “Launch”를 누른다. 첫 번째 인스턴스는 신기해서 재미있다.
문제는 같은 환경을 한 번 더 만들 때부터 시작된다. 개발용으로 하나, 스테이징용으로 또 하나, 운영용으로 또 하나. 세 환경이 비슷하지만 미묘하게 다르다. 어느 보안 그룹에 22번 포트를 열었더라? 스테이징의 인스턴스 타입은 뭐였더라? 콘솔에서 클릭한 흔적은 어디에도 남지 않는다. 구글 독스에 적어둔 설정 메모는 3주만 지나도 현실과 어긋난다.
이 상황에서 누군가 “저 환경 그대로 다른 리전에 복제해줘”라고 하면 하루가 증발한다. 클릭해서 만든 인프라는 재현 가능성이 없기 때문이다. Terraform이 푸는 문제는 여기서 시작된다.
Infrastructure as Code란
Infrastructure as Code(IaC)는 이름 그대로다. 인프라를 코드로 정의한다. 서버, 네트워크, 스토리지, 데이터베이스 같은 클라우드 리소스를 텍스트 파일로 기술하고, 그 파일을 실행하면 실제 클라우드에 인프라가 만들어진다.
# EC2 인스턴스 한 대를 선언한다
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = "web-server"
}
}
이 파일이 인프라의 설계도다. terraform apply를 실행하면 Terraform이 AWS API를 호출해서 실제 인스턴스를 만들어준다. 같은 파일을 다른 계정에서 실행하면 똑같은 인스턴스가 생긴다.
코드로 관리한다는 건 개발자에게 익숙한 도구를 인프라에도 쓸 수 있다는 뜻이다.
- Git으로 버전 관리한다. 누가 언제 뭘 바꿨는지 커밋 로그에 다 남는다
- PR로 리뷰한다. “VPC에 새 서브넷 추가”가 “main 브랜치에 머지된 PR”이 된다
- CI로 검증한다.
terraform plan을 돌려서 변경점을 자동 확인한다 - 롤백이 명확하다. 원하는 커밋으로 돌아간 뒤 apply 하면 된다
콘솔 클릭으로는 이 중 어느 것도 자연스럽게 되지 않는다. IaC는 “인프라 운영을 소프트웨어 개발처럼 다루자”는 선언이다.
Terraform의 자리
Terraform은 IaC 도구 중에서 가장 널리 쓰이는 편이다. HashiCorp가 2014년에 오픈소스로 공개했고, 현재는 사실상 멀티 클라우드 IaC의 표준 자리를 차지하고 있다.
Terraform의 성격을 한 줄로 정리하면 이렇다. 여러 클라우드 프로바이더를 단일 언어(HCL)로, 선언형으로 관리하는 도구.
세 단어가 핵심이다.
- 여러 클라우드: AWS, Azure, GCP, Kubernetes, Cloudflare, Datadog, GitHub까지. “API가 있는 것”이면 대부분 Terraform으로 관리할 수 있다
- 단일 언어(HCL): HashiCorp Configuration Language. YAML보다 표현력이 있고, JSON보다 읽기 좋다
- 선언형: “어떻게 만들지”가 아니라 “어떤 상태여야 하는지”만 쓴다
마지막 선언형이 Terraform의 철학을 가장 잘 드러낸다. 다음 절에서 이 개념을 파고들어본다.
선언형 vs 명령형
IaC 도구를 비교할 때 빠지지 않고 등장하는 구분이 선언형(declarative)과 명령형(imperative)이다. Terraform은 선언형 진영이다.
명령형은 “이걸 해라, 그다음에 저걸 해라”라고 단계를 나열한다. Bash 스크립트가 전형적이다.
# 명령형 — 단계를 하나씩 지시한다
aws ec2 create-security-group --group-name web-sg --description "web"
aws ec2 authorize-security-group-ingress --group-name web-sg --protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 run-instances --image-id ami-xxx --count 1 --instance-type t3.micro \
--security-groups web-sg
문제는 이 스크립트를 두 번 실행하면 보안 그룹이 이미 있다는 에러가 난다는 점이다. “이미 만든 건 건너뛰고, 없는 것만 만든다”는 로직을 스크립트에 직접 써야 한다. 환경이 복잡해질수록 if-else의 지옥이 된다.
선언형은 다르다. “이런 상태가 되어야 한다”라고만 쓴다.
# 선언형 — 바라는 상태만 쓴다
resource "aws_security_group" "web" {
name = "web-sg"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web" {
ami = "ami-xxx"
instance_type = "t3.micro"
vpc_security_group_ids = [aws_security_group.web.id]
}
이 파일을 몇 번을 적용하든 결과는 같다. 이미 있으면 건드리지 않고, 없으면 만들고, 속성이 달라졌으면 고친다. 이 성질을 멱등성(idempotency)이라고 부른다. Terraform은 실제 상태와 선언한 상태의 차이를 계산해서 필요한 API 호출만 한다.
선언형의 이점을 흐름으로 그려보면 이렇다.
flowchart LR
DEV[개발자가 .tf 파일 작성] --> PLAN[terraform plan]
PLAN -->|차이 계산| DIFF{현재 상태 vs<br/>바라는 상태}
DIFF -->|추가 필요| CREATE[리소스 생성]
DIFF -->|수정 필요| UPDATE[리소스 수정]
DIFF -->|삭제 필요| DELETE[리소스 삭제]
DIFF -->|차이 없음| NOOP[아무것도 안 함]
개발자는 “이런 상태여야 한다”를 쓰고, Terraform이 “그 상태로 만들기 위한 행동”을 찾아낸다. 이게 Kubernetes의 선언형 철학과 맞닿아 있기도 하다.
Terraform이 동작하는 방식
선언형이라는 말이 어떻게 실제로 구현되는지 궁금해질 법하다. Terraform은 크게 세 가지를 조합해서 일한다.
- Configuration(.tf 파일): 사용자가 작성한 바라는 상태
- State(terraform.tfstate): Terraform이 “내가 만든 것들”을 기록해두는 JSON 파일
- Provider: AWS, GCP 같은 실제 API를 호출하는 플러그인
terraform plan은 이 셋을 비교한다. State에 기록된 것들과 Configuration을 견주어서 “뭐가 새로 생겼고, 뭐가 바뀌었고, 뭐가 사라졌는지” 보여준다. terraform apply는 그 차이를 실제로 적용한다.
flowchart TB
USER[사용자]
TF[Terraform Core]
CFG[.tf 파일<br/>바라는 상태]
STATE[(terraform.tfstate<br/>기록된 상태)]
PROV[Provider<br/>AWS/GCP/Azure...]
CLOUD[(실제 클라우드)]
USER -->|작성| CFG
USER -->|terraform apply| TF
CFG --> TF
STATE <--> TF
TF <-->|API 호출| PROV
PROV <--> CLOUD
여기서 특히 중요한 개념이 State다. Terraform은 “이 리소스는 내가 만든 거다”를 기억해야 어떤 리소스를 수정하고 어떤 리소스를 삭제할지 안다. State는 이후 편에서 깊게 다룬다. 지금은 “Terraform이 과거를 기억하는 파일이 있다”는 것만 기억해두면 충분하다.
Terraform vs 다른 도구들
Terraform만이 IaC 도구는 아니다. 비슷해 보이는 도구들이 여럿 있는데, 각각 초점이 다르다. 실무에서 Terraform을 고를 때 이 차이를 아는 게 중요하다.
vs Ansible
Ansible은 가장 자주 비교되는 도구다. 둘 다 YAML/HCL로 환경을 기술하지만 영역이 다르다.
- Ansible: 서버 안을 설정한다. 패키지 설치, 파일 복사, 서비스 재시작 같은 일
- Terraform: 서버 자체와 주변 인프라를 만든다. VPC, 로드밸런서, RDS 같은 일
둘은 경쟁이 아니라 역할 분담에 가깝다. Terraform으로 EC2를 만들고, 그 안에 Ansible로 nginx를 설치하는 식의 조합이 전형적이다. Ansible은 기본적으로 명령형에 가깝고(Playbook의 task가 순서대로 실행됨), Terraform은 완전히 선언형이다.
vs AWS CloudFormation
CloudFormation은 AWS가 직접 만든 IaC 서비스다. JSON/YAML로 AWS 리소스를 기술한다.
- CloudFormation: AWS 전용. AWS가 새 기능을 내면 CloudFormation도 같이 업데이트된다
- Terraform: 멀티 클라우드. AWS 외에도 GCP, Azure, Cloudflare 등 수많은 프로바이더 지원
AWS만 쓰는 조직이라면 CloudFormation도 합리적인 선택이다. 하지만 멀티 클라우드이거나, AWS 외 SaaS(Datadog, Cloudflare, GitHub)도 같이 관리해야 한다면 Terraform이 훨씬 깔끔하다.
State 관리도 다르다. CloudFormation은 AWS가 상태를 관리해주기 때문에 신경 쓸 게 적지만, Terraform은 State 파일을 직접 관리해야 한다. 대신 Terraform은 어떤 클라우드에도 동일한 방식으로 쓰인다.
vs Pulumi
Pulumi는 상대적으로 새로운 도구다. 프로그래밍 언어(TypeScript, Python, Go 등)로 인프라를 기술한다.
- Pulumi: 범용 언어로 작성. 반복문, 함수, 클래스 같은 추상화가 자유롭다
- Terraform: DSL(HCL)로 작성. 제약이 많지만 그만큼 일관된다
프로그래밍 언어의 표현력이 필요한 복잡한 시나리오(예: 매니페스트 생성 로직이 복잡한 경우)에선 Pulumi가 유리하다. 반면 팀원 다수가 비슷한 수준으로 이해하고 유지보수해야 한다면, “선언형 DSL”이라는 제약이 있는 Terraform이 러닝 커브가 낮다. Terraform도 loop, for 같은 표현식을 지원하긴 하지만, 프로그램 전체의 흐름 제어는 불가능하다.
비교 요약
flowchart TB
subgraph IMP[명령형 / 절차적]
ANS[Ansible<br/>서버 구성 관리]
end
subgraph DEC[선언형]
TF[Terraform<br/>멀티 클라우드]
CF[CloudFormation<br/>AWS 전용]
PU[Pulumi<br/>범용 언어 기반]
end
subgraph SCOPE[영역]
INFRA[인프라 프로비저닝]
CFG[서버 내부 설정]
end
TF -.-> INFRA
CF -.-> INFRA
PU -.-> INFRA
ANS -.-> CFG
실무에서 Terraform을 고르는 이유를 정리하면 이렇다.
- 여러 클라우드/SaaS를 하나의 도구로 관리하고 싶다
- 선언형의 안정성과 멱등성이 필요하다
- 커뮤니티와 프로바이더 생태계가 가장 크다
- 공식 모듈(Terraform Registry)이 풍부하다
Terraform이 풀지 않는 문제
도구의 가치를 제대로 이해하려면 경계도 알아야 한다. Terraform은 만능이 아니다.
- 서버 내부 설정 관리에는 약하다. 그래서 Ansible/Chef/Puppet과 조합한다
- 런타임 배포에는 적합하지 않다. 롤링 업데이트나 카나리 배포는 Kubernetes/ArgoCD가 낫다
- 실시간 감시/자동 복구는 안 한다. 한 번 apply 한 뒤 상태가 드리프트(drift)되면 다음 apply까지 그대로다
- 애플리케이션 코드는 그냥 가만히 둔다. 이건 처음부터 목적이 아니다
Terraform의 자리는 명확하다. 클라우드 리소스의 라이프사이클(생성, 변경, 삭제)을 선언적으로 관리하는 도구. 이 역할에 집중하는 덕에 다른 도구와 조합해서 쓰기도 편하다.
첫걸음을 시작하기 전에
여기까지 읽었다면 Terraform이 “왜” 필요한지는 감이 왔을 것이다. 다음은 “어떻게” 다. 다음 편에서는 실제로 Terraform을 설치하고, AWS 프로파일을 설정하고, 첫 EC2 인스턴스를 코드로 띄워본다. terraform init, plan, apply, destroy 네 가지 명령의 의미도 직접 체험하면서 익힌다.
선언형의 철학은 실습으로 체득할 때 가장 빨리 와닿는다. 콘솔을 클릭하던 경험과 어떻게 다른지 몸으로 느껴보자.




Loading comments...