Terraform 실전 가이드 | IaC·AWS·State·Module·Workspace·Best Practices
이 글의 핵심
Terraform으로 인프라를 코드로 관리하는 실전 가이드입니다. 기본 문법, AWS 리소스, State 관리, Module, Workspace, Best Practices까지 실무 예제로 정리했습니다.
실무 경험 공유: 수동 인프라 관리를 Terraform으로 자동화하면서, 배포 시간을 2시간에서 10분으로 단축하고 인프라 오류를 90% 줄인 경험을 공유합니다.
들어가며: “인프라 관리가 복잡해요”
실무 문제 시나리오
시나리오 1: 콘솔에서 수동으로 클릭해요
AWS 콘솔에서 리소스를 생성합니다. 실수가 많고 재현이 어렵습니다.
시나리오 2: 환경마다 다르게 설정해요
개발/스테이징/프로덕션 설정이 달라 혼란스럽습니다. Terraform으로 일관성을 유지합니다.
시나리오 3: 인프라 변경 이력이 없어요
누가 언제 무엇을 바꿨는지 모릅니다. Terraform은 Git으로 관리합니다.
1. Terraform이란?
핵심 특징
Terraform은 인프라를 코드로 관리하는 IaC 도구입니다.
주요 장점:
- 선언적: 원하는 상태를 정의
- 멀티 클라우드: AWS, GCP, Azure 지원
- State 관리: 현재 상태 추적
- Plan: 변경 사항 미리 확인
- 모듈: 재사용 가능한 구성
2. 설치
설치
# Windows (Chocolatey)
choco install terraform
# macOS
brew install terraform
# 확인
terraform version
3. 기본 문법
첫 번째 리소스
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "example" {
bucket = "my-terraform-bucket-12345"
tags = {
Name = "My bucket"
Environment = "Dev"
}
}
명령어
# 초기화
terraform init
# Plan (변경 사항 확인)
terraform plan
# Apply (적용)
terraform apply
# Destroy (삭제)
terraform destroy
4. 변수
변수 정의
# variables.tf
variable "region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
variable "tags" {
description = "Common tags"
type = map(string)
default = {
Environment = "Dev"
Project = "MyApp"
}
}
변수 사용
# main.tf
provider "aws" {
region = var.region
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = var.instance_type
tags = var.tags
}
변수 값 전달
# CLI
terraform apply -var="region=ap-northeast-2"
# 파일
# terraform.tfvars
region = "ap-northeast-2"
instance_type = "t3.small"
5. Output
# outputs.tf
output "instance_id" {
description = "EC2 instance ID"
value = aws_instance.web.id
}
output "instance_public_ip" {
description = "Public IP"
value = aws_instance.web.public_ip
}
output "s3_bucket_name" {
description = "S3 bucket name"
value = aws_s3_bucket.example.id
}
# Output 확인
terraform output
terraform output instance_public_ip
6. 실전 예제: VPC + EC2
# vpc.tf
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "main-vpc"
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
map_public_ip_on_launch = true
tags = {
Name = "public-subnet"
}
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "main-igw"
}
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "public-rt"
}
}
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
# ec2.tf
resource "aws_security_group" "web" {
name = "web-sg"
description = "Security group for web server"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = [0.0.0.0/0]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [0.0.0.0/0]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [0.0.0.0/0]
}
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "Hello from Terraform" > /var/www/html/index.html
EOF
tags = {
Name = "web-server"
}
}
7. State 관리
Remote State (S3)
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-lock"
encrypt = true
}
}
State 명령어
# State 확인
terraform state list
# 특정 리소스 확인
terraform state show aws_instance.web
# State 이동
terraform state mv aws_instance.old aws_instance.new
# State에서 제거
terraform state rm aws_instance.web
8. Module
Module 정의
# modules/vpc/main.tf
variable "cidr_block" {
type = string
}
variable "name" {
type = string
}
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
tags = {
Name = var.name
}
}
output "vpc_id" {
value = aws_vpc.main.id
}
Module 사용
# main.tf
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
name = "production-vpc"
}
resource "aws_subnet" "public" {
vpc_id = module.vpc.vpc_id
cidr_block = "10.0.1.0/24"
}
9. Workspace
# Workspace 생성
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod
# Workspace 전환
terraform workspace select dev
# 현재 Workspace
terraform workspace show
# Workspace 목록
terraform workspace list
Workspace별 설정
locals {
env = terraform.workspace
instance_type = {
dev = "t3.micro"
staging = "t3.small"
prod = "t3.medium"
}
}
resource "aws_instance" "web" {
instance_type = local.instance_type[local.env]
}
정리 및 체크리스트
핵심 요약
- Terraform: 인프라를 코드로 관리
- 선언적: 원하는 상태를 정의
- State: 현재 상태 추적
- Module: 재사용 가능한 구성
- Workspace: 환경별 관리
- 멀티 클라우드: AWS, GCP, Azure
프로덕션 체크리스트
- Remote State 설정 (S3 + DynamoDB)
- Module 구조화
- Workspace 분리
- 변수 파일 관리
- CI/CD 통합
- 문서화
같이 보면 좋은 글
- Kubernetes 실전 가이드
- GitHub Actions CI/CD 가이드
- AWS 완벽 가이드
이 글에서 다루는 키워드
Terraform, IaC, AWS, DevOps, Infrastructure, Cloud, Automation
자주 묻는 질문 (FAQ)
Q. Terraform vs CloudFormation, 어떤 게 나은가요?
A. Terraform은 멀티 클라우드를 지원합니다. CloudFormation은 AWS 전용입니다. 멀티 클라우드는 Terraform, AWS만 사용하면 둘 다 괜찮습니다.
Q. State 파일을 Git에 커밋해도 되나요?
A. 아니요, 절대 안 됩니다. 민감한 정보가 포함될 수 있습니다. S3 같은 Remote Backend를 사용하세요.
Q. 학습 곡선이 가파른가요?
A. 기본 문법은 간단합니다. 하지만 클라우드 지식이 필요합니다.
Q. 프로덕션에서 사용해도 되나요?
A. 네, 많은 기업에서 프로덕션 인프라를 Terraform으로 관리합니다.