TFAS (TerraForm Addicted School)의 내용을 정리한 글입니다.
심각한 테라폼 중독입니다 - 책으로 스터디를 진행합니다.

| IaC 도구 | 멱등성 | 선언형 | 여러 프로바이더 제공 | 선언적인 관리 언어 |
| 테라폼 | ✅ | ✅ | ✅ | ✅ |
| 앤서블 | ✅ | ❌ | ⚠️* | ❌ |
| AWS CDK | ✅ | ✅ | ❌ | ❌ |
| Pulumi | ✅ | ✅ | ✅ | ❌ |
* 앤서블은 다양한 모듈을 제공하지만, 테라폼에 비해 클라우드 인프라 프로비저닝 프로바이더가 제한적임
선언형 인프라 관리
많은 리소스와 리소스 간 복잡한 연관 관계를 팀 단위로 관리하게 된다면 복잡하다. 그렇기 때문에 명령형 방식으로 생성되는 리소스보다 기대된 상태 정의에 기반하여 멱등성이 보장되는 선언형 IaC 도구를 사용해야 한다.
테라폼은 선언형 IaC 도구로 리소스에 대한 명령이 아닌 리소스의 상태를 선언하는 방식으로 사용한다. 그리고 멱등성을 보장하기 위해 현재 인프라의 프로비저닝 상태를 스캔하여 테라폼 상태로 저장한다. 테라폼 상태를 리소스의 기대 상태와 비교하여 만약 다른 경우 현재 상태를 기대 상태에 맞게 변경하고 새로운 상태로 기존의 테라폼 상태를 갱신한다.
EC2 인스턴스 관리 비교
테라폼으로 EC2 인스턴스를 관리하는 경우
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = "web-server"
}
}
위 코드는 "이러한 상태의 EC2 인스턴스가 존재해야 한다"는 것을 선언한다. 실행 시 테라폼은 현재 상태를 확인하고, 인스턴스가 없으면 생성하고, 이미 존재하면 변경사항이 있는지 확인한 후 필요한 경우만 수정한다.
반면 앤서블의 경우 명령형 관리 방식을 채택한다. 리소스에 기대하는 상태를 선언하는 것이 아닌 기대 상태를 만들기 위한 명령을 작성한다.
앤서블로 동일한 작업을 수행하는 경우
- name: Launch EC2 instance
ec2:
image: ami-0c55b159cbfafe1f0
instance_type: t3.micro
instance_tags:
Name: web-server
wait: yes
앤서블도 멱등성을 제공하지만, "EC2 인스턴스를 실행하라"는 명령을 기술하는 방식이다. 시스템의 규모가 커질수록 리소스 각각의 기대 상태를 통제하는 것은 운영 복잡성이 높아진다.
실제 운영 시나리오 예시
예를 들어, 10개의 EC2 인스턴스와 5개의 RDS, 여러 개의 Security Group과 VPC가 복잡하게 연결된 환경을 생각해 보자.
- 테라폼: 전체 인프라의 기대 상태를 하나의 코드베이스로 관리하고, terraform plan으로 변경사항을 미리 확인할 수 있다. 누군가 콘솔에서 Security Group 규칙을 수동으로 변경했다면, 다음 terraform apply 시 자동으로 코드에 정의된 상태로 되돌린다.
- 앤서블: 각 작업의 실행 순서를 명확히 정의해야 하며, 의존성 관리가 복잡해진다. VPC를 먼저 생성하고, 그 다음 Subnet, 그리고 Security Group 순서로 playbook을 작성해야 한다. 순서가 잘못되면 실패할 수 있다.
다양한 프로바이더
IaC 도구를 사용하여 여러 클라우드의 인프라를 관리하고자 한다. AWS, GCP, Azure, On-Prem 그리고 쿠버네티스나 다양한 인프라 리소스를 사용할 수 있고 외부 서드파티 인프라를 사용할 수도 있다.
테라폼은 인프라로 관리될 수 있는 모든 서비스에 대한 프로바이더를 제공하며, 공식적인 테라폼 프로바이더로 제공된다. 클라우드 프로바이더뿐 아니라, 네트워크 기술에 대한 프로바이더, 구글 워크스페이스, 마이크로소프트 AD 등 정말 다양한 프로바이더를 제공하기 때문에 테라폼으로 관리할 수 있는 인프라의 선택지가 넓어진다. 이는 관리에 대한 용이성이 높다는 의미기도 하다.
프로바이더 범위 비교
테라폼 레지스트리에는 3,000개 이상의 프로바이더가 등록되어 있다:
- 클라우드: AWS, GCP, Azure, Oracle Cloud, Alibaba Cloud
- 인프라: Kubernetes, Docker, VMware, Helm
- SaaS: Datadog, PagerDuty, GitHub, GitLab
- 네트워크: Cloudflare, F5, Palo Alto Networks
- 데이터베이스: MongoDB Atlas, Snowflake
- 보안: Vault, Auth0, Okta
AWS CDK의 경우 AWS의 리소스만 프로바이더로 제공한다. 내부적으로 AWS CloudFormation을 사용하기 때문에 대부분의 관리 가능한 리소스는 AWS에 제한되어 있다.
앤서블도 다양한 모듈을 제공하지만, 주로 구성 관리(Configuration Management)에 특화되어 있어 클라우드 인프라 프로비저닝보다는 서버 설정 관리에 더 적합하다.
쿠버네티스 관리 예시
쿠버네티스 프로바이더를 본다면 테라폼의 경우 쿠버네티스 프로바이더를 통해 쿠버네티스 매니페스트를 정의하고, 매니페스트의 기대 상태를 실제 클러스터에 적용할 수 있다.
resource "kubernetes_deployment" "app" {
metadata {
name = "app"
}
spec {
replicas = 3
selector {
match_labels = {
app = "my-app"
}
}
template {
metadata {
labels = {
app = "my-app"
}
}
spec {
container {
image = "nginx:1.21"
name = "app"
}
}
}
}
}
또한 현재 쿠버네티스 인프라 상태를 테라폼의 상태와 비교하는 등 쿠버네티스 또한 인프라의 하나로 관리를 수행할 수 있다.
하지만 AWS CDK의 경우 람다를 통해서 kubectl을 수행할 수 있도록 하는 lambda-layer-kubectl 콘스트럭트를 사용하는 방식이나, 매니페스트 관리 및 배포를 서로 다른 콘스트럭터에서 하는 등의 한계점과 복잡성이 존재한다.
// AWS CDK에서 쿠버네티스 관리
const cluster = new eks.Cluster(this, 'Cluster', {
// ...
});
// 별도의 람다 레이어를 사용해야 함
const kubectlLayer = new KubectlLayer(this, 'KubectlLayer');
// 매니페스트를 별도로 관리
cluster.addManifest('app', {
// manifest 정의
});
거기에 추가적으로 사용하는 AWS 리소스(Lambda, Lambda Layer) 비용은 덤이다.
선언형 스크립트 언어
선언형 패러다임의 IaC는 관리하는 스크립트 언어 역시 선언적이어야 한다. 기대되는 인프라 상태를 정의하여 안정적으로 인프라를 관리하고 버전 관리를 통해 이력을 파악할 수 있게 된다.
테라폼은 HCL(HashiCorp Configuration Language)이라는 선언형 언어를 사용한다. HCL은 JSON과 유사하면서도 더 읽기 쉽고, 인프라 상태를 명확하게 선언할 수 있도록 설계되었다.
풀루미는 타입스크립트, 파이썬, Go 등의 명령형 스크립트를 사용하는 IaC 도구이다. 이는 흐름제어와 로직처리를 사용자가 직접 작성할 수 있게 되는 것이다.
선언형 vs 명령형 언어 비교
테라폼 (HCL - 선언형)
variable "instance_count" {
default = 3
}
resource "aws_instance" "web" {
count = var.instance_count
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
풀루미 (TypeScript - 명령형)
const instanceCount = 3;
for (let i = 0; i < instanceCount; i++) {
// 런타임에 결정되는 로직
const instanceType = i === 0 ? "t3.small" : "t3.micro";
new aws.ec2.Instance(`web-${i}`, {
ami: "ami-0c55b159cbfafe1f0",
instanceType: instanceType,
});
}
이는 인프라 관리 측면에서 안정적이지 않은 상태를 만들 수 있다. 선언형 IaC를 채택하나 명령형 스크립트와 복잡한 로직이 결합되어 상태 값이나 수가 선언적이지 않은 상황이 된다. 이유는 명령형 스크립트가 존재하면 런타임에 상태 값이 결정되기 때문에 기대되는 리소스의 결과 상태를 알아보기가 어렵다.
실제 문제 시나리오
예를 들어, 다음과 같은 풀루미 코드가 있다고 가정하자.
const currentHour = new Date().getHours();
const isPeakTime = currentHour >= 9 && currentHour <= 18;
const instanceCount = isPeakTime ? 10 : 3;
for (let i = 0; i < instanceCount; i++) {
new aws.ec2.Instance(`web-${i}`, {
// ...
});
}
이 코드는 실행 시간에 따라 다른 수의 인스턴스를 생성한다. Git 히스토리를 보더라도 특정 시점에 몇 개의 인스턴스가 실행 중이었는지 알 수 없다. 따라서 이력을 관리함에 있어 코드만으로 당시 인프라의 상태를 확인하기 어렵게 된다.
반면 테라폼은 아래와 같다.
resource "aws_instance" "web" {
count = 10 # 코드만 봐도 정확히 10개임을 알 수 있음
# ...
}
코드를 보는 것만으로도 정확히 몇 개의 인스턴스가 생성되는지 즉시 파악할 수 있다.
복잡한 인프라의 경우 코드로 인해서 인프라의 문제점을 알아채기 힘들게 되고 런타임시 치명적인 문제가 발생할 수 있다. 예를 들어, 조건문 실수로 프로덕션 데이터베이스가 삭제되거나, 예상과 다른 리전에 리소스가 생성될 수 있다.
'School > TFAS' 카테고리의 다른 글
| [TFAS] 테라폼 기능별 실무 사례 (챕터 6, 7, 8, 9) (1) | 2025.12.01 |
|---|---|
| [TFAS] 챕터 5 테라폼 모듈 & 챕터 10 모듈을 직접 만드는 이유와 만드는 방법 (1) | 2025.11.29 |
| [TFAS] 챕터 4 테라폼 기본 문법 (1) | 2025.11.25 |
| [TFAS] 챕터 3 테라폼 작동 방식 (0) | 2025.11.24 |
| [TFAS] 챕터 1 클라우드와 코드형 인프라 스트럭처 (0) | 2025.11.08 |