[IaC] Terraform: HCL, provider, state
Terraform, HCL, Terraform provider, terraform plan, terraform apply, tfstate, OpenTofu, aws-terraform
정의
Terraform = 선언적 인프라 코드. HCL (HashiCorp Configuration Language) 로 리소스 정의 → AWS/GCP/Azure 등 provider 가 실제 생성.
NOTE
2024 라이센스 변경 (BSL) 으로 OpenTofu fork 등장. OSS 분기. 2026 시점 OpenTofu 도 안정적.
흐름
flowchart LR
Code[main.tf] --> Init[terraform init<br/>provider download]
Init --> Plan[terraform plan<br/>diff 표시]
Plan --> Review[Review by team]
Review --> Apply[terraform apply<br/>실제 변경]
Apply --> State[(terraform.tfstate)]
HCL 예시
terraform {
required_version = ">= 1.6"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "tf-lock"
encrypt = true
}
}
provider "aws" {
region = var.region
}
variable "region" {
type = string
default = "us-east-1"
}
resource "aws_s3_bucket" "data" {
bucket = "myapp-data-${terraform.workspace}"
tags = {
Environment = terraform.workspace
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket_versioning" "data" {
bucket = aws_s3_bucket.data.id
versioning_configuration { status = "Enabled" }
}
output "bucket_name" {
value = aws_s3_bucket.data.id
}
핵심 명령
terraform init # provider + module download
terraform fmt # 코드 포맷
terraform validate # 문법
terraform plan # diff (실행 X)
terraform apply # 실제 변경
terraform destroy # 모두 삭제
terraform show # state 출력
terraform state list # 리소스 목록
terraform import # 기존 리소스 → state 등록
terraform workspace # 환경 분리
State
flowchart LR
Code["코드 (의도)"] --> Compare
State["state (실제 알려진 상태)"] --> Compare
Compare["diff 계산"] --> Plan
| 저장 | 적합 |
|---|---|
| Local file | 팀 작업 금지 |
| S3 + DynamoDB lock | AWS 표준 |
| Terraform Cloud / HCP | managed |
| GCS / Azure Blob | GCP / Azure |
자세한 건 terraform-state.
Module (재사용)
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.5.0"
name = "prod-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
...
}
Terraform Registry (수천 모듈), 자체 모듈, Git 소스 가능.
Lifecycle Meta-arguments
resource "aws_instance" "web" {
...
lifecycle {
create_before_destroy = true # 새 생성 후 옛 삭제
prevent_destroy = true # apply -destroy 차단
ignore_changes = [tags] # 특정 필드 무시
}
}
for_each / count
# count: 단순 N
resource "aws_instance" "web" {
count = 3
ami = "ami-..."
}
# for_each: 명시적 키 (변경 안전)
resource "aws_iam_user" "team" {
for_each = toset(["alice", "bob", "charlie"])
name = each.key
}
Terraform vs Pulumi vs CDK
| Terraform | Pulumi | AWS CDK | |
|---|---|---|---|
| 언어 | HCL | TS/Python/Go/.NET | TS/Python/Java |
| Multi-cloud | 예 | 예 | AWS only |
| 학습 곡선 | 중간 | 높음 (코드 자유) | 중간 |
| 생태계 | 가장 큼 | 성장 | AWS 강 |
흔한 함정
WARNING
- State git commit = secret 노출. 원격 backend + 암호화.
apply직전plan안 봄 = 의도하지 않은 destroy.destroy사고 (production) =prevent_destroylifecycle + IAM 보호.- 버전 미고정 = provider 새 버전 = 다른 결과.
~>또는 lock file.
Workspace (환경 분리)
terraform workspace new prod
terraform workspace new staging
terraform workspace select prod
terraform workspace list
locals {
env_config = {
prod = { instance_type = "r6i.2xlarge", min_size = 3 }
staging = { instance_type = "t3.medium", min_size = 1 }
}
cfg = local.env_config[terraform.workspace]
}
workspace = state 파일만 분리. 실제 환경 격리에는 별도 AWS account 권장. workspace 는 단순 분기에 적합.
Moved 블록 (리팩터링 안전)
moved {
from = aws_s3_bucket.data
to = module.storage.aws_s3_bucket.data
}
리소스를 모듈로 이동 시 destroy + recreate 방지. state 파일만 업데이트.
Import 블록 (선언적 import)
import {
to = aws_s3_bucket.existing
id = "my-existing-bucket-name"
}
기존 인프라를 terraform 관리로 전환.
terraform import명령어 대신 선언적으로.
Terraform Test (1.6+)
# tests/s3.tftest.hcl
variables {
region = "us-east-1"
}
run "creates_bucket" {
assert {
condition = aws_s3_bucket.data.bucket != ""
error_message = "bucket name must not be empty"
}
}
terraform test # built-in testing framework
CI/CD 통합
flowchart LR
PR["Pull Request"] --> CI["CI: terraform plan"]
CI -->|"plan output"| Review["PR Comment"]
Review --> Merge["Merge to main"]
Merge --> CD["CD: terraform apply"]
CD --> State[("Remote State")]
| 도구 | 특징 |
|---|---|
| Atlantis | PR comment 기반, self-hosted |
| Terraform Cloud | HashiCorp managed, plan 저장 |
| GitHub Actions | 커스텀 워크플로 |
| Spacelift | policy-as-code, OPA 통합 |
시크릿은 절대 코드에 넣지 않음. CI 환경변수 또는 Vault 사용.
Terragrunt (DRY 관리)
# terragrunt.hcl
terraform {
source = "github.com/myorg/tf-modules//aws/vpc"
}
inputs = {
cidr = "10.0.0.0/16"
env = "prod"
}
Terraform 의 DRY 한계 (module 반복, backend 중복) 를 Terragrunt 가 보완. 대규모 멀티 계정 환경에서 유용.
관련 위키
이 글의 용어 (6개)
- [AWS] CDK (Cloud Development Kit)cloud
- 정의 AWS CDK (Cloud Development Kit) 는 프로그래밍 언어 (TypeScript, Python, Java, C#, Go) 로 AWS 인프라를 정의하여 Cl…
- [AWS] CloudFormationcloud
- 정의 AWS CloudFormation 은 JSON 또는 YAML 템플릿으로 AWS 인프라를 선언적으로 프로비저닝하는 IaC (Infrastructure as Code) 서비스입…
- [AWS] IAM: User, Role, Policy, STScloud
- 정의 IAM (Identity and Access Management) = AWS 의 권한 관리 전부. User, Group, Role, Policy 로 구성. "누가 어떤 리소…
- [CI/CD] GitHub Actions: workflow, action, runnerdevops
- 정의 GitHub Actions = GitHub 내장 CI/CD. YAML workflow + marketplace action. 2018 출시 → Travis CI 대체. 구조…
- [IaC] Pulumi: 코드로 인프라 (TS/Python/Go)cloud
- 정의 Pulumi = 일반 프로그래밍 언어로 IaC. TypeScript, Python, Go, .NET, Java. Terraform 의 HCL DSL 대신 코드 자유도. 사용…
- [IaC] Terraform State: backend, locking, drift, importcloud
- 정의 Terraform State = 코드 (의도) vs 실제 인프라 매핑. JSON 파일. 모든 Terraform 작업의 핵심. , , 모두 state 를 기반으로 diff 계…
💬 댓글