본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 11. 30. · 24 Views
Terraform 기초 - Infrastructure as Code 완벽 가이드
코드로 인프라를 관리하는 Terraform의 기초부터 실무 활용까지 배워봅니다. 설치부터 State 관리, Remote Backend까지 차근차근 알아가는 IaC 입문서입니다.
목차
- Terraform_설치하기
- HCL_문법_기초
- Provider_설정하기
- Resource와_Data_Source
- State_파일_관리
- Remote_Backend_설정
- State_Locking_적용
1. Terraform 설치하기
어느 날 김개발 씨는 회사에서 새로운 프로젝트를 맡게 되었습니다. AWS에 서버 10대를 구축해야 하는데, 콘솔에서 일일이 클릭하다 보니 하루가 다 갔습니다.
"이걸 매번 수동으로 해야 해요?" 선배 박시니어 씨가 웃으며 말했습니다. "Terraform 써봐요.
인생이 달라질 거예요."
Terraform은 HashiCorp에서 만든 Infrastructure as Code 도구입니다. 마치 레시피를 보고 요리하듯, 코드로 작성한 설계도대로 인프라를 자동으로 생성합니다.
AWS, GCP, Azure 등 주요 클라우드를 모두 지원하며, 한 번 작성한 코드는 언제든 동일한 인프라를 재현할 수 있습니다.
다음 코드를 살펴봅시다.
# macOS에서 Homebrew로 설치
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
# 설치 확인
terraform version
# Terraform v1.6.0
# 자동완성 설정 (선택사항)
terraform -install-autocomplete
# 첫 번째 프로젝트 디렉토리 생성
mkdir my-first-terraform
cd my-first-terraform
# 초기화 명령어 (나중에 자세히 배웁니다)
terraform init
김개발 씨는 입사 6개월 차 주니어 DevOps 엔지니어입니다. 오늘도 AWS 콘솔을 켜고 EC2 인스턴스를 생성하고 있었습니다.
보안 그룹 설정하고, VPC 연결하고, IAM 역할 붙이고... 한 대 만드는 데만 30분이 걸렸습니다.
"이걸 10대나 만들어야 한다고?" 김개발 씨는 한숨을 쉬었습니다. 더 큰 문제는 따로 있었습니다.
한 달 뒤 같은 환경을 다시 구축해야 하는데, 지금 어떤 설정을 했는지 기억이 날 리가 없었습니다. 그때 옆자리 박시니어 씨가 다가왔습니다.
"김개발 씨, 아직도 콘솔로 하고 있어요? Terraform 쓰면 5분이면 끝나는데." Terraform이란 정확히 무엇일까요?
쉽게 비유하자면, Terraform은 마치 건축 설계도와 같습니다. 건축가가 설계도를 그리면 건설 회사가 그대로 건물을 짓듯이, 개발자가 코드로 인프라 설계도를 작성하면 Terraform이 그대로 클라우드에 인프라를 생성합니다.
이것이 바로 Infrastructure as Code, 줄여서 IaC입니다. 인프라를 코드로 관리한다는 뜻입니다.
마우스 클릭 대신 코드를 작성하고, 그 코드를 Git으로 버전 관리하며, 팀원들과 공유할 수 있습니다. Terraform이 없던 시절에는 어땠을까요?
개발자들은 클라우드 콘솔에 접속해서 일일이 리소스를 생성했습니다. 문제는 이 과정이 문서화되지 않는다는 점이었습니다.
"지난번에 어떻게 설정했더라?" 기억에 의존해야 했고, 실수가 잦았습니다. 더 심각한 문제는 환경 간 불일치였습니다.
개발 환경, 스테이징 환경, 운영 환경을 동일하게 만들어야 하는데, 수동으로 하다 보면 미묘한 차이가 생겼습니다. 이런 차이가 나중에 큰 장애로 이어지기도 했습니다.
Terraform을 사용하면 이 모든 문제가 해결됩니다. 코드로 작성하니 Git으로 버전 관리가 됩니다.
누가, 언제, 무엇을 변경했는지 히스토리가 남습니다. 코드 리뷰도 가능합니다.
설치는 매우 간단합니다. macOS라면 Homebrew로 한 줄이면 됩니다.
Windows라면 Chocolatey를, Linux라면 apt나 yum을 사용하면 됩니다. 공식 홈페이지에서 바이너리를 직접 다운로드해도 됩니다.
설치 후 터미널에서 terraform version을 입력해보세요. 버전 정보가 출력되면 설치가 완료된 것입니다.
이제 인프라를 코드로 관리할 준비가 되었습니다. 박시니어 씨의 말대로, 김개발 씨의 인생이 달라지려 하고 있었습니다.
다음 장에서는 Terraform의 언어인 HCL 문법을 배워보겠습니다.
실전 팁
💡 - terraform -install-autocomplete 명령으로 탭 자동완성을 설정하면 편리합니다
- tfenv를 사용하면 여러 버전의 Terraform을 관리할 수 있습니다
- 회사에서는 팀원들과 동일한 Terraform 버전을 사용하세요
2. HCL 문법 기초
Terraform을 설치한 김개발 씨는 첫 번째 코드를 작성하려고 했습니다. 그런데 파일을 열어보니 낯선 문법이 눈에 들어왔습니다.
"이건 JSON도 아니고 YAML도 아닌데... 뭐지?" 박시니어 씨가 설명했습니다.
"HCL이라고 해요. HashiCorp Configuration Language의 약자예요."
HCL은 Terraform 전용 설정 언어입니다. JSON처럼 구조화되어 있으면서도 사람이 읽고 쓰기 편하게 설계되었습니다.
블록, 인자, 표현식이라는 세 가지 핵심 요소로 구성되며, 한 번 익히면 직관적으로 인프라를 정의할 수 있습니다.
다음 코드를 살펴봅시다.
# 블록 정의: 블록타입 "라벨1" "라벨2" { ... }
resource "aws_instance" "web_server" {
# 인자: 키 = 값
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
# 중첩 블록
tags = {
Name = "WebServer"
Environment = "production"
}
# 표현식 사용
count = var.server_count > 0 ? var.server_count : 1
}
김개발 씨는 처음 HCL 파일을 열었을 때 당황했습니다. 중괄호가 있어서 JSON 같기도 하고, 들여쓰기가 중요해 보여서 YAML 같기도 했습니다.
하지만 둘 다 아니었습니다. 박시니어 씨가 차근차근 설명했습니다.
"HCL은 HashiCorp가 만든 언어예요. 사람이 읽기 쉬우면서도 기계가 파싱하기 좋게 설계되었죠." HCL의 가장 기본 단위는 블록입니다.
블록은 마치 레고 블록과 같습니다. 여러 블록을 조합해서 전체 인프라를 만들어갑니다.
블록은 타입, 라벨, 내용으로 구성됩니다. 위 코드를 보면 resource가 블록 타입입니다.
첫 번째 라벨 "aws_instance"는 어떤 종류의 리소스인지, 두 번째 라벨 "web_server"는 이 리소스의 이름입니다. 중괄호 안에는 실제 설정값들이 들어갑니다.
블록 안에는 인자가 들어갑니다. 인자는 "키 = 값" 형태로 작성합니다.
ami는 AMI 이미지 ID를, instance_type은 인스턴스 크기를 지정합니다. 등호 앞뒤에 공백을 넣어 가독성을 높이는 것이 관례입니다.
표현식도 사용할 수 있습니다. 삼항 연산자, 산술 연산, 함수 호출 등 프로그래밍 언어처럼 동적인 값을 만들 수 있습니다.
var.server_count는 변수를 참조하는 표현식입니다. 주석은 샵 기호로 작성합니다.
여러 줄 주석은 슬래시 별표로 감쌉니다. 코드에 충분한 주석을 달아두면 나중에 유지보수할 때 큰 도움이 됩니다.
문자열은 큰따옴표로 감싸고, 여러 줄 문자열은 heredoc 문법을 사용합니다. 리스트는 대괄호로, 맵은 중괄호로 표현합니다.
JavaScript 개발자라면 익숙하게 느껴질 것입니다. 중첩 블록도 가능합니다.
tags처럼 블록 안에 또 다른 블록을 넣을 수 있습니다. 이렇게 계층 구조를 만들어 복잡한 설정도 깔끔하게 표현합니다.
김개발 씨는 고개를 끄덕였습니다. "생각보다 직관적이네요.
JSON보다 훨씬 읽기 편해요." 박시니어 씨가 웃었습니다. "그게 HCL의 매력이에요.
이제 실제로 인프라를 만들어볼까요?"
실전 팁
💡 - terraform fmt 명령으로 코드 스타일을 자동 정리할 수 있습니다
- .tf 확장자를 사용하며, 한 디렉토리의 모든 .tf 파일이 함께 처리됩니다
- VS Code의 HashiCorp Terraform 확장을 설치하면 문법 하이라이팅과 자동완성을 지원합니다
3. Provider 설정하기
김개발 씨가 첫 번째 Terraform 코드를 작성하려는데, 박시니어 씨가 말렸습니다. "잠깐, Provider부터 설정해야 해요." "Provider요?
그게 뭔가요?" 김개발 씨가 물었습니다. "Terraform이 AWS랑 대화할 수 있게 해주는 통역사 같은 거예요."
Provider는 Terraform이 특정 클라우드나 서비스와 통신할 수 있게 해주는 플러그인입니다. AWS, GCP, Azure 같은 클라우드뿐만 아니라 GitHub, Kubernetes, Datadog 등 다양한 서비스의 Provider가 있습니다.
Provider 없이는 어떤 리소스도 생성할 수 없습니다.
다음 코드를 살펴봅시다.
# Terraform 버전과 필요한 Provider 선언
terraform {
required_version = ">= 1.0.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# AWS Provider 설정
provider "aws" {
region = "ap-northeast-2" # 서울 리전
# 태그를 모든 리소스에 자동 적용
default_tags {
tags = {
ManagedBy = "Terraform"
}
}
}
박시니어 씨의 비유가 정확했습니다. Terraform은 그 자체로는 아무것도 할 수 없습니다.
AWS에 EC2를 만들려면 AWS Provider가, GCP에 VM을 만들려면 Google Provider가 필요합니다. Provider가 바로 Terraform과 클라우드 사이의 통역사 역할을 합니다.
terraform 블록은 프로젝트의 기본 설정을 담습니다. required_version은 이 코드를 실행할 수 있는 Terraform 버전을 지정합니다.
팀원들이 서로 다른 버전을 쓰면 문제가 생길 수 있으니, 버전을 명시하는 것이 좋습니다. required_providers 블록에서는 필요한 Provider를 선언합니다.
source는 Provider의 출처를, version은 사용할 버전을 지정합니다. 물결표시 꺾쇠는 "5.0 이상 6.0 미만"을 의미합니다.
provider 블록에서는 실제 설정을 합니다. AWS Provider라면 리전을 지정해야 합니다.
서울 리전은 ap-northeast-2입니다. 회사 정책에 따라 다른 리전을 사용할 수도 있습니다.
인증은 어떻게 할까요? Provider는 여러 방식을 지원합니다.
환경 변수로 AWS_ACCESS_KEY_ID와 AWS_SECRET_ACCESS_KEY를 설정하거나, AWS CLI의 프로파일을 사용하거나, IAM 역할을 사용할 수 있습니다. 주의할 점이 있습니다.
절대로 코드에 직접 인증 정보를 적지 마세요. access_key와 secret_key를 하드코딩하면 Git에 올라가서 보안 사고가 날 수 있습니다.
환경 변수나 AWS CLI 설정을 사용하는 것이 안전합니다. default_tags 기능은 유용합니다.
모든 리소스에 자동으로 태그를 붙여줍니다. "이 리소스는 Terraform으로 관리됩니다"라는 표시를 해두면, 나중에 콘솔에서 수동으로 만든 리소스와 구분하기 쉽습니다.
Provider를 설정했다면 terraform init 명령을 실행합니다. 이 명령이 Provider 플러그인을 다운로드합니다.
.terraform 디렉토리가 생기고, 그 안에 Provider 바이너리가 저장됩니다. 김개발 씨가 terraform init을 실행하자 초록색 글씨가 나왔습니다.
"Terraform has been successfully initialized!" 드디어 AWS와 대화할 준비가 된 것입니다.
실전 팁
💡 - AWS 인증은 환경 변수나 AWS CLI 프로파일을 사용하고, 코드에 직접 적지 마세요
- Provider 버전을 고정하면 팀원 간 일관성을 유지할 수 있습니다
- terraform providers 명령으로 사용 중인 Provider 목록을 확인할 수 있습니다
4. Resource와 Data Source
Provider 설정을 마친 김개발 씨는 드디어 첫 번째 리소스를 만들려고 했습니다. "자, 이제 EC2 하나 만들어볼까요?" 그런데 박시니어 씨가 물었습니다.
"근데 어떤 VPC에 만들 거예요? 기존 VPC를 쓸 거면 Data Source를 써야 해요." Resource와 Data Source, 이 둘의 차이가 뭘까요?
Resource는 새로운 인프라를 생성하는 블록입니다. EC2 인스턴스, S3 버킷, RDS 데이터베이스 등을 만들 때 사용합니다.
반면 Data Source는 이미 존재하는 인프라의 정보를 읽어오는 블록입니다. 기존 VPC나 AMI 정보를 가져올 때 사용합니다.
다음 코드를 살펴봅시다.
# Data Source: 기존 VPC 정보 조회
data "aws_vpc" "existing" {
filter {
name = "tag:Name"
values = ["production-vpc"]
}
}
# Data Source: 최신 Amazon Linux 2 AMI 조회
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
# Resource: 새로운 EC2 인스턴스 생성
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t2.micro"
subnet_id = data.aws_vpc.existing.main_route_table_id
tags = {
Name = "WebServer"
}
}
김개발 씨는 처음에 헷갈렸습니다. "그냥 VPC도 새로 만들면 안 돼요?" 물론 가능합니다.
하지만 실무에서는 이미 존재하는 인프라와 연동해야 하는 경우가 훨씬 많습니다. Resource를 비유하자면, 새 집을 짓는 것과 같습니다.
설계도대로 재료를 모아 처음부터 건물을 세웁니다. terraform apply를 실행하면 클라우드에 실제 리소스가 생성됩니다.
Data Source는 이미 지어진 집의 주소를 찾는 것과 같습니다. 새로 짓지 않고, 기존 건물의 정보만 가져옵니다.
VPC ID가 뭔지, 서브넷 CIDR이 뭔지 같은 정보를 읽어올 수 있습니다. 왜 Data Source가 필요할까요?
실무에서는 네트워크 팀이 VPC를 미리 만들어두는 경우가 많습니다. 개발팀은 그 VPC 안에 EC2만 만들면 됩니다.
이때 VPC ID를 하드코딩하면 환경마다 코드를 수정해야 합니다. Data Source를 쓰면 동적으로 VPC ID를 가져올 수 있습니다.
태그 이름으로 검색하면, 개발 환경에서는 dev-vpc를, 운영 환경에서는 production-vpc를 자동으로 찾습니다. 위 코드에서 data 블록은 기존 VPC와 AMI 정보를 조회합니다.
filter를 사용해 조건에 맞는 리소스를 찾습니다. most_recent 옵션은 여러 개가 있을 때 가장 최신 것을 선택합니다.
resource 블록에서는 Data Source의 결과를 참조합니다. data.aws_ami.amazon_linux.id 형식으로 AMI ID를 가져옵니다.
이렇게 하면 AMI ID가 바뀌어도 코드를 수정할 필요가 없습니다. 주의할 점이 있습니다.
Data Source는 읽기 전용입니다. 기존 리소스를 수정하거나 삭제할 수 없습니다.
오직 정보를 조회하는 용도로만 사용됩니다. 또한 Data Source가 찾는 리소스가 없으면 에러가 납니다.
조건을 너무 엄격하게 설정하면 매칭되는 리소스가 없을 수 있으니 주의하세요. 김개발 씨는 이해했습니다.
"아, 새로 만들 땐 Resource, 기존 걸 참조할 땐 Data Source군요!" 박시니어 씨가 엄지를 들었습니다.
실전 팁
💡 - AMI ID는 리전마다 다르므로, Data Source로 동적으로 가져오는 것이 좋습니다
- Data Source는 terraform plan 단계에서 실행되어 정보를 미리 가져옵니다
- count나 for_each와 함께 사용하면 여러 리소스를 동적으로 생성할 수 있습니다
5. State 파일 관리
김개발 씨가 terraform apply를 실행하자 EC2가 생성되었습니다. 그런데 디렉토리에 이상한 파일이 생겼습니다.
terraform.tfstate라는 파일이었습니다. "이건 뭐예요?
지워도 돼요?" 박시니어 씨가 화들짝 놀라며 말했습니다. "절대 지우면 안 돼요!
그건 Terraform의 심장이에요."
State 파일은 Terraform이 관리하는 인프라의 현재 상태를 저장하는 파일입니다. 어떤 리소스가 있는지, 각 리소스의 속성은 무엇인지 JSON 형태로 기록됩니다.
Terraform은 이 파일을 보고 "무엇을 생성하고, 수정하고, 삭제해야 하는지" 판단합니다.
다음 코드를 살펴봅시다.
# terraform.tfstate 파일 구조 (일부)
{
"version": 4,
"terraform_version": "1.6.0",
"resources": [
{
"mode": "managed",
"type": "aws_instance",
"name": "web",
"instances": [
{
"attributes": {
"id": "i-0abc123def456789",
"ami": "ami-0c55b159cbfafe1f0",
"instance_type": "t2.micro",
"public_ip": "54.180.123.45"
}
}
]
}
]
}
박시니어 씨가 비유를 들었습니다. "김개발 씨, 장부 없이 가게를 운영할 수 있을까요?" 재고가 얼마나 있는지, 오늘 뭘 팔았는지 기록하지 않으면 가게 운영이 불가능합니다.
State 파일은 Terraform의 장부입니다. Terraform은 코드와 State를 비교해서 무엇을 해야 할지 결정합니다.
코드에는 EC2가 있는데 State에 없으면 "생성해야겠구나"라고 판단합니다. 코드에서 EC2를 지웠는데 State에 있으면 "삭제해야겠구나"라고 판단합니다.
만약 State 파일을 삭제하면 어떻게 될까요? Terraform은 자신이 무엇을 만들었는지 잊어버립니다.
다음에 apply를 실행하면 이미 있는 리소스를 또 만들려고 시도합니다. 대혼란이 일어납니다.
State 파일 안에는 민감한 정보가 들어갈 수 있습니다. 데이터베이스 비밀번호, API 키 같은 것들이요.
그래서 State 파일은 절대 Git에 커밋하면 안 됩니다. .gitignore에 반드시 추가해야 합니다.
로컬에 State 파일을 두면 문제가 있습니다. 첫째, 팀원들과 공유하기 어렵습니다.
둘째, 노트북이 고장 나면 State를 잃어버립니다. 셋째, 두 사람이 동시에 terraform apply를 실행하면 충돌이 납니다.
그래서 실무에서는 State를 원격 저장소에 보관합니다. S3, GCS, Azure Blob Storage 같은 곳에요.
이것을 Remote Backend라고 합니다. 다음 장에서 자세히 알아보겠습니다.
State를 직접 수정하는 것은 위험합니다. 하지만 가끔 필요할 때가 있습니다.
terraform state 명령을 사용하면 안전하게 State를 조작할 수 있습니다. terraform state list로 리소스 목록을 보고, terraform state show로 상세 정보를 볼 수 있습니다.
terraform state rm 명령은 State에서 리소스를 제거합니다. 실제 인프라는 그대로 두고, Terraform 관리에서만 빠집니다.
수동으로 만든 리소스를 Terraform 관리로 가져올 때는 terraform import를 사용합니다. 김개발 씨는 고개를 끄덕였습니다.
"State 파일, 정말 중요하네요. 백업도 해둬야겠어요." 현명한 판단이었습니다.
실전 팁
💡 - terraform.tfstate와 terraform.tfstate.backup을 반드시 .gitignore에 추가하세요
- terraform state list와 terraform state show로 현재 상태를 확인할 수 있습니다
- State 파일을 수동으로 편집하지 말고, terraform state 명령을 사용하세요
6. Remote Backend 설정
김개발 씨는 동료 이주니어 씨와 같은 프로젝트를 작업하게 되었습니다. 둘 다 각자의 노트북에서 terraform apply를 실행했더니 난리가 났습니다.
"왜 리소스가 두 개야?" 박시니어 씨가 한숨을 쉬며 말했습니다. "그래서 Remote Backend를 쓰라고 했잖아요."
Remote Backend는 State 파일을 원격 저장소에 보관하는 방식입니다. AWS S3, Google Cloud Storage, Azure Blob Storage 등을 사용할 수 있습니다.
팀원 모두가 같은 State를 공유하므로 충돌을 방지하고, State 유실 위험도 줄일 수 있습니다.
다음 코드를 살펴봅시다.
# S3 Backend 설정
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "prod/terraform.tfstate"
region = "ap-northeast-2"
encrypt = true
# State Locking을 위한 DynamoDB 테이블
dynamodb_table = "terraform-state-lock"
}
}
# Backend용 S3 버킷 생성 (별도 프로젝트에서)
resource "aws_s3_bucket" "terraform_state" {
bucket = "my-terraform-state-bucket"
lifecycle {
prevent_destroy = true
}
}
# 버전 관리 활성화
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
로컬 State의 문제점을 다시 정리해봅시다. 팀원마다 각자의 State가 있으면, 서로 다른 "현실"을 보게 됩니다.
A가 EC2를 만들어도 B의 State에는 기록되지 않습니다. B가 apply를 실행하면 또 EC2를 만들려고 합니다.
Remote Backend는 이 문제를 해결합니다. State를 중앙 저장소에 두면 모든 팀원이 같은 State를 봅니다.
A가 변경하면 B도 그 변경 사항을 볼 수 있습니다. S3 Backend가 가장 많이 쓰입니다.
AWS 환경에서 자연스럽게 연동되고, 비용도 저렴합니다. 버전 관리를 켜면 State 히스토리도 보관됩니다.
실수로 잘못된 apply를 해도 이전 버전으로 복구할 수 있습니다. Backend 설정은 terraform 블록 안에 작성합니다.
bucket은 S3 버킷 이름, key는 State 파일 경로, region은 버킷이 있는 리전입니다. encrypt를 true로 하면 서버 측 암호화가 적용됩니다.
한 가지 닭과 달걀 문제가 있습니다. State를 저장할 S3 버킷은 누가 만들까요?
이 버킷 자체도 Terraform으로 만들고 싶은데, 아직 Backend가 없습니다. 해결책은 Bootstrap 프로젝트를 따로 만드는 것입니다.
작은 Terraform 프로젝트를 하나 만들어서 S3 버킷과 DynamoDB 테이블만 생성합니다. 이 프로젝트는 로컬 State를 사용합니다.
그 다음 메인 프로젝트에서 이 버킷을 Backend로 사용합니다. Backend 설정을 변경한 후에는 terraform init -reconfigure를 실행해야 합니다.
기존 로컬 State를 원격으로 마이그레이션할 건지 물어봅니다. yes를 입력하면 State가 S3로 이동합니다.
prevent_destroy 옵션은 중요합니다. 실수로 State 버킷을 삭제하면 모든 것을 잃습니다.
이 옵션을 켜면 terraform destroy로도 버킷을 삭제할 수 없습니다. 김개발 씨와 이주니어 씨는 Remote Backend를 설정한 후 평화롭게 협업할 수 있었습니다.
더 이상 리소스 충돌이 일어나지 않았습니다.
실전 팁
💡 - State 버킷은 별도의 Bootstrap 프로젝트로 관리하세요
- S3 버킷에 버전 관리를 켜서 State 히스토리를 보관하세요
- 환경별로 다른 key를 사용하세요 (예: prod/terraform.tfstate, dev/terraform.tfstate)
7. State Locking 적용
Remote Backend를 설정했지만, 박시니어 씨는 아직 걱정이 남았습니다. "만약 김개발 씨와 이주니어 씨가 동시에 apply를 누르면 어떻게 될까요?" 둘 다 같은 State를 수정하려고 하면 데이터가 꼬일 수 있습니다.
이 문제를 막는 것이 바로 State Locking입니다.
State Locking은 한 번에 한 사람만 State를 수정할 수 있게 잠금을 거는 기능입니다. 누군가 terraform apply를 실행하면 Lock이 걸리고, 다른 사람은 기다려야 합니다.
AWS에서는 DynamoDB 테이블을 사용해 Lock을 관리합니다. 이로써 동시 수정으로 인한 State 손상을 방지합니다.
다음 코드를 살펴봅시다.
# DynamoDB 테이블 생성 (State Locking용)
resource "aws_dynamodb_table" "terraform_lock" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = {
Name = "Terraform State Lock"
Purpose = "State Locking for Terraform"
}
}
# Backend에서 DynamoDB 테이블 지정
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "prod/terraform.tfstate"
region = "ap-northeast-2"
encrypt = true
dynamodb_table = "terraform-state-lock"
}
}
박시니어 씨가 또 비유를 들었습니다. "공용 화장실에 자물쇠가 있는 이유가 뭘까요?
두 사람이 동시에 들어가면 곤란하니까요." State Locking도 마찬가지입니다. 한 사람이 State를 수정하는 동안 다른 사람은 문 앞에서 기다려야 합니다.
Lock 없이 두 사람이 동시에 apply를 실행하면 어떻게 될까요? 둘 다 같은 State를 읽고, 각자 변경 사항을 적용하고, 각자 State를 저장합니다.
나중에 저장한 사람의 State가 이기고, 먼저 저장한 사람의 변경 사항은 사라집니다. 더 심각한 경우도 있습니다.
State 파일 자체가 손상될 수 있습니다. 두 프로세스가 동시에 같은 파일을 쓰다가 데이터가 섞이는 것입니다.
이렇게 되면 State를 복구하기가 매우 어렵습니다. S3 Backend에서는 DynamoDB를 사용해 Lock을 구현합니다.
DynamoDB는 AWS의 NoSQL 데이터베이스인데, 여기서는 단순히 Lock 정보만 저장합니다. 테이블 구조도 간단합니다.
LockID라는 키 하나만 있으면 됩니다. terraform apply를 실행하면 Terraform이 DynamoDB에 Lock 레코드를 생성합니다.
이 레코드가 있는 동안 다른 사람은 apply를 실행할 수 없습니다. apply가 끝나면 Lock이 해제됩니다.
Lock이 걸려 있을 때 다른 사람이 apply를 시도하면 어떻게 될까요? "Error acquiring the state lock"이라는 메시지가 나옵니다.
누가 Lock을 잡고 있는지, 언제부터 잡고 있는지 정보도 함께 보여줍니다. 가끔 Lock이 해제되지 않는 경우가 있습니다.
apply 도중에 네트워크가 끊기거나, 프로세스가 강제 종료되면 그럴 수 있습니다. 이때는 terraform force-unlock 명령으로 강제 해제할 수 있습니다.
하지만 정말 필요한 경우에만 사용해야 합니다. billing_mode를 PAY_PER_REQUEST로 설정하면 사용한 만큼만 비용을 냅니다.
State Locking은 요청 수가 매우 적으므로 비용은 거의 무시할 수 있는 수준입니다. 김개발 씨는 이제 안심이 되었습니다.
동료와 동시에 작업해도 State가 꼬일 걱정이 없어졌습니다. Terraform의 기초를 모두 배운 김개발 씨, 이제 진정한 IaC 여정이 시작됩니다.
실전 팁
💡 - DynamoDB 테이블은 State 버킷과 함께 Bootstrap 프로젝트에서 만드세요
- force-unlock은 정말 필요한 경우에만 사용하고, Lock을 잡은 사람에게 먼저 확인하세요
- Lock 정보에는 누가 언제 Lock을 잡았는지 기록되므로 디버깅에 유용합니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
마이크로서비스 배포 완벽 가이드
Kubernetes를 활용한 마이크로서비스 배포의 핵심 개념부터 실전 운영까지, 초급 개발자도 쉽게 따라할 수 있는 완벽 가이드입니다. 실무에서 바로 적용 가능한 배포 전략과 노하우를 담았습니다.
CloudFormation 기초 완벽 가이드
AWS 인프라를 코드로 관리하는 CloudFormation의 기초부터 실전까지 다룹니다. 템플릿 작성부터 스택 관리까지, 초급 개발자도 쉽게 따라 할 수 있는 실무 중심 가이드입니다.
Application Load Balancer 완벽 가이드
AWS의 Application Load Balancer를 처음 배우는 개발자를 위한 실전 가이드입니다. ALB 생성부터 ECS 연동, 헬스 체크, HTTPS 설정까지 실무에 필요한 모든 내용을 다룹니다. 초급 개발자도 쉽게 따라할 수 있도록 단계별로 설명합니다.
고객 상담 AI 시스템 완벽 구축 가이드
AWS Bedrock Agent와 Knowledge Base를 활용하여 실시간 고객 상담 AI 시스템을 구축하는 방법을 단계별로 학습합니다. RAG 기반 지식 검색부터 Guardrails 안전 장치, 프론트엔드 연동까지 실무에 바로 적용 가능한 완전한 시스템을 만들어봅니다.
에러 처리와 폴백 완벽 가이드
AWS API 호출 시 발생하는 에러를 처리하고 폴백 전략을 구현하는 방법을 다룹니다. ThrottlingException부터 서킷 브레이커 패턴까지, 실전에서 바로 활용할 수 있는 안정적인 에러 처리 기법을 배웁니다.