☁️ 클라우드

CloudFormation

AWS CloudFormation

AWS IaC 서비스. YAML/JSON으로 인프라 정의. 스택 단위로 리소스 관리.

📖 상세 설명

AWS CloudFormation은 AWS의 대표적인 Infrastructure as Code(IaC) 서비스로, YAML 또는 JSON 형식의 템플릿 파일을 사용하여 AWS 리소스를 선언적으로 정의하고 프로비저닝합니다.

CloudFormation의 핵심 개념은 스택(Stack)입니다. 스택은 하나의 템플릿으로 생성된 AWS 리소스 집합을 의미하며, VPC, EC2, RDS, Lambda 등 1,000개 이상의 AWS 서비스 리소스를 단일 스택으로 관리할 수 있습니다.

주요 특징:

💻 코드 예제

# vpc-stack.yaml - VPC와 EC2 인스턴스 생성 템플릿
AWSTemplateFormatVersion: '2010-09-09'
Description: Production VPC with EC2 instance

Parameters:
  Environment:
    Type: String
    Default: production
    AllowedValues:
      - production
      - staging
      - development
  InstanceType:
    Type: String
    Default: t3.medium
    Description: EC2 instance type

Resources:
  # VPC 생성
  MainVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub ${Environment}-vpc
        - Key: Environment
          Value: !Ref Environment

  # Public Subnet
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MainVPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub ${Environment}-public-subnet

  # Internet Gateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub ${Environment}-igw

  # EC2 Instance
  WebServer:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: ami-0c55b159cbfafe1f0
      SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: !Sub ${Environment}-web-server

Outputs:
  VPCId:
    Description: VPC ID
    Value: !Ref MainVPC
    Export:
      Name: !Sub ${Environment}-VPCId
  WebServerPublicIP:
    Description: Public IP of web server
    Value: !GetAtt WebServer.PublicIp
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "S3 Bucket with versioning and lifecycle",

  "Parameters": {
    "BucketName": {
      "Type": "String",
      "Description": "Name of the S3 bucket"
    },
    "RetentionDays": {
      "Type": "Number",
      "Default": 90,
      "Description": "Days to retain objects"
    }
  },

  "Resources": {
    "DataBucket": {
      "Type": "AWS::S3::Bucket",
      "DeletionPolicy": "Retain",
      "Properties": {
        "BucketName": { "Ref": "BucketName" },
        "VersioningConfiguration": {
          "Status": "Enabled"
        },
        "LifecycleConfiguration": {
          "Rules": [
            {
              "Id": "ArchiveOldVersions",
              "Status": "Enabled",
              "NoncurrentVersionTransitions": [
                {
                  "StorageClass": "GLACIER",
                  "TransitionInDays": 30
                }
              ],
              "NoncurrentVersionExpiration": {
                "NoncurrentDays": { "Ref": "RetentionDays" }
              }
            }
          ]
        },
        "PublicAccessBlockConfiguration": {
          "BlockPublicAcls": true,
          "BlockPublicPolicy": true,
          "IgnorePublicAcls": true,
          "RestrictPublicBuckets": true
        }
      }
    }
  },

  "Outputs": {
    "BucketArn": {
      "Description": "S3 Bucket ARN",
      "Value": { "Fn::GetAtt": ["DataBucket", "Arn"] }
    }
  }
}
# 스택 생성
aws cloudformation create-stack \
  --stack-name production-vpc-stack \
  --template-body file://vpc-stack.yaml \
  --parameters \
    ParameterKey=Environment,ParameterValue=production \
    ParameterKey=InstanceType,ParameterValue=t3.large \
  --capabilities CAPABILITY_IAM \
  --tags Key=Project,Value=MainApp

# 스택 생성 완료 대기
aws cloudformation wait stack-create-complete \
  --stack-name production-vpc-stack

# 변경 세트 생성 (업데이트 미리보기)
aws cloudformation create-change-set \
  --stack-name production-vpc-stack \
  --change-set-name update-instance-type \
  --template-body file://vpc-stack-updated.yaml \
  --parameters \
    ParameterKey=InstanceType,ParameterValue=t3.xlarge

# 변경 세트 확인
aws cloudformation describe-change-set \
  --stack-name production-vpc-stack \
  --change-set-name update-instance-type

# 변경 세트 실행 (실제 업데이트)
aws cloudformation execute-change-set \
  --stack-name production-vpc-stack \
  --change-set-name update-instance-type

# 드리프트 감지 시작
aws cloudformation detect-stack-drift \
  --stack-name production-vpc-stack

# 드리프트 상태 확인
aws cloudformation describe-stack-drift-detection-status \
  --stack-drift-detection-id abc12345-1234-1234-1234-abc123456789

# 스택 삭제
aws cloudformation delete-stack \
  --stack-name production-vpc-stack

🗣️ 실무에서 이렇게 말하세요

인프라 설계 회의에서
"이번 마이크로서비스 인프라는 CloudFormation으로 관리하려고 합니다. 중첩 스택으로 네트워크, 컴퓨트, 데이터베이스 레이어를 분리하면 각 팀이 독립적으로 템플릿을 관리할 수 있어요. 크로스 스택 레퍼런스로 VPC ID나 서브넷 정보를 공유하면 됩니다."
면접에서 IaC 경험 질문에
"CloudFormation으로 30개 이상의 스택을 관리한 경험이 있습니다. 특히 변경 세트를 활용해서 프로덕션 배포 전 항상 리소스 변경 내역을 검토했고, 실수로 콘솔에서 수정된 리소스는 드리프트 감지로 찾아서 템플릿과 동기화했습니다."
장애 대응 회의에서
"어제 배포 중 RDS 인스턴스 타입 변경이 실패해서 자동 롤백되었습니다. UpdateReplacePolicy가 Delete로 되어 있어서 스냅샷 없이 교체를 시도했던 게 원인이에요. Retain으로 변경하고 수동 스냅샷 후에 재배포하겠습니다."

⚠️ 흔한 실수 & 주의사항

하드코딩된 리소스 이름

S3 버킷이나 IAM 역할 이름을 하드코딩하면 동일 템플릿으로 여러 환경을 생성할 수 없습니다. Parameters와 !Sub 함수를 사용하세요: !Sub ${Environment}-data-bucket

DeletionPolicy 미설정

RDS, S3, DynamoDB 등 데이터 리소스에 DeletionPolicy를 설정하지 않으면 스택 삭제 시 데이터가 영구 손실됩니다. 프로덕션에서는 반드시 DeletionPolicy: Retain 또는 Snapshot을 설정하세요.

올바른 방법: 변경 세트 활용

프로덕션 스택 업데이트 전 반드시 변경 세트를 생성하여 어떤 리소스가 추가/수정/삭제되는지 검토하세요. 특히 Replacement가 발생하는 변경은 다운타임을 유발할 수 있으므로 주의가 필요합니다.

🔗 관련 용어

📚 더 배우기