7월 17일, AWS Cost Explorer가 일부 고객에게 수백만, 수십억, 몇몇 스크린샷에서는 수조 달러의 예상 청구액을 표시했다. 숫자는 잘못된 것이었고, 실제로 청구된 사람은 없었으며, AWS는 하루 안에 데이터를 바로잡았다. 기억해 둘 만한 대목은 따로 있다. 이 이상을 가장 먼저 알아챈 사람들은 빌링 알림을 설정해 둔 쪽이었다. 이 글은 Terraform의 aws_budgets_budget으로 그 알림을 설정하는 101 가이드다. 단순한 월간 비용 알림부터 사용량 예산, Savings Plan 사용률 추적까지 다룬다.

그날 아침 LinkedIn이나 X를 연 사람이라면 누구나 같은 피드를 봤다. 웬만한 국가 예산보다 자릿수가 많은 AWS 청구 예상액 스크린샷들이었다. 전달에 0.19달러를 낸 어느 사용자는 25억 달러에 가까운 예상액을 봤고, 2조 5천억 달러까지 찍힌 숫자를 올린 사람들도 있었다.

무슨 일이 있었나

태평양 시간 새벽 1시 33분, AWS는 Health Dashboard에 Cost Explorer가 "reflecting inaccurate estimated billing data", 즉 부정확한 예상 청구 데이터를 표시하고 있다고 공지했다. AWS가 밝힌 근본 원인은 "an issue with unit pricing within the estimated billing computation subsystem", 예상 청구액 계산 서브시스템의 단가 처리 문제였다. 요약하면:

  • 문제의 숫자는 예상치였고, 실제 사용량이나 청구액이 아니었다.
  • 실제로 청구된 사람은 없었고, 고객이 취해야 할 조치도 없었다.
  • AWS가 데이터를 다시 채워 넣었고, 7월 18일에는 숫자가 정상으로 돌아왔다.

흥미로운 부분은 여기다. 많은 사람이 이 버그를 빌링 임계값 초과 이메일로 처음 알았다. 알림을 설정해 둔 계정은 몇 분 안에 이상을 잡아냈다. 알림이 없던 계정은 소셜 미디어를 통해 알았거나, 아예 모르고 지나갔다.

이번 건은 오탐이었다. 하지만 지우는 걸 잊은 NAT Gateway, 재시도 루프에 갇힌 Lambda, 유출된 액세스 키가 만드는 청구서는 아주 현실적인 금액이다. 그러니 이번 주야말로 빌링 알림을 설정하기 좋은 때고, 콘솔 클릭이 아니라 코드로 하는 게 맞다.

왜 콘솔이 아니라 IaC인가

콘솔에서 만든 알림은 계정 하나와 한 사람의 기억 속에만 존재한다. Terraform으로 하면:

  • 버전 관리 안에 남는다. 누가 무엇을 언제 바꿨는지 보인다.
  • 새 계정이 생기면? 같은 모듈을 apply 하고 표준을 유지하면 된다.
  • 임계값 변경은 리뷰를 거치는 풀 리퀘스트가 된다.

실제 작업을 하는 리소스는 AWS Budgets를 감싸는 aws_budgets_budget이다.

1. 이메일 알림이 달린 월간 비용 예산

실제 지출이 80%를 넘으면 이메일을 보내는 월 100달러 예산:

resource "aws_budgets_budget" "monthly_cost" {
  name         = "monthly-cost-budget"
  budget_type  = "COST"
  limit_amount = "100"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["ops@example.com"]
  }
}

2. 예측 기반 조기 경보

notification_type = "FORECASTED"를 쓰면 돈이 실제로 나가기 전에, 월말 예측치가 예산을 초과하는 궤도에 올랐을 때 AWS가 미리 경고한다. ACTUAL 알림과 짝지으면 양방향을 모두 커버한다:

resource "aws_budgets_budget" "with_forecast" {
  name         = "monthly-cost-budget"
  budget_type  = "COST"
  limit_amount = "100"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  # 예측치가 예산을 초과할 것 같으면 미리 경고
  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 100
    threshold_type             = "PERCENTAGE"
    notification_type          = "FORECASTED"
    subscriber_email_addresses = ["ops@example.com"]
  }

  # 실제 지출이 90%를 넘으면 다시 경고
  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 90
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["ops@example.com"]
  }
}

3. SNS를 거쳐 Slack 또는 PagerDuty로

이메일은 묻히기 마련이다. 알림을 SNS 토픽으로 보내고, 그 토픽을 Slack 웹훅이나 PagerDuty에 연결하자:

resource "aws_sns_topic" "billing_alerts" {
  name = "billing-alerts"
}

resource "aws_budgets_budget" "sns_alert" {
  name         = "monthly-cost-budget-sns"
  budget_type  = "COST"
  limit_amount = "100"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  notification {
    comparison_operator       = "GREATER_THAN"
    threshold                 = 80
    threshold_type            = "PERCENTAGE"
    notification_type         = "ACTUAL"
    subscriber_sns_topic_arns = [aws_sns_topic.billing_alerts.arn]
  }
}

여기서 흔한 실패 지점: 토픽 정책이 budgets.amazonaws.com 서비스 프린시펄에 SNS:Publish 권한을 부여해야 한다. 없으면 Budgets가 전송하지 못하고 알림은 소리 없이 사라진다. 예산 쪽에는 아무 에러도 뜨지 않는다.

4. 서비스별 예산

특정 서비스 하나만, 예를 들어 EC2만 보고 싶다면 cost_filter를 추가한다:

resource "aws_budgets_budget" "ec2_only" {
  name         = "ec2-monthly-budget"
  budget_type  = "COST"
  limit_amount = "50"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  cost_filter {
    name   = "Service"
    values = ["Amazon Elastic Compute Cloud - Compute"]
  }

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["ops@example.com"]
  }
}

5. 사용량 예산: S3 3GB

FinOps는 달러만 추적하는 일이 아니다. 소비량 추적도 업무의 일부다. budget_type = "USAGE"를 쓰면 예산이 통화 대신 사용량 단위로 정의된다. S3 스토리지를 3GB로 제한하는 예산:

resource "aws_budgets_budget" "s3" {
  name         = "s3-3GB-limit"
  budget_type  = "USAGE"
  limit_amount = "3"
  limit_unit   = "GB"
  time_unit    = "MONTHLY"

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["ops@example.com"]
  }
}

프리 티어 안에 머물고 싶은 사이드 프로젝트에 유용하고, "이 버킷이 왜 계속 크지"를 청구서 항목이 되기 전에 잡아내는 데도 좋다.

6. Savings Plan 사용률 예산

FinOps의 나머지 절반: 과지출을 잡는 것만큼, 선불로 산 할인을 낭비하지 않는 것도 중요하다. Savings Plan을 샀는데 사용률이 낮다면, 워크로드는 다른 곳에서 온디맨드로 돌아가는 동안 약정은 돈을 태우고 있는 셈이다. SAVINGS_PLANS_UTILIZATION 예산 타입이 정확히 그것을 추적한다:

resource "aws_budgets_budget" "savings_plan_utilization" {
  name         = "savings-plan-utilization"
  budget_type  = "SAVINGS_PLANS_UTILIZATION"
  limit_amount = "100.0"
  limit_unit   = "PERCENTAGE"
  time_unit    = "MONTHLY"

  cost_types {
    include_credit             = false
    include_discount           = false
    include_other_subscription = false
    include_recurring          = false
    include_refund             = false
    include_subscription       = true
    include_support            = false
    include_tax                = false
    include_upfront            = false
    use_blended                = false
  }

  notification {
    comparison_operator        = "LESS_THAN"
    threshold                  = 90
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["finops@example.com"]
  }
}

연산자가 뒤집혀 있다는 점에 주목하자. comparison_operator = "LESS_THAN"이다. 이 알림은 지출이 올라갈 때가 아니라 사용률이 90% 아래로 떨어질 때 울린다. Reserved Instance에도 RI_UTILIZATION으로 같은 패턴을 쓸 수 있다.

정리

7월 17일의 수조 달러짜리 스크린샷은 표시 버그였다. 그 돈을 낸 사람은 없었고, AWS는 하루 안에 데이터를 바로잡았다. 그래도 교훈은 그대로다. 청구서의 이상은 남의 타임라인이 아니라 내 알림을 통해 나에게 도착해야 한다.

  • aws_budgets_budget으로 월간 예산을 정의한다.
  • FORECASTEDACTUAL 알림을 짝지어 2단계 경보를 만든다.
  • 알림을 SNS를 거쳐 팀이 실제로 보는 채널로 보낸다.
  • 사용량 예산(S3 3GB)과 Savings Plan 사용률 추적으로 그림을 완성한다.

다음에 "AWS 청구서 폭발"이 트렌드에 오르면, 커피를 들고 구경만 하면 된다. 사건 배경 자료로는 The RegisterTechCrunch가 상황이 전개되는 대로 다뤘다.

이어서 읽기

참고 자료