Skip to content
ioob.dev
Go back

Terraform 1편 — Terraform이란

· 10분 읽기
Terraform 시리즈 (1/15)
  1. Terraform 1편 — Terraform이란
  2. Terraform 2편 — 설치와 첫 배포
  3. Terraform 3편 — HCL 문법
  4. Terraform 4편 — 변수와 출력
  5. Terraform 5편 — 프로바이더
  6. Terraform 6편 — 리소스와 의존성
  7. Terraform 7편 — 데이터 소스와 Import
  8. Terraform 8편 — State 관리
  9. Terraform 9편 — 모듈
  10. Terraform 10편 — 반복과 조건
  11. Terraform 11편 — 워크스페이스와 환경 분리
  12. Terraform 12편 — Kubernetes와 Helm 프로바이더
  13. Terraform 13편 — CI/CD 통합
  14. Terraform 14편 — 테스트와 정책
  15. Terraform 15편 — 실전 패턴과 함정
Table of contents

Table of contents

콘솔을 클릭하다가 지치는 순간

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를 호출해서 실제 인스턴스를 만들어준다. 같은 파일을 다른 계정에서 실행하면 똑같은 인스턴스가 생긴다.

코드로 관리한다는 건 개발자에게 익숙한 도구를 인프라에도 쓸 수 있다는 뜻이다.

콘솔 클릭으로는 이 중 어느 것도 자연스럽게 되지 않는다. IaC는 “인프라 운영을 소프트웨어 개발처럼 다루자”는 선언이다.

Terraform의 자리

Terraform은 IaC 도구 중에서 가장 널리 쓰이는 편이다. HashiCorp가 2014년에 오픈소스로 공개했고, 현재는 사실상 멀티 클라우드 IaC의 표준 자리를 차지하고 있다.

Terraform의 성격을 한 줄로 정리하면 이렇다. 여러 클라우드 프로바이더를 단일 언어(HCL)로, 선언형으로 관리하는 도구.

세 단어가 핵심이다.

마지막 선언형이 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은 크게 세 가지를 조합해서 일한다.

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로 환경을 기술하지만 영역이 다르다.

둘은 경쟁이 아니라 역할 분담에 가깝다. Terraform으로 EC2를 만들고, 그 안에 Ansible로 nginx를 설치하는 식의 조합이 전형적이다. Ansible은 기본적으로 명령형에 가깝고(Playbook의 task가 순서대로 실행됨), Terraform은 완전히 선언형이다.

vs AWS CloudFormation

CloudFormation은 AWS가 직접 만든 IaC 서비스다. JSON/YAML로 AWS 리소스를 기술한다.

AWS만 쓰는 조직이라면 CloudFormation도 합리적인 선택이다. 하지만 멀티 클라우드이거나, AWS 외 SaaS(Datadog, Cloudflare, GitHub)도 같이 관리해야 한다면 Terraform이 훨씬 깔끔하다.

State 관리도 다르다. CloudFormation은 AWS가 상태를 관리해주기 때문에 신경 쓸 게 적지만, Terraform은 State 파일을 직접 관리해야 한다. 대신 Terraform은 어떤 클라우드에도 동일한 방식으로 쓰인다.

vs Pulumi

Pulumi는 상대적으로 새로운 도구다. 프로그래밍 언어(TypeScript, Python, Go 등)로 인프라를 기술한다.

프로그래밍 언어의 표현력이 필요한 복잡한 시나리오(예: 매니페스트 생성 로직이 복잡한 경우)에선 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을 고르는 이유를 정리하면 이렇다.

Terraform이 풀지 않는 문제

도구의 가치를 제대로 이해하려면 경계도 알아야 한다. Terraform은 만능이 아니다.

Terraform의 자리는 명확하다. 클라우드 리소스의 라이프사이클(생성, 변경, 삭제)을 선언적으로 관리하는 도구. 이 역할에 집중하는 덕에 다른 도구와 조합해서 쓰기도 편하다.

첫걸음을 시작하기 전에

여기까지 읽었다면 Terraform이 “왜” 필요한지는 감이 왔을 것이다. 다음은 “어떻게” 다. 다음 편에서는 실제로 Terraform을 설치하고, AWS 프로파일을 설정하고, 첫 EC2 인스턴스를 코드로 띄워본다. terraform init, plan, apply, destroy 네 가지 명령의 의미도 직접 체험하면서 익힌다.

선언형의 철학은 실습으로 체득할 때 가장 빨리 와닿는다. 콘솔을 클릭하던 경험과 어떻게 다른지 몸으로 느껴보자.


2편: 설치와 첫 배포


Related Posts

Share this post on:

Comments

Loading comments...


Previous Post
Kubernetes 입문 12편 — Helm과 패키지 관리
Next Post
Terraform 2편 — 설치와 첫 배포