프로비저닝(Provisioning)

도은호·2025년 9월 23일

terraform

목록 보기
17/32
  • 프로비저닝: 서비스를 위해 필요한 **인프라/플랫폼 자원을 ‘준비·할당·생성’**하는 일.
  • 층위: 인프라(IaC)OS/앱 설정(구성관리)배포(Deploy) 는 목적이 다르다.
  • 도구맵: Terraform/CloudFormation/Pulumi(IaC) + cloud-init/Ansible(설정) + Packer(이미지) + Helm(K8s 앱).
  • 베스트프랙티스: 멱등성, 불변 인프라, 비밀관리, 원격 상태, 태깅, plan -out → apply plan.bin.
  • Terraform provisioner는 최후의 수단. 가급적 UserData/이미지/구성관리로.

1) 프로비저닝이란?

  • 목적: 필요한 자원을 원하는 상태로 만들어 놓는 과정
    예) 네트워크(VPC/Subnet/RT), 보안(SG/IAM), 컴퓨트(EC2/ASG), 데이터(RDS/S3) 등.

  • 선언형 vs 절차형

    • 선언형(IaC): “원하는 상태”를 코드로 선언 → 엔진이 차이를 계산(Terraform).
    • 절차형: 쉘 스크립트로 “어떻게”를 직접 기술.
  • 프로비저닝 vs 구성관리 vs 배포

    구분하는 일대표 도구
    프로비저닝VPC/EC2/RDS 등 리소스 생성Terraform, CloudFormation
    구성관리OS/미들웨어 설정/패키지cloud-init(UserData), Ansible
    배포애플리케이션 릴리즈/롤백GitHub Actions, Argo CD, Helm

2) 도구 맵 (언제 무엇을 쓰나)

  • IaC: Terraform(멀티클라우드), CloudFormation(AWS), Pulumi(일반언어 기반).
  • 부팅 스크립트: cloud-init/UserData(EC2가 처음 켤 때 실행).
  • 구성관리: Ansible/Chef(서버 내부 설정을 멱등적으로).
  • 이미지 빌드: Packer(미리 Hardened AMI/Docker 이미지 → 부팅 즉시 준비).
  • Kubernetes: 클러스터 프로비저닝(EKS 등)과 앱 배포(Helm)를 구분.
  • Secrets: AWS Secrets Manager, HashiCorp Vault 등.

3) 프로비저닝 핵심 패턴

  • 멱등성(Idempotency): 같은 코드를 여러 번 적용해도 결과가 같아야 한다.
  • 불변 인프라(Immutable Infra): 인스턴스를 “고쳐 쓰기”보다 새로 만들고 교체.
  • 분리와 인터페이스: 모듈은 입력(variables)과 출력(outputs)만 깔끔히.
  • 원격 상태 & 리뷰: S3(+DynamoDB 락) / plan -out → apply plan.bin.
  • 보안: 비밀은 출력/로그에 마스킹(sensitive), 상태는 암호화/KMS.
  • 태깅/이름 규칙: 비용/운영 가시성 확보.

4) 예제 A — Terraform로 EC2 + cloud-init(유저데이터) 프로비저닝

VPC/서브넷이 있다고 가정. 퍼블릭 서브넷에 Nginx 준비.

# versions.tf
terraform {
  required_version   = "~> 1.9"
  required_providers { aws = { source = "hashicorp/aws", version = "~> 5.0" } }
}
provider "aws" { region = "ap-northeast-2" }

# data & locals
data "aws_ssm_parameter" "al2023" {
  name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"
}
variable "subnet_id" { type = string }
variable "vpc_id"    { type = string }

resource "aws_security_group" "web" {
  name   = "nginx-sg"
  vpc_id = var.vpc_id
  ingress { from_port=80 to_port=80 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"] }
}

# cloud-init(UserData)로 멱등적 설치
locals {
  user_data = <<-YAML
  #cloud-config
  packages:
    - nginx
  runcmd:
    - systemctl enable --now nginx
  YAML
}

resource "aws_instance" "web" {
  ami                         = data.aws_ssm_parameter.al2023.value
  instance_type               = "t3.micro"
  subnet_id                   = var.subnet_id
  vpc_security_group_ids      = [aws_security_group.web.id]
  associate_public_ip_address = true
  user_data                   = local.user_data
  tags = { Name = "web-nginx" }
}

output "web_public_ip" { value = aws_instance.web.public_ip }

명령

terraform init
terraform plan -out=plan.bin
terraform apply plan.bin
# 접속 확인
curl http://$(terraform output -raw web_public_ip)

포인트

  • 소프트웨어 설치는 UserData/cloud-init으로 충분한 범위부터.
  • 더 복잡하면 Ansible(아래 예제) 또는 Packer(AMI 미리 굽기) 고려.

5) 예제 B — Packer로 “골든 AMI” 빌드 → Terraform에서 사용

부팅 즉시 준비된 이미지를 쓰면 배포가 빠르고 일관.

packer.pkr.hcl

packer {
  required_plugins { amazon = { source = "github.com/hashicorp/amazon" } }
}
source "amazon-ebs" "al2023" {
  region        = "ap-northeast-2"
  instance_type = "t3.micro"
  source_ami_filter {
    filters = { name = "al2023-ami-*-x86_64" }
    owners  = ["137112412989"]
    most_recent = true
  }
  ssh_username = "ec2-user"
  ami_name     = "nginx-al2023-{{timestamp}}"
}
build {
  sources = ["source.amazon-ebs.al2023"]
  provisioner "shell" {
    inline = ["sudo dnf -y install nginx", "sudo systemctl enable --now nginx"]
  }
}

사용(개념): Packer가 만든 AMI ID를 Terraform 변수/SSM 파라미터로 참조.


6) 예제 C — Ansible로 서버 내부 구성(멱등적)

# playbook.yml
- hosts: web
  become: yes
  tasks:
    - name: ensure nginx
      ansible.builtin.package:
        name: nginx
        state: present
    - name: start nginx
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: yes

Terraform은 서버(외부) 만들기, Ansible은 서버 안(내부) 설정에 강함.


7) (보너스) Kubernetes에서의 “프로비저닝”

  • 클러스터 프로비저닝: EKS/GKE/AKS(노드·네트워크·IAM 등). → Terraform/eksctl.
  • 스토리지 동적 프로비저닝: StorageClassPVC 생성 시 PV를 자동 할당.
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: data }
spec:
  accessModes: ["ReadWriteOnce"]
  storageClassName: gp2
  resources: { requests: { storage: 5Gi } }
  • 앱 배포: Helm/Kustomize(프로비저닝과 다른 층위!).

8) 베스트 프랙티스 & 안티패턴

해야 할 것

  • required_version, provider 버전 고정 + .terraform.lock.hcl 관리
  • 원격 상태(S3+KMS, DynamoDB 락) + IAM 최소권한
  • 태깅/네이밍 규칙(locals) + outputs로 필요한 값만 공개
  • 항상 plan -out → apply plan.bin, PR에서 리뷰
  • 비밀은 sensitive/Secrets Manager 사용(로그/유저데이터 평문 금지)

피해야 할 것

  • 콘솔 수작업으로 리소스 만들고 나중에 코드에 “맞추려는” 시나리오(드리프트 폭탄)
  • Terraform provisioner(local/remote-exec) 남용(로그에 비밀 노출/재실행 불안정)
  • count 인덱스 흔들림으로 대량 재생성 → for_each + 안정 키 사용

9) 체크리스트

  • 인프라/IaC와 구성/배포를 명확히 분리했는가
  • 멱등성을 보장하는가(UserData/Ansible/Packer)
  • 원격 상태, 암호화, 락 구성이 되어 있는가
  • 태그/네이밍으로 자산·비용 가시성 확보했는가
  • 변경은 plan 리뷰를 통과했는가
  • 비밀/자격증명은 로그/아티팩트에 노출되지 않는가

요약

프로비저닝은 원하는 상태의 인프라를 ‘안전하고 일관되게’ 준비하는 일.
Terraform으로 리소스를 만들고, cloud-init/Ansible/Packer로 내부를 준비하며,
멱등성·불변성·보안을 습관처럼 지키면 된다.

profile
`•.¸¸.•´´¯`••._.• 🎀 𝒸𝓇𝒶𝓏𝓎 𝓅𝓈𝓎𝒸𝒽💞𝓅𝒶𝓉𝒽 🎀 •._.••`¯´´•.¸¸.•`

0개의 댓글