테라폼
고친 사람 github-actions[bot]
테라폼은 클라우드의 서버와 네트워크를 코드로 만들고 고치는 도구입니다. 개발자가 원하는 인프라의 모습을 설정 파일에 적어 두면 테라폼이 지금 모습과 견줍니다. 없는 것은 만들고 달라진 것은 고치고 파일에서 빠진 것은 지웁니다. 인프라가 파일로 남으니 코드처럼 리뷰하고 이력을 되짚을 수 있습니다.
쉽고 빠른 이해
무슨 일을 하나 — 클라우드 관리 화면에서 손으로 누르던 일을 설정 파일로 옮깁니다. 예를 들어 「파일 저장소 하나, 네트워크 하나」를 파일에 적고 명령 한 번으로 만듭니다.
왜 쓰나 — 손으로 만든 인프라는 누가 무엇을 바꿨는지 남지 않습니다. 개발용과 운영용 환경이 조금씩 달라져도 알아채기 어렵습니다. 같은 구성을 하나 더 만들려면 처음부터 다시 눌러야 합니다.
어떻게 도나
- 있어야 할 자원을 설정 파일에 적습니다
- 계획 명령이 무엇을 만들고 고치고 지울지 미리 보여 줍니다
- 적용 명령이 클라우드에 요청을 보내 계획대로 바꿉니다. 만든 결과는 상태 파일에 적어 둡니다
대가 — 상태 파일을 잃거나 두 사람이 동시에 적용하면 인프라가 꼬입니다. 관리 화면에서 손으로 고친 것은 다음 적용 때 파일 내용으로 되돌아갑니다. 한 번 쓰고 버릴 실험이나, 부하에 따라 서버 수가 저절로 늘고 주는 자원에는 맞지 않습니다.
상세
테라폼(Terraform)은 HashiCorp 가 만든 코드형 인프라 도구입니다. 코드형 인프라는 서버·네트워크·데이터베이스 같은 인프라를 손 대신 코드로 만들고 관리하는 방식입니다. 테라폼은 Go 로 짠 명령줄 프로그램 하나입니다. 내 컴퓨터나 배포 서버에서 돌립니다.
이 절은 파일 저장소 하나와 네트워크 하나를 만드는 작은 예를 따라갑니다. 그 과정에서 설정 파일, init·plan·apply 세 명령, 프로바이더, 상태 파일을 차례로 봅니다. 뒤쪽에서는 여럿이 함께 쓸 때 생기는 문제와 테라폼이 맡지 않는 일을 봅니다.
손으로 만드는 인프라
클라우드에서 서버를 하나 띄우는 일은 처음엔 관리 화면에서 몇 번 누르면 끝납니다. 서버가 수십 대로 늘고 네트워크와 방화벽 규칙이 얽히면 세 가지가 곤란해집니다.
첫째는 기록입니다. 누가 언제 어떤 규칙을 바꿨는지가 어디에도 남지 않습니다. 장애가 났을 때 무엇이 달라졌는지 찾으려면 사람의 기억에 기대야 합니다.
둘째는 환경 사이의 차이입니다. 개발용 환경에서 고친 설정을 운영용에 옮기다 하나를 빠뜨립니다. 그런 차이가 쌓이면 두 환경은 이름만 같고 속은 다른 것이 됩니다.
셋째는 다시 만들기입니다. 같은 구성을 다른 지역에 하나 더 세우려면 처음부터 다시 눌러야 합니다. 테라폼은 이 셋을 인프라를 파일로 적는 방법으로 풉니다.
원하는 모습을 적는 설정 파일
테라폼 설정은 .tf 확장자를 가진 글자 파일입니다.
문법은 HCL(HashiCorp Configuration Language, 해시코프 설정 언어)입니다. 중괄호로 블록을 묶고 이름 = 값 으로 속성을 적는 단순한 언어입니다.
아래 블록은 AWS(Amazon Web Services)의 파일 저장 서비스인 Amazon S3(Simple Storage Service)에 저장소 하나를 만들라는 뜻입니다. S3 는 저장소 하나를 버킷이라고 부릅니다.
resource "aws_s3_bucket" "logs" {
bucket = "app-logs"
}
resource 는 「이런 자원이 있어야 한다」를 적는 블록입니다. 뒤따르는 두 문자열 가운데 aws_s3_bucket 은 자원의 종류입니다.
logs 는 이 파일 안에서 이 자원을 부를 이름입니다.
중괄호 안의 bucket = "app-logs" 는 클라우드에 만들어질 버킷의 이름입니다.
이 파일에는 「버킷을 만들어라」라는 명령이 없습니다. 「이런 버킷이 있어야 한다」는 결과만 있습니다. 이렇게 끝 모습만 적고 거기까지 가는 단계는 도구에 맡기는 방식을 선언적 설정이라고 부릅니다.
선언적으로 적으면 같은 파일을 여러 번 돌려도 결과가 같습니다. 버킷이 이미 있으면 테라폼은 아무것도 하지 않습니다. 몇 번을 해도 한 번 한 것과 같은 이 성질이 멱등성입니다.
init · plan · apply
테라폼은 설정 파일이 든 폴더에서 명령 셋을 차례로 부르며 씁니다.
| 명령 | 하는 일 |
|---|---|
terraform init |
클라우드와 통신하는 플러그인(프로바이더)을 내려받고 작업 폴더를 준비한다 |
terraform plan |
지금 인프라와 설정 파일을 견줘 무엇을 바꿀지 계획을 보여 준다 |
terraform apply |
계획을 한 번 더 보여 주고, 사람이 승인하면 그대로 실행한다 |
terraform destroy |
이 설정이 만든 자원을 전부 지운다 |
표의 마지막 destroy 는 이 흐름에 들지 않습니다. 설정이 만든 자원을 정리할 때만 따로 부릅니다.
핵심은 plan 과 apply 를 나눈 데 있습니다. 클라우드를 바꾸기 전에 무엇이 바뀔지를 사람이 먼저 읽습니다. 위 버킷 설정으로 plan 을 부르면 대략 이런 출력이 나옵니다.
+ resource "aws_s3_bucket" "logs" {
+ bucket = "app-logs"
}
Plan: 1 to add, 0 to change, 0 to destroy.
줄 앞의 + 는 새로 만든다는 표시입니다. 마지막 줄은 만들 것 하나, 고칠 것 0, 지울 것 0 을 셉니다.
plan 출력에 붙는 표시는 넷입니다.
| 표시 | 뜻 |
|---|---|
+ |
새로 만든다 |
~ |
있는 자원의 속성을 고친다 |
- |
지운다 |
-/+ |
지우고 새로 만든다 |
마지막 -/+ 는 뒤의 「지우고 새로 만드는 변경」 소절에서 다시 봅니다. 눈여겨볼 표시입니다.
프로바이더
테라폼 본체는 AWS 를 모릅니다. 버킷을 만드는 요청을 어떻게 보내는지도 모릅니다. 그 일은 프로바이더라는 플러그인이 맡습니다.
프로바이더는 테라폼의 자원 블록을 한 클라우드의 API(Application Programming Interface, 응용 프로그램 인터페이스) 호출로 바꿔 주는 프로그램입니다.
API 는 프로그램이 다른 서비스에 일을 시킬 때 쓰는 정해진 요청 형식입니다.
aws_s3_bucket 의 앞머리 aws 가 이 자원을 AWS 프로바이더가 맡는다는 표시입니다.
프로바이더는 클라우드마다, 서비스마다 따로 있습니다. AWS, Google Cloud, Azure 같은 클라우드뿐 아니라 Kubernetes, Cloudflare, GitHub 저장소 설정까지 API 가 있는 것이면 프로바이더가 붙습니다.
terraform init 이 설정 파일에 적힌 프로바이더를 찾아 내려받습니다.
그래서 테라폼의 문법과 명령은 어느 클라우드에서나 같습니다. 달라지는 것은 자원 종류의 이름과 그 속성뿐입니다.
상태 파일
설정 파일은 버킷을 logs 라고 부릅니다. 클라우드는 그 버킷을 자기가 붙인 식별자로 압니다.
테라폼은 둘을 짝지어 기억해야 합니다. 이 짝을 적어 두는 파일이 상태 파일입니다.
상태 파일은 기본으로 작업 폴더의 terraform.tfstate 입니다. 형식은 JSON(JavaScript Object Notation)입니다.
JSON 은 중괄호와 따옴표로 값을 적는 글자 형식입니다.
테라폼이 만든 자원마다 설정 파일의 이름, 클라우드의 식별자, 만들 때 받은 속성 값이 들어갑니다.
상태 파일이 없으면 테라폼은 logs 버킷을 이미 만들었다는 것을 모릅니다.
다음 apply 때 같은 버킷을 또 만들려 합니다. 그러면 이름이 겹쳐 실패하거나 똑같은 자원이 둘이 됩니다.
상태 파일에는 자원의 속성이 암호화 없이 들어갑니다. 데이터베이스를 만들며 넣은 비밀번호도 여기 남습니다. 그래서 상태 파일은 설정 파일과 달리 Git 저장소에 넣지 않고 따로 보관합니다. 보관 방법은 뒤의 「여럿이 함께 쓸 때」 소절에서 봅니다.
한 번의 실행
plan 을 부르면 테라폼은 상태 파일만 믿지 않습니다. 먼저 프로바이더를 시켜 상태 파일에 적힌 자원들의 지금 속성을 클라우드에서 읽어 옵니다. 읽어 온 값으로 상태를 새로 맞춘 뒤 설정 파일과 견줘 계획을 세웁니다.
sequenceDiagram
participant 개발자
participant 테라폼
participant 프로바이더
participant 클라우드
개발자->>테라폼: terraform plan
테라폼->>프로바이더: 상태 파일의 자원을 읽어 달라
프로바이더->>클라우드: 조회 요청
클라우드-->>프로바이더: 지금 속성 값
프로바이더-->>테라폼: 지금 속성 값
테라폼-->>개발자: 설정 파일과 견준 계획
개발자->>테라폼: terraform apply 와 승인
테라폼->>프로바이더: 만들기 · 고치기 · 지우기
프로바이더->>클라우드: 생성 · 변경 · 삭제 요청
클라우드-->>프로바이더: 결과와 새 식별자
프로바이더-->>테라폼: 결과와 새 식별자
테라폼->>테라폼: 상태 파일에 적는다
미리 읽어 오는 까닭은 누군가 관리 화면에서 자원을 손으로 고쳤을 수 있어서입니다. 코드와 실물이 이렇게 어긋난 상태가 드리프트입니다.
드리프트가 있으면 plan 은 그 자원을 ~ 로 보여 줍니다. 설정 파일에 적힌 값으로 되돌리겠다는 뜻입니다.
테라폼에게 정본은 언제나 설정 파일입니다. 손으로 고친 것을 남기려면 그 값을 설정 파일에도 적어야 합니다.
참조가 정하는 실행 순서
자원은 다른 자원의 값을 가져다 씁니다. 아래 두 블록은 네트워크 하나와 그 안의 작은 구역 하나를 만듭니다. VPC(Virtual Private Cloud, 가상 사설 클라우드)는 클라우드 안에 따로 떼어 낸 사설 네트워크입니다. 서브넷은 그 네트워크를 나눈 구역입니다.
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
}
cidr_block 은 그 네트워크가 쓸 주소 범위입니다. 눈여겨볼 줄은 서브넷의 vpc_id = aws_vpc.main.id 입니다.
「main 이라는 VPC 의 식별자를 여기 넣어라」는 뜻입니다. 그 식별자는 VPC 를 만들어야 생깁니다.
테라폼은 이런 참조를 모두 모아 어느 자원이 어느 자원을 기다려야 하는지 그래프로 만듭니다. 이 그래프는 DAG(Directed Acyclic Graph, 방향 비순환 그래프)입니다. 화살표가 한 방향으로만 이어지고 되돌아오는 고리가 없는 그래프입니다. 고리가 없으니 누가 누구를 먼저 기다리는지가 언제나 풀립니다.
flowchart TD
V["aws_vpc.main"] --> A["aws_subnet.a"]
L["aws_s3_bucket.logs"]
그림에서 서브넷은 VPC 가 생긴 뒤에 만들어집니다. 앞 소절의 버킷은 누구도 기다리지 않습니다. 서로 기다리지 않는 자원은 동시에 만듭니다. 위 그림이라면 VPC 와 버킷이 함께 만들어집니다. 지울 때는 이 순서를 거꾸로 따라갑니다. 서브넷을 먼저 지우고 VPC 를 나중에 지웁니다.
변수, 출력, 모듈
설정 파일에 값을 박아 두면 개발용과 운영용을 따로 쓰기 어렵습니다. 그래서 바뀌는 값은 변수로 뺍니다.
variable 블록이 변수를 선언합니다. 설정 안에서는 var.이름 으로 읽습니다.
반대로 만든 자원의 값을 밖에 알려 줄 때는 output 블록을 씁니다.
출력 값은 apply 가 끝날 때 화면에 찍힙니다. 다른 설정이 가져다 쓸 수도 있습니다.
오른쪽 주석이 apply 뒤에 찍히는 값입니다.
output "bucket_name" {
value = aws_s3_bucket.logs.id // app-logs
}
버킷 자원의 id 는 버킷 이름이라서 app-logs 가 나옵니다.
모듈은 .tf 파일을 묶은 폴더 하나입니다. 다른 설정이 이 폴더를 불러 쓰면서 변수에 값을 넘깁니다.
「VPC 하나와 서브넷 둘」을 모듈로 만들어 두면 개발용과 운영용이 같은 모듈을 부르고 주소 범위만 다르게 넘깁니다.
두 환경의 구성이 같은 코드에서 나오므로 앞에서 본 환경 사이의 차이가 줄어듭니다.
여럿이 함께 쓸 때
상태 파일이 한 사람의 노트북에만 있으면 다른 사람은 그 인프라를 고칠 수 없습니다. 각자 자기 상태 파일로 apply 하면 서로 모르는 자원을 만들거나 지웁니다.
그래서 팀에서는 상태 파일을 원격 저장소에 둡니다. 테라폼은 상태를 두는 곳을 백엔드라고 부릅니다. S3 버킷 같은 곳을 백엔드로 지정합니다. 모든 사람이 같은 상태 파일을 읽고 씁니다.
같은 파일을 두 사람이 동시에 고치면 한쪽이 덮어씁니다. 이를 막는 장치가 상태 잠금입니다. apply 를 시작한 쪽이 잠금을 쥡니다. 그동안 다른 쪽의 apply 는 기다리거나 실패합니다.
많은 팀은 사람이 직접 apply 하지 않고 CI/CD(Continuous Integration/Continuous Delivery, 지속적 통합·배포) 파이프라인에 맡깁니다. 설정을 바꾼 풀 리퀘스트에 plan 결과를 붙여 코드 리뷰를 받습니다. 병합되면 파이프라인이 apply 합니다.
지우고 새로 만드는 변경
어떤 속성은 이미 있는 자원에서 바꿀 수 없습니다. 클라우드 API 가 그 속성을 만들 때만 받기 때문입니다.
앞의 예에서 버킷 이름이 그렇습니다. app-logs 를 다른 이름으로 바꾸면 테라폼은 기존 버킷을 지우고 새 버킷을 만듭니다.
plan 은 이런 변경을 -/+ 로 표시합니다. 버킷이나 데이터베이스라면 안에 든 데이터가 함께 사라질 수 있습니다.
그래서 plan 을 읽을 때 가장 먼저 찾는 표시가 -/+ 와 - 입니다.
실수로 지워지면 안 되는 자원은 그 자원 블록 안에 lifecycle 블록을 넣습니다.
lifecycle 은 자원을 만들고 지우는 방식을 조정하는 블록입니다.
여기에 prevent_destroy = true 를 적으면 그 자원을 지우는 계획이 나오는 순간 테라폼이 오류를 내고 멈춥니다.
테라폼이 맡지 않는 일
테라폼은 서버를 만들지만 서버 안은 잘 다루지 않습니다. 패키지를 설치하고 설정 파일을 고치는 일은 설정 관리 도구의 몫입니다. 앤서블이 그런 도구입니다.
서버 안을 채우는 다른 길도 있습니다. 머신 이미지는 패키지와 설정을 미리 넣어 둔 서버의 원본입니다. 이 이미지는 Packer 같은 도구로 만들기도 합니다. 테라폼은 그 이미지로 서버를 띄웁니다.
클라우드 사이의 차이도 감추지 않습니다. AWS 용으로 쓴 설정은 자원 종류가 전부 aws_ 로 시작합니다.
같은 구성을 Google Cloud 에 세우려면 자원 블록을 새로 써야 합니다. 테라폼이 하나로 맞춘 것은 문법과 작업 흐름이지 자원이 아닙니다.
apply 가 중간에 실패해도 앞서 만든 자원을 되돌리지 않습니다. 성공한 것은 상태 파일에 남고 실패한 것만 빠집니다. 원인을 고치고 다시 apply 하면 남은 것부터 이어서 만듭니다.
같은 일을 하는 다른 도구
인프라를 코드로 적는 도구는 테라폼 말고도 여럿입니다. 무엇으로 적는지와 상태를 누가 들고 있는지로 갈립니다. 아래 표의 YAML(YAML Ain't Markup Language)은 들여쓰기로 계층을 나타내는 설정 파일 형식입니다.
| 도구 | 무엇으로 적나 | 상태를 누가 들고 있나 | 다루는 클라우드 |
|---|---|---|---|
| 테라폼 | HCL | 사용자가 정한 백엔드 | 프로바이더가 있는 곳 전부 |
| CloudFormation | YAML 이나 JSON 템플릿 | AWS 가 들고 있다 | AWS 만 |
| Pulumi | TypeScript · Python · Go 같은 일반 프로그래밍 언어 | 사용자가 정한 백엔드나 Pulumi 서비스 | 여러 클라우드 |
| OpenTofu | HCL | 사용자가 정한 백엔드 | 테라폼과 같다 |
OpenTofu 는 테라폼의 라이선스가 바뀐 뒤 오픈 소스로 갈라져 나온 도구입니다. 테라폼 설정 파일을 읽습니다.
맞는 경우와 안 맞는 경우
테라폼은 같은 구성을 여러 번 세우거나, 여러 사람이 인프라를 함께 고칠 때 쓸모가 큽니다. 개발용·검증용·운영용 환경을 같은 모듈로 찍어 내는 팀이 대표적입니다.
한 번 띄워 보고 지울 실험에는 맞지 않습니다. 실험보다 설정 파일과 상태 파일을 갖추는 품이 더 듭니다. 다른 시스템이 수시로 바꾸는 값에도 맞지 않습니다. 부하에 따라 서버 수를 늘리고 줄이는 자동 확장이 그런 예입니다. 테라폼이 매번 파일에 적힌 수로 되돌리려 들기 때문입니다.
관련 항목
테라폼이 따르는 인프라 관리 방식
코드형 인프라 · 선언적 설정 · 인프라 · 프로비저닝 · 불변 인프라 · 멱등성 · GitOps
테라폼 설정을 이루는 구성 요소
HCL · 프로바이더 (테라폼) · 리소스 (테라폼) · 데이터 소스 (테라폼) · 모듈 (테라폼) · 변수 (테라폼) · 출력 (테라폼)
테라폼 상태를 지키는 장치
상태 파일 · 상태 잠금 · 원격 백엔드 · 구성 드리프트 · Amazon S3
테라폼이 자원을 만드는 클라우드
클라우드 · AWS · Google Cloud · Azure · Kubernetes · Cloudflare · VPC
테라폼과 같은 일을 두고 겨루는 도구
CloudFormation · Pulumi · OpenTofu · AWS CDK
테라폼이 만든 서버 안을 채우는 도구
설정 관리 · 앤서블 · Packer · 머신 이미지 · 스노우플레이크 서버
테라폼 변경을 검토하고 실행하는 흐름
테라폼을 만든 회사와 기반 기술
다른 이름: Terraform · terraform