본문으로 건너뛰기
김신건의 로그

[IaC] Terraform: HCL, provider, state

· 수정 · 📖 약 1분 · 443자/단어 #terraform #iac #infrastructure-as-code #devops #cloud
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 lockAWS 표준
Terraform Cloud / HCPmanaged
GCS / Azure BlobGCP / 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

TerraformPulumiAWS CDK
언어HCLTS/Python/Go/.NETTS/Python/Java
Multi-cloudAWS only
학습 곡선중간높음 (코드 자유)중간
생태계가장 큼성장AWS 강

흔한 함정

WARNING

  1. State git commit = secret 노출. 원격 backend + 암호화.
  2. apply 직전 plan 안 봄 = 의도하지 않은 destroy.
  3. destroy 사고 (production) = prevent_destroy lifecycle + IAM 보호.
  4. 버전 미고정 = 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")]
도구특징
AtlantisPR comment 기반, self-hosted
Terraform CloudHashiCorp managed, plan 저장
GitHub Actions커스텀 워크플로
Spaceliftpolicy-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 계…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기