필터:#AWS CLI×

Terraform로 다루는 클라우드 인프라

Terraform로 다루는 클라우드 인프라 코드로 인프라를 선언하고, 한 번의 명령으로 만들고 지우는 법 — 그리고 프로젝트에 적용된 내용 목차 1. Terraform이란 무엇인가 2. AWS CLI와 무엇이 다른가 3. 장점과 단점 4. 기본 문법 한눈에 5. 꼭 쓰는 명령어 6. State 관리 — Remote Backend 7. 팀 협업 방식 8. 우리 프로젝트 구조 9. 실제 정의된 AWS 리소스 10. 실제 코드 예시 11. 전체 아키텍처 12. [주의사항] 1. Terraform이란 무엇인가 HashiCorp가 만든 Infrastructure as Code(IaC) 도구다. 한 줄로 풀면, 클라우드 인프라를 코드로 적어두고 명령어 한 번으로 만들고·고치고·지우는 도구다. 콘솔에서 마우스로 클릭하던 작업을 텍스트 파일(.tf)로 옮긴다고 보면 된다. 코드 작성 → plan(미리보기) → apply(실제 반영) → 인프라 완성 먼저 잡고 갈 세 가지 개념 선언형 (Declarative) — "어떻게 만들어라"가 아니라 "최종 상태가 이래야 한다"고 적는다. 그러면 Terraform이 현재 상태와 비교해서 달라진 부분만 알아서 반영한다. State 파일 — 지금 인프라가 어떤 상태인지 추적하는 JSON 파일이다(terraform.tfstate). Terraform이 "내가 뭘 만들어놨는지" 기억하는 장부라고 보면 된다. Provider — AWS·GCP·Azure 같은 클라우드 API에 연결해주는 플러그인이다. "AWS를 쓰겠다"고 선언하면 해당 provider가 실제 API 호출을 담당한다. 2. AWS CLI와 무엇이 다른가 둘 다 AWS를 다루지만 접근 방식이 정반대다. CLI는 명령형(하나씩 시킨다), Terraform은 선언형(원하는 결과를 적는다). 항목 AWS CLI Terraform 방식 명령형 — 하나씩 실행 선언형 — 최종 상태 정의 예시 aws ec2 runinstances … resource "awsinstance" "web" {…} 상태 추적 ✗ 없음 · 직접 확인 ✓ state 파일로 자동 추적 변경 미리보기 ✗ 불가 ✓ terraform plan 롤백 수동으로 원복 코드 되돌리고 apply 재현성 스크립트 따로 작성 코드 자체가 곧 문서 의존성 순서를 직접 관리 의존성 그래프 자동 생성 삭제 리소스 하나씩 terraform destroy 한 번 언제 뭘 쓰나 AWS CLI — 빠른 조회, 디버깅, 한 번 쓰고 마는 작업. Terraform — 인프라를 짓고 관리할 때, 환경을 복제할 때, 여럿이 협업할 때. 3. 장점과 단점 좋기만 한 도구는 없다. 도입 전에 트레이드오프를 알고 가는 게 중요하다. 장점 인프라를 코드로 버전 관리 — Git으로 변경 이력 추적 plan으로 적용 전 변경사항 확인 → 실수 방지 같은 코드로 dev/prod 환경 복제 모듈화로 재사용 — VPC 모듈 한 번 만들면 dev·prod 공유 멀티 클라우드 — AWS·GCP·Azure 동일 문법 의존성 자동 해결 — 서브넷 전에 VPC부터 생성 단점 State 파일 관리 필요 — 분실·충돌 시 위험 콘솔에서 수동 변경하면 drift 발생(코드와 실제가 어긋남) 학습 곡선 — HCL 문법, 모듈 구조 이해 필요 일부 리소스는 삭제 후 재생성 → downtime 가능 민감정보(비밀번호) 관리에 주의 필요 drift(드리프트)란 코드에 적힌 상태와 실제 클라우드 상태가 달라진 것을 말한다. 누군가 콘솔에서 손으로 바꾸면 생긴다. 7장 협업 규칙이 이걸 막기 위한 것이다. 4. 기본 문법 한눈에 Terraform은 HCL(HashiCorp Configuration Language)이라는 문법을 쓴다. 자주 쓰는 7가지 블록만 알면 대부분 읽힌다. 41. Provider — 어떤 클라우드를 쓸지 선언 hcl terraform { requiredproviders { aws = { source = "hashicorp/aws" version = " 5.0" } } } provider "aws" { region = "apnortheast2" 서울 리전 } 42. Resource — 실제로 만들 자원 hcl resource "awsinstance" "web" { ami = "ami0c55b159cbfafe1f0" instancetype = "t3.micro" tags = { Name = "mywebserver" } } 구조는 항상 resource "리소스타입" "이름" { 설정값 } 형태다. 43. Variable — 값을 바깥에서 주입 hcl 변수 선언 (variables.tf) variable "dbpassword" { type = string sensitive = true plan 출력 시 마스킹 } 변수 사용 resource "awsdbinstance" "main" { password = var.dbpassword } 실제 값은 terraform.tfvars에 적는다 — dbpassword = "mysecretpassword" 44. Output — 결과값 꺼내기 hcl output "albdnsname" { value = awslb.main.dnsname } apply 후 값을 출력하고, 다른 모듈에서 참조할 수도 있다. 45. Module — 재사용 가능한 코드 묶음 hcl module "vpc" { source = "../../modules/vpc" 모듈 경로 env = "dev" region = "apnortheast2" vpccidr = "10.0.0.0/16" } 한 번 정의해두고 dev/prod에서 다른 값만 넣어 재사용한다. 46. Data Source — 기존 리소스 읽어오기 hcl data "awsroute53zone" "main" { name = "farmily.info" } 사용: data.awsroute53zone.main.zoneid Terraform이 만들지 않은 기존 리소스 정보를 가져올 때 쓴다. 47. locals — 반복 표현식 정리 hcl locals { appenvironment = [ { name = "S3BUCKET", value = module.s3.bucketid }, { name = "S3REGION", value = var.region }, ] } 5. 꼭 쓰는 명령어 명령어 설명 terraform init 프로바이더 다운로드, 백엔드 연결 (최초 1회) terraform plan 변경사항 미리보기 (실제 반영 X) terraform apply 실제 인프라에 반영 terraform destroy 모든 리소스 삭제 (주의!) terraform state list 관리 중인 리소스 목록 terraform state show 특정 리소스 상세 정보 terraform fmt 코드 포맷팅 terraform validate 문법 검증 코드 수정 → plan → 변경 확인 → apply → 완료 6. State 관리 — Remote Backend State 파일을 각자 노트북에 두면 팀원끼리 충돌한다. 그래서 S3에 두고 공유한다. 동시에 두 명이 apply하지 못하도록 DynamoDB로 잠금(Lock)을 건다. hcl backend.tf terraform { backend "s3" { bucket = "farmilyterraformstate" key = "prod/terraform.tfstate" region = "apnortheast2" dynamodbtable = "terraformlocks" 동시 수정 방지 (Lock) encrypt = true } } 구성 요소 역할 S3 버킷 State 파일 저장소 DynamoDB 테이블 동시에 apply 못 하게 Lock encrypt 저장 시 암호화 7. 팀 협업 방식 브랜치 전략 main (운영 반영 코드) └── featxxx (작업 브랜치) → PR 생성 → 리뷰 → main 머지 → apply 협업 규칙 1. 콘솔에서 직접 수정 금지 — 코드와 실제가 어긋남(drift) 2. main에 직접 커밋 금지 — PR로만 머지 3. plan 결과를 PR에 공유 — 뭐가 바뀌는지 팀원이 확인 4. tfvars는 gitignore — 비밀번호 등 민감정보 보호 5. 모듈 수정은 dev 먼저 테스트 — prod 반영 전 검증 .gitignore 설정 gitignore .terraform/ .tfstate .tfstate.backup .tfplan .terraform.lock.hcl .tfvars !.tfvars.example .DSStore 8. 우리 프로젝트 구조 Desktop/VPC/ ├── environments/ │ ├── dev/ 개발 환경 │ │ ├── main.tf 모듈 호출 (dev 설정) │ │ ├── variables.tf 변수 선언 │ │ ├── backend.tf S3 state 설정 │ │ └── terraform.tfvars 변수 값 (gitignore) │ └── prod/ 운영 환경 │ ├── main.tf │ ├── variables.tf │ ├── backend.tf │ └── terraform.tfvars └── modules/ 재사용 모듈 ├── vpc/ ├── ecs/ ├── rds/ ├── elasticache/ ├── s3/ ├── cloudfront/ ├── cloudwatch/ ├── sg/ ├── acm/ ├── route53/ ├── ecsscheduler/ └── waf/ 환경 분리 방식 같은 모듈을 dev/prod에서 다른 파라미터로 호출하는 게 핵심이다. hcl dev: NAT 1개, RDS 소규모, Replica 없음 module "vpc" { source = "../../modules/vpc" enablemultinat = false } prod: NAT 2개, RDS MultiAZ, Replica 있음 module "vpc" { source = "../../modules/vpc" enablemultinat = true } 9. 실제 정의된 AWS 리소스 Prod 환경 — 84개 리소스 서비스 리소스 설명 VPC VPC, Subnet×4, IGW, NAT×2, Route Table×3, S3 Endpoint 네트워크 기반 ECS Fargate Cluster, Task Definition, Service, ALB, Listener(HTTP+HTTPS), Target Group, Auto Scaling 백엔드 컨테이너 RDS PostgreSQL(MultiAZ) + Read Replica, Subnet Group, Monitoring Role 데이터베이스 ElastiCache Redis Replication Group(노드 2개), Subnet Group 캐시 S3 s3bucket, prodfrontendweb, templates 저장소 3개 CloudFront 프론트엔드 CDN + 이미지 CDN(OAC) 정적 배포 Route53 api → ALB, 루트 → CF, www → CF DNS ACM ALB용(서울) + CloudFront용(버지니아) SSL 인증서 WAF Web ACL + Rate Limit + AWS Managed Rules L7 보안 CloudWatch ECS CPU/Mem 알람, RDS CPU 알람, SNS Topic 모니터링 Security Group ALB, ECS, RDS, Redis, Lambda, Noti Lambda, AgentCore (7개) 접근 제어 IAM ECS Execution/Task Role, S3 정책, Secrets Manager 정책 권한 Dev 환경 — 65개 리소스 (Prod 대비 차이) 서비스 Prod과의 차이 VPC NAT 1개 (비용 절감) ECS Scheduler로 평일 09–18시만 운영 RDS SingleAZ, Replica 없음 ElastiCache 노드 1개 S3 1개만 (devs3bucket) CloudFront / WAF 없음 Route53 api.dev.farmily.info → ALB 10. 실제 코드 예시 VPC 모듈 — modules/vpc/main.tf hcl resource "awsvpc" "main" { cidrblock = var.vpccidr enablednssupport = true enablednshostnames = true tags = { Name = "${var.env}vpc" } } resource "awssubnet" "publica" { vpcid = awsvpc.main.id cidrblock = var.publicsubnetacidr availabilityzone = "${var.region}a" mappubliciponlaunch = true tags = { Name = "${var.env}publicsubneta" } } 모듈 호출 — environments/prod/main.tf hcl module "ecs" { source = "../../modules/ecs" env = "prod" region = var.region vpcid = module.vpc.vpcid VPC 모듈의 출력값 참조 privatesubnetids = [module.vpc.privatesubnetaid, module.vpc.privatesubnetcid] containerimage = var.containerimage desiredcount = 1 maxcount = 8 taskcpu = "512" taskmemory = "1024" enablehttps = true albcertificatearn = module.acmalb.certificatearn } 민감정보 관리 — Secrets Manager 연동 비밀번호를 코드에 적지 않고, Secrets Manager에서 ECS 컨테이너로 직접 주입한다. hcl data "awssecretsmanagersecret" "app" { name = "farmily/prod/app" } locals { appsecrets = [for k in ["DBPASSWORD", "JWTSECRET", "KAKAOCLIENTSECRET"] : { name = k valueFrom = "${data.awssecretsmanagersecret.app.arn}:${k}::" }] } 11. 전체 아키텍처 요청이 들어와서 데이터까지 닿는 전체 흐름이다. 위에서 아래로 읽으면 된다. mermaid flowchart TD Internet([Internet]) R53["Route 53farmily.info · api.farmily.info"] CF["CloudFront정적 웹 CDN"] ALB["ALBHTTPS · L7"] WAF[["WAF"]] S3F["S3frontend 정적 호스팅"] ECS["ECS FargateSpring Boot 컨테이너"] RDS[("RDSPostgreSQL")] REDIS[("ElastiCacheRedis")] S3I["S3이미지"] Internet R53 R53 CF R53 ALB WAF .보호. ALB CF S3F ALB ECS ECS RDS ECS REDIS ECS S3I Route 53(DNS)가 트래픽을 둘로 나눠 — 정적 웹은 CloudFront·S3로, API는 WAF를 거친 ALB·ECS로 보낸다. ECS는 다시 RDS·Redis·S3 세 데이터 계층과 통신한다. 12. 주의사항 실수하기 쉬운 지점 prod에서 terraform destroy 절대 금지 — 모든 리소스가 삭제된다. apply 전 항상 plan 확인 — 뭐가 바뀌는지 반드시 눈으로 체크. 콘솔 수정 후엔 terraform import — 코드에 반영해야 drift를 막는다. tfvars는 절대 git에 올리지 않기 — 비밀번호 노출 사고로 이어진다. 모듈 수정은 영향 범위 확인 — 모듈 하나 바꾸면 dev·prod 둘 다 영향. CI/CD가 바꾸는 값은 lifecycle 블록으로 무시하게 둔다. hcl lifecycle { ignorechanges = [taskdefinition] CI/CD가 이미지 태그 바꾸는 건 무시 }

Jun 17, 2026Terraform
Terraform로 다루는 클라우드 인프라