FinOps 원칙과 플랫폼 통합, Backstage 비용 대시보드, 태그 기반 비용 할당, 리소스 생성 시점의 비용 예측, 그리고 AI 기반 비용 최적화를 다룹니다.
**FinOps(Financial Operations, 클라우드 재무 운영)**는 클라우드 비용에 대한 재무적 책임을 조직 전체에 분산하는 운영 모델입니다. "누가 얼마나 쓰는지 모르겠다"에서 "모든 팀이 자신의 비용을 알고 최적화한다"로 전환하는 것이 목표입니다.
| 원칙 | 설명 | 플랫폼 통합 방법 |
|---|---|---|
| Inform | 비용 데이터를 수집하고 모든 이해관계자에게 공유 | Backstage 비용 대시보드 |
| Optimize | 비용 절감 기회를 식별하고 실행 | 리소스 최적화 추천, AI 분석 |
| Operate | 비용 관리를 일상 업무에 내재화 | 예산 알림, 리소스 생성 시 비용 예측 |
기존에 FinOps는 재무팀이나 클라우드 팀의 영역이었습니다. 하지만 비용 결정은 개발자가 리소스를 선택하는 시점에 이루어집니다. "db.r6g.xlarge와 db.r6g.2xlarge 중 어떤 것을 선택할지"를 결정하는 사람은 개발자입니다. 그래서 비용 정보를 개발자가 결정하는 시점에 제공해야 합니다.
2026년 기준, 94%의 Platform Engineering 조직이 FinOps를 플랫폼의 핵심 기능으로 인식하고 있습니다. 비용 가시성은 더 이상 선택이 아닌 필수입니다.
비용 정보를 효과적으로 전달하려면 개발자가 결정하는 시점에 제공해야 합니다.
1. 리소스 생성 시점
Backstage Scaffolder에서 리소스를 생성할 때 예상 비용을 표시합니다.
import React from 'react';
import { Typography, Card, CardContent } from '@material-ui/core';
interface CostEstimateProps {
database: string;
size: string;
environment: string;
}
function CostEstimate({
database,
size,
environment,
}: CostEstimateProps) {
const estimates: Record<string, Record<string, number>> = {
postgresql: { small: 25, medium: 95, large: 380 },
mysql: { small: 22, medium: 88, large: 350 },
};
const monthlyCost = estimates[database]?.[size] ?? 0;
const environmentMultiplier =
environment === 'production' ? 2.5 : 1.0; // production은 Multi-AZ
const totalMonthlyCost = monthlyCost * environmentMultiplier;
return (
<Card variant="outlined">
<CardContent>
<Typography variant="h6">예상 월 비용</Typography>
<Typography variant="h4">
${totalMonthlyCost.toFixed(0)} USD / 월
</Typography>
<Typography variant="body2" color="textSecondary">
{database} ({size}) - {environment}
{environment === 'production' && ' (Multi-AZ 포함)'}
</Typography>
</CardContent>
</Card>
);
}
export { CostEstimate };2. Pull Request 시점
인프라 코드 변경이 포함된 PR에 비용 변동을 자동으로 코멘트합니다.
name: Infracost
on:
pull_request:
paths:
- "terraform/**"
- "crossplane/**"
jobs:
infracost:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Infracost
uses: infracost/actions/setup@v3
with:
api-key: ${{ secrets.INFRACOST_API_KEY }}
- name: Generate cost diff
run: |
infracost diff \
--path=terraform/ \
--format=json \
--out-file=/tmp/infracost.json
- name: Post PR comment
uses: infracost/actions/comment@v3
with:
path: /tmp/infracost.json
behavior: update3. 일상 모니터링
Backstage 대시보드에서 서비스별 비용 추이를 확인합니다.
Backstage의 Cost Insights 플러그인을 활용하거나 커스텀 플러그인을 개발하여 비용 대시보드를 제공합니다.
import { CostInsightsPage } from '@backstage/plugin-cost-insights';
// App 라우트에 추가
<Route path="/cost-insights" element={<CostInsightsPage />} />Cost Insights 플러그인은 비용 데이터를 제공하는 백엔드 구현이 필요합니다.
import {
CostInsightsApi,
Alert,
Cost,
Group,
MetricData,
Project,
} from '@backstage/plugin-cost-insights-common';
export class MyCostInsightsClient implements CostInsightsApi {
async getLastCompleteBillingDate(): Promise<string> {
// 가장 최근 완료된 청구 날짜 반환
const today = new Date();
today.setDate(today.getDate() - 1);
return today.toISOString().split('T')[0];
}
async getUserGroups(userId: string): Promise<Group[]> {
// 사용자가 속한 팀/그룹 반환
const response = await fetch(
`${this.baseUrl}/api/groups?userId=${userId}`,
);
return response.json();
}
async getGroupDailyCost(
group: string,
intervals: string,
): Promise<Cost> {
// 팀별 일일 비용 데이터 반환
const response = await fetch(
`${this.baseUrl}/api/costs/daily?group=${group}&intervals=${intervals}`,
);
return response.json();
}
async getProjectDailyCost(
project: string,
intervals: string,
): Promise<Cost> {
// 서비스(프로젝트)별 일일 비용 데이터 반환
const response = await fetch(
`${this.baseUrl}/api/costs/daily?project=${project}&intervals=${intervals}`,
);
return response.json();
}
async getDailyMetricData(
metric: string,
intervals: string,
): Promise<MetricData> {
const response = await fetch(
`${this.baseUrl}/api/metrics/daily?metric=${metric}&intervals=${intervals}`,
);
return response.json();
}
async getAlerts(group: string): Promise<Alert[]> {
// 비용 관련 알림 반환
const response = await fetch(
`${this.baseUrl}/api/alerts?group=${group}`,
);
return response.json();
}
}정확한 비용 할당을 위해 모든 클라우드 리소스에 일관된 태그를 적용합니다.
required_tags:
- key: "team"
description: "리소스를 소유하는 팀"
example: "checkout-team"
source: "catalog-info.yaml의 spec.owner"
- key: "service"
description: "리소스가 속한 서비스"
example: "checkout-service"
source: "catalog-info.yaml의 metadata.name"
- key: "environment"
description: "배포 환경"
example: "production"
allowed_values: ["dev", "staging", "production"]
- key: "cost-center"
description: "비용 센터 코드"
example: "CC-001"
source: "팀 메타데이터에서 자동 매핑"
- key: "managed-by"
description: "리소스 관리 도구"
example: "crossplane"
allowed_values: ["terraform", "crossplane", "manual"]
optional_tags:
- key: "project"
description: "프로젝트 또는 이니셔티브"
example: "checkout-v2-migration"
- key: "ttl"
description: "리소스 만료 시간 (dev 환경용)"
example: "72h"플랫폼에서 생성되는 모든 리소스에 태그를 자동으로 적용합니다.
locals {
common_tags = {
team = var.team
service = var.service_name
environment = var.environment
cost-center = var.cost_center
managed-by = "terraform"
created-at = timestamp()
created-by = var.created_by
}
}
# 모든 리소스에 공통 태그 적용
resource "aws_db_instance" "main" {
# ... 설정 ...
tags = merge(local.common_tags, {
resource-type = "database"
})
}
resource "aws_elasticache_cluster" "main" {
# ... 설정 ...
tags = merge(local.common_tags, {
resource-type = "cache"
})
}태그가 누락된 리소스를 자동으로 탐지하고 알림을 발송합니다.
import boto3
from typing import Any
REQUIRED_TAGS = ['team', 'service', 'environment', 'cost-center', 'managed-by']
def check_tag_compliance(resource: dict[str, Any]) -> list[str]:
"""리소스의 태그 컴플라이언스를 검사합니다."""
existing_tags = {
tag['Key']: tag['Value']
for tag in resource.get('Tags', [])
}
missing_tags = [
tag for tag in REQUIRED_TAGS
if tag not in existing_tags
]
return missing_tags
def scan_rds_instances() -> list[dict[str, Any]]:
"""RDS 인스턴스의 태그 컴플라이언스를 스캔합니다."""
rds = boto3.client('rds', region_name='ap-northeast-2')
instances = rds.describe_db_instances()
non_compliant = []
for instance in instances['DBInstances']:
arn = instance['DBInstanceArn']
tags_response = rds.list_tags_for_resource(ResourceName=arn)
instance['Tags'] = tags_response['TagList']
missing = check_tag_compliance(instance)
if missing:
non_compliant.append({
'resource_id': instance['DBInstanceIdentifier'],
'resource_type': 'RDS',
'missing_tags': missing,
})
return non_compliant태그 기반 비용 할당은 태그가 100% 적용되었을 때만 정확합니다. 태그가 누락된 리소스가 있으면 "미할당 비용"이 발생하여 비용 분석의 신뢰성이 떨어집니다. 자동 태깅과 컴플라이언스 검증을 반드시 병행하세요.
팀별, 서비스별 예산을 설정하고 초과 시 알림을 발송합니다.
budgets:
- name: "checkout-team-monthly"
team: checkout-team
period: monthly
amount: 5000 # USD
alerts:
- threshold: 50 # 50% 도달 시
channels: ["slack:checkout-team-alerts"]
severity: info
- threshold: 80 # 80% 도달 시
channels: ["slack:checkout-team-alerts", "email:team-lead"]
severity: warning
- threshold: 100 # 100% 도달 시
channels: ["slack:checkout-team-alerts", "email:team-lead", "email:cto"]
severity: critical
- name: "dev-environment-total"
scope: environment:dev
period: monthly
amount: 10000 # USD
alerts:
- threshold: 90
channels: ["slack:platform-team"]
severity: warning개발자가 리소스를 생성할 때 즉시 비용을 예측하여 보여줍니다.
interface CostEstimateInput {
template: string;
database?: string;
messaging?: string;
environment?: string;
}
interface CostEstimateResult {
monthly: number;
breakdown: CostBreakdownItem[];
comparison: string;
}
interface CostBreakdownItem {
resource: string;
monthlyCost: number;
}
const COST_TABLE: Record<string, Record<string, number>> = {
compute: {
'spring-boot': 45, // EKS Pod (0.5 vCPU, 1Gi) x 2 replicas
'go-grpc': 30, // EKS Pod (0.25 vCPU, 512Mi) x 2 replicas
'fastapi': 35, // EKS Pod (0.25 vCPU, 512Mi) x 2 replicas
'nextjs': 20, // EKS Pod (0.25 vCPU, 256Mi) x 2 replicas
},
database: {
postgresql_small: 25,
postgresql_medium: 95,
postgresql_large: 380,
mysql_small: 22,
mysql_medium: 88,
mysql_large: 350,
},
messaging: {
kafka: 150,
rabbitmq: 45,
},
};
export class CostEstimator {
static async estimate(input: CostEstimateInput): Promise<CostEstimateResult> {
const breakdown: CostBreakdownItem[] = [];
// 컴퓨트 비용
const computeCost = COST_TABLE.compute[input.template] ?? 40;
breakdown.push({ resource: 'Compute (EKS)', monthlyCost: computeCost });
// 데이터베이스 비용
if (input.database && input.database !== 'none') {
const dbKey = `${input.database}_small`;
const dbCost = COST_TABLE.database[dbKey] ?? 0;
breakdown.push({ resource: `Database (${input.database})`, monthlyCost: dbCost });
}
// 메시징 비용
if (input.messaging && input.messaging !== 'none') {
const msgCost = COST_TABLE.messaging[input.messaging] ?? 0;
breakdown.push({ resource: `Messaging (${input.messaging})`, monthlyCost: msgCost });
}
// CI/CD, 모니터링 등 공통 비용
breakdown.push({ resource: 'CI/CD + Monitoring', monthlyCost: 15 });
const monthly = breakdown.reduce((sum, item) => sum + item.monthlyCost, 0);
return {
monthly,
breakdown,
comparison: `팀 월 예산의 ${((monthly / 5000) * 100).toFixed(1)}%에 해당합니다.`,
};
}
}Platform Engineering에서 활용할 수 있는 주요 FinOps 도구를 비교합니다.
| 도구 | 유형 | 주요 기능 | 적합한 환경 |
|---|---|---|---|
| Kubecost | Kubernetes 비용 | 네임스페이스/워크로드별 비용, 최적화 추천 | K8s 중심 환경 |
| OpenCost | Kubernetes 비용 (오픈소스) | Kubecost의 오픈소스 코어, CNCF 프로젝트 | K8s + 비용 절약 |
| Infracost | IaC 비용 예측 | Terraform PR 비용 코멘트 | GitOps 환경 |
| CAST AI | AI 기반 최적화 | 자동 리소스 최적화, 스팟 인스턴스 관리 | 대규모 K8s |
# Kubecost Helm 설치 설정
kubecostProductConfigs:
clusterName: "production-cluster"
defaultModelPricing:
enabled: true
CPU: "0.031611" # ap-northeast-2 m6i.large 기준
RAM: "0.004237"
GPU: "0.95"
storage: "0.000127"
labelMappingConfigs:
enabled: true
team_label: "team"
service_label: "service"
environment_label: "environment"
# Backstage 연동을 위한 API 노출
service:
type: ClusterIP
port: 9090AI를 활용한 비용 최적화는 2026년 Platform Engineering의 핵심 트렌드입니다.
optimization_rules:
- name: "유휴 리소스 감지"
description: "72시간 이상 CPU 사용률 5% 미만인 워크로드 탐지"
action: "스케일 다운 또는 제거 추천"
automation: semi-auto # 추천 후 수동 승인
- name: "오버프로비저닝 감지"
description: "실제 사용량 대비 2배 이상 할당된 리소스 탐지"
action: "리소스 리밋 조정 추천"
automation: semi-auto
- name: "스팟 인스턴스 전환"
description: "Stateless 워크로드를 스팟 인스턴스로 전환"
action: "dev/staging 환경 자동 전환"
automation: auto # dev/staging만 자동
- name: "비용 이상 탐지"
description: "전주 대비 30% 이상 비용 증가 서비스 탐지"
action: "팀 리드에게 알림"
automation: auto비용 최적화의 가장 큰 효과는 "오버프로비저닝 제거"에서 나옵니다. 대부분의 조직에서 Kubernetes 워크로드의 리소스 요청은 실제 사용량의 2-5배에 달합니다. 이를 적정 수준으로 조정하는 것만으로도 30-50%의 비용 절감이 가능합니다.
이번 장에서는 FinOps를 Platform Engineering에 통합하는 방법을 다루었습니다.
다음 장에서는 조직 확장과 플랫폼 팀 운영을 다룹니다. 플랫폼 팀의 구조, Team Topologies 적용, 개발자 만족도 측정, 그리고 플랫폼 성숙도 모델을 살펴보겠습니다.
이 글이 도움이 되셨나요?
플랫폼 팀의 구조와 Team Topologies 적용, 채택률 측정과 개선, 개발자 만족도(NPS), 이해관계자 관리, 그리고 플랫폼 성숙도 모델을 다룹니다.
Platform as a Product 관점에서의 API 계층 설계, 추상화 수준 결정, 내부 API 버전닝, 인증과 인가, 감사 로깅, 그리고 CLI 도구 제공까지 다룹니다.
Backstage, ArgoCD, Crossplane으로 엔드투엔드 IDP를 구축하는 실전 프로젝트. Golden Path 작성, 셀프서비스 워크플로우, 비용 가시성 통합까지 전 과정을 다룹니다.