DevOps Admin

FinOps e Otimização de Custos em Cloud: Estratégias e Ferramentas na Prática Já leu

O que é FinOps e por que você deve se importar FinOps é a prática de trazer disciplina financeira para a computação em nuvem. A sigla significa "Financial Operations" e representa um framework cultural e operacional onde times de engenharia, finanças e negócios trabalham juntos para otimizar gastos em cloud. Diferente de simplesmente "cortar custos", FinOps busca maximizar o valor entregue por cada real investido em infraestrutura em nuvem. A realidade é que muitas organizações gastam entre 20% a 30% a mais do que precisam em serviços cloud. Isso acontece porque a maioria dos times não tem visibilidade clara de seus gastos, não entende como as instâncias são precificadas, e não há uma cultura de responsabilidade financeira compartilhada. FinOps muda essa dinâmica estabelecendo processos, ferramentas e incentivos para que todos—desde o desenvolvedor até o CFO—pensem em eficiência de custos como parte do dia a dia. Pilares Estratégicos: Visibilidade, Otimização e Governança Visibilidade: Conhecer seus gastos Você não pode otimizar o

O que é FinOps e por que você deve se importar

FinOps é a prática de trazer disciplina financeira para a computação em nuvem. A sigla significa "Financial Operations" e representa um framework cultural e operacional onde times de engenharia, finanças e negócios trabalham juntos para otimizar gastos em cloud. Diferente de simplesmente "cortar custos", FinOps busca maximizar o valor entregue por cada real investido em infraestrutura em nuvem.

A realidade é que muitas organizações gastam entre 20% a 30% a mais do que precisam em serviços cloud. Isso acontece porque a maioria dos times não tem visibilidade clara de seus gastos, não entende como as instâncias são precificadas, e não há uma cultura de responsabilidade financeira compartilhada. FinOps muda essa dinâmica estabelecendo processos, ferramentas e incentivos para que todos—desde o desenvolvedor até o CFO—pensem em eficiência de custos como parte do dia a dia.

Pilares Estratégicos: Visibilidade, Otimização e Governança

Visibilidade: Conhecer seus gastos

Você não pode otimizar o que não consegue medir. O primeiro pilar de qualquer estratégia FinOps é estabelecer visibilidade completa dos gastos em nuvem. Isso significa entender não apenas quanto você gasta no total, mas onde exatamente esse dinheiro está sendo gasto: qual serviço, qual projeto, qual time, qual ambiente (dev, staging, produção).

Na prática, as provedoras cloud (AWS, Azure, GCP) fornecem ferramentas nativas para isso. Na AWS, você tem o AWS Cost Explorer e o AWS Billing Dashboard. No GCP, existe o Cloud Billing. Essas ferramentas permitem criar alertas, análises por tag, e até prever gastos futuros. Além delas, existem ferramentas de terceiros como Kubecost (especializada em Kubernetes), CloudHealth, Infracost e Cloudlytics que oferecem análises mais granulares e integrações com seu workflow de desenvolvimento.

# Exemplo: Script Python para extrair custos da AWS usando boto3
import boto3
from datetime import datetime, timedelta

ce_client = boto3.client('ce', region_name='us-east-1')

def get_daily_costs_by_service(days_back=30):
    """
    Retorna custos diários agrupados por serviço nos últimos N dias
    """
    end_date = datetime.now().date()
    start_date = end_date - timedelta(days=days_back)

    response = ce_client.get_cost_and_usage(
        TimePeriod={
            'Start': start_date.isoformat(),
            'End': end_date.isoformat()
        },
        Granularity='DAILY',
        Metrics=['UnblendedCost'],
        GroupBy=[
            {'Type': 'DIMENSION', 'Key': 'SERVICE'}
        ]
    )

    costs_by_service = {}
    for result in response['ResultsByTime']:
        date = result['TimePeriod']['Start']
        for group in result['Groups']:
            service = group['Keys'][0]
            cost = float(group['Metrics']['UnblendedCost']['Amount'])

            if service not in costs_by_service:
                costs_by_service[service] = {}

            costs_by_service[service][date] = cost

    return costs_by_service

# Uso
costs = get_daily_costs_by_service(days_back=7)
for service, dates in costs.items():
    total = sum(dates.values())
    print(f"{service}: ${total:.2f}")

Otimização: Reduzindo desperdícios

Com visibilidade em mano, você identifica oportunidades de otimização. As mais comuns são: eliminar recursos ociosos, usar instâncias reservadas ou savings plans, rightsizing (usar o tamanho correto de máquina), e otimizar transferências de dados. Uma instância EC2 rodando em produção mas que está 5% utilizada é um desperdício óbvio.

A otimização não é um evento único, é um processo contínuo. Recomenda-se revisar custos semanalmente, identificar padrões, e automatizar as otimizações sempre que possível. Ferramentas como o AWS Trusted Advisor, Compute Optimizer, e Right Sizing Recommendations dão insights automáticos sobre o que pode ser otimizado.

# Exemplo: Identificar instâncias EC2 subutilizadas usando CloudWatch
import boto3
from datetime import datetime, timedelta

ec2_client = boto3.client('ec2', region_name='us-east-1')
cloudwatch_client = boto3.client('cloudwatch', region_name='us-east-1')

def find_underutilized_instances(cpu_threshold=10, days=7):
    """
    Encontra instâncias EC2 com CPU média abaixo de um threshold nos últimos dias
    """
    # Listar todas as instâncias rodando
    response = ec2_client.describe_instances(
        Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]
    )

    underutilized = []
    end_time = datetime.utcnow()
    start_time = end_time - timedelta(days=days)

    for reservation in response['Reservations']:
        for instance in reservation['Instances']:
            instance_id = instance['InstanceId']
            instance_type = instance['InstanceType']

            # Obter métrica de CPU média
            metrics = cloudwatch_client.get_metric_statistics(
                Namespace='AWS/EC2',
                MetricName='CPUUtilization',
                Dimensions=[{'Name': 'InstanceId', 'Value': instance_id}],
                StartTime=start_time,
                EndTime=end_time,
                Period=3600,  # 1 hora
                Statistics=['Average']
            )

            if metrics['Datapoints']:
                avg_cpu = sum(dp['Average'] for dp in metrics['Datapoints']) / len(metrics['Datapoints'])

                if avg_cpu < cpu_threshold:
                    underutilized.append({
                        'instance_id': instance_id,
                        'instance_type': instance_type,
                        'avg_cpu': avg_cpu
                    })

    return underutilized

# Uso
underutilized = find_underutilized_instances(cpu_threshold=10, days=7)
for instance in underutilized:
    print(f"ID: {instance['instance_id']}, Tipo: {instance['instance_type']}, CPU Média: {instance['avg_cpu']:.2f}%")

Governança: Estabelecendo controle

Governança em FinOps significa definir políticas, responsabilidades e processos que garantam que os custos sejam gerenciados adequadamente. Isso inclui: aprovações para provisionamento de recursos, limite de gastos por projeto/time, políticas de naming convention para rastrear recursos, e automated cleanup de recursos não utilizados.

A governança deve equilibrar liberdade de inovação com controle financeiro. Um time de desenvolvimento não pode estar preso a burocracias que o impeçam de escalar rapidamente, mas também não pode provisionar infraestrutura de forma caótica. Ferramentas como AWS Organizations, IAM Policies com Cost Tags, e serviços como Terraform com políticas Sentinel permitem estabelecer guardrails efetivas.

# Exemplo: Terraform com políticas de governança
# Este arquivo define tagging obrigatório e limites em tipos de instância

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

variable "required_tags" {
  description = "Tags obrigatórias em todos os recursos"
  type        = map(string)
  default = {
    Environment = ""
    CostCenter  = ""
    Owner       = ""
    Project     = ""
  }
}

# Variável local para instâncias permitidas (economia: evita tipos muito caros)
locals {
  allowed_instance_types = [
    "t3.micro",
    "t3.small",
    "t3.medium",
    "m5.large",
    "m5.xlarge"
  ]
}

resource "aws_instance" "example" {
  ami                    = "ami-0c55b159cbfafe1f0"
  instance_type          = "t3.micro"

  # Validação: apenas tipos permitidos
  lifecycle {
    precondition {
      condition     = contains(local.allowed_instance_types, self.instance_type)
      error_message = "Instance type ${self.instance_type} não é permitido por política de governança."
    }
  }

  # Tags obrigatórias
  tags = merge(
    var.required_tags,
    {
      Name             = "web-server-01"
      LaunchDate       = timestamp()
      ManagedBy        = "terraform"
    }
  )
}

# Output mostrando o custo estimado (informativo)
output "instance_details" {
  value = {
    id            = aws_instance.example.id
    instance_type = aws_instance.example.instance_type
    tags          = aws_instance.example.tags
  }
}

Estratégias Práticas de Redução de Custos

Instâncias Reservadas e Savings Plans

Servidores em nuvem são precificados sob demanda por padrão: você paga por hora de uso. Se você sabe que uma aplicação rodará por 12 meses, comprar uma Reserved Instance (RI) ou Savings Plan oferece desconto de até 70% comparado ao preço sob demanda. A desvantagem é o comprometimento antecipado: você paga agora por um período futuro.

Essa é geralmente a primeira otimização que gera ROI imediato. Reserve apenas o que você realmente precisa usar continuamente (bases de dados, servidores web sempre ativos). Deixe flexibilidade para picos de demanda usando instâncias sob demanda. No GCP e Azure existem opções similares (Committed Use Discounts e Reserved Instances, respectivamente).

# Exemplo: Calcular economia com Reserved Instances
def calculate_ri_savings(
    instance_type="m5.large",
    hours_per_month=720,  # 30 dias * 24 horas
    months=12,
    on_demand_hourly=0.096,  # Preço sob demanda (exemplo AWS)
    ri_hourly=0.0345  # Preço RI 1 ano (aproximado)
):
    """
    Calcula economia usando Reserved Instances vs On-Demand
    """
    total_hours = hours_per_month * months

    on_demand_cost = total_hours * on_demand_hourly
    ri_cost = total_hours * ri_hourly

    savings = on_demand_cost - ri_cost
    savings_percentage = (savings / on_demand_cost) * 100

    print(f"Instância: {instance_type}")
    print(f"Período: {months} meses ({total_hours} horas)")
    print(f"Custo On-Demand: ${on_demand_cost:.2f}")
    print(f"Custo com RI: ${ri_cost:.2f}")
    print(f"Economia: ${savings:.2f} ({savings_percentage:.1f}%)")

    return {
        'on_demand': on_demand_cost,
        'ri': ri_cost,
        'savings': savings,
        'savings_percentage': savings_percentage
    }

# Uso
calculate_ri_savings()

Otimização em Kubernetes e Containers

Kubernetes é excelente para otimizar custos porque permite compartilhar recursos eficientemente entre múltiplos containers. Porém, muitos times deixam recursos sobre-provisionados ou executam workloads sem otimização. Usar Horizontal Pod Autoscaler (HPA), Vertical Pod Autoscaler (VPA), e Node Autoscaling reduz significativamente os custos.

Além disso, usar Spot Instances (EC2 Spot, GKE Preemptible) pode reduzir custos em até 90%, ideal para workloads tolerantes a interrupção como batch jobs e processamento de dados. A chave é categorizar seus workloads: produção crítica usa On-Demand/Reserved, batch e dev usa Spot.

# Exemplo: Kubernetes com autoscaling e resource requests/limits
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
  namespace: production
spec:
  replicas: 2  # Será ajustado pelo HPA
  selector:
    matchLabels:
      app: api-server
  template:
    metadata:
      labels:
        app: api-server
        cost-center: "platform"  # Para rastreamento de custos
    spec:
      containers:
      - name: api
        image: myregistry.azurecr.io/api-server:v1.2.0
        ports:
        - containerPort: 8080

        # Limites e requests são CRÍTICOS para otimizar custos
        resources:
          requests:
            memory: "256Mi"    # Mínimo que a app precisa
            cpu: "100m"        # 0.1 CPUs
          limits:
            memory: "512Mi"    # Máximo antes de kill
            cpu: "500m"        # 0.5 CPUs

        # Readiness e liveness probes ajudam autoscaler a tomar decisões corretas
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5

        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 20

---
# Horizontal Pod Autoscaler: escala automaticamente pods baseado em CPU
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-server-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 2      # Nunca menos de 2
  maxReplicas: 10     # Nunca mais de 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70  # Escala quando CPU > 70%
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80  # Escala quando memória > 80%

---
# Node Pool com Spot Instances (GKE) para workloads não-críticos
apiVersion: container.cnrm.cloud.google.com/v1beta1
kind: ContainerNodePool
metadata:
  name: batch-processing-pool
spec:
  cluster:
    name: production-cluster
  nodeCount: 0  # Autoscaling ativo
  autoscaling:
    minNodeCount: 0
    maxNodeCount: 20
  nodeConfig:
    machineType: n2-standard-4
    spot: true  # 70% mais barato que On-Demand!
    diskSizeGb: 50
    labels:
      workload-type: batch

Análise e Otimização de Transferência de Dados

Transferência de dados entre regiões e para a internet é frequentemente uma surpresa cara. Uma aplicação que move 100GB entre regiões pode custar centenas de reais por mês. Estratégias incluem: manter dados perto da computação (usar regiões específicas), usar CDN (CloudFront, Cloud CDN), comprimir dados, e implementar cache agressivo.

Analisar padrões de tráfego e estabelecer políticas é essencial. Às vezes, duplicar dados em outra região é mais barato que pagar pela transferência repetida. Ferramentas como VPC Flow Logs e observabilidade de rede ajudam identificar onde o tráfego está indo.

Ferramentas e Integração com Workflow de Desenvolvimento

Ferramentas de Monitoramento e Alerting

Usar ferramentas especializadas acelera a detecção de problemas. Kubecost é excelente para Kubernetes porque quebra custos por namespace, label, e até pod. Infracost integra-se ao seu pipeline Terraform/CloudFormation e mostra o custo estimado de uma mudança antes de fazer deploy. CloudHealth oferece análises multi-cloud e recomendações automatizadas.

# Exemplo: Usando Infracost para estimar custo de mudanças Terraform
# Instalar: brew install infracost

# Verificar custo atual
infracost breakdown --path ./terraform

# Verificar custo de mudanças antes de aplicar
infracost diff --path ./terraform --compare-to main

# Output mostra incremento/decremento de custo
# exemplo:
# ✓ Detected 3 resource types
# 
# Monthly costs will increase by $150 (5%)
# 
# + aws_instance.web_server: $100 → $150 (+$50, +50%)
# + aws_rds_instance.db: $75 → $80 (+$5, +6.7%)

Integração com CI/CD

A melhor forma de garantir que FinOps seja praticado é integrar verificações de custo no pipeline de CI/CD. Você pode rejeitar pull requests que aumentem custos acima de um limite, ou exigir aprovação explícita. Isso traz a conversa sobre custos para o momento da decisão (durante code review) e não para depois (quando a fatura chega).

# Exemplo: GitHub Actions com Infracost
name: Cost Analysis

on:
  pull_request:
    paths:
      - 'terraform/**'

jobs:
  infracost:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Setup Infracost
        uses: infracost/actions/setup@v2
        with:
          api-key: ${{ secrets.INFRACOST_API_KEY }}

      - name: Generate Infracost JSON
        run: |
          infracost breakdown --path terraform --format json --out-file /tmp/infracost-base.json

      - name: Post cost estimate to PR
        uses: infracost/actions/comment@v2
        with:
          path: /tmp/infracost-base.json
          behavior: update

Conclusão

Aprendemos que FinOps é um framework prático e acessível para qualquer organização que use cloud. Os três pilares—visibilidade, otimização contínua, e governança compartilhada—devem ser implementados juntos para gerar valor real. Visibilidade sem ação é apenas um relatório bonito; otimização sem governança volta a gastar descontrolado; e governança sem visibilidade é somente burocracia.

A prática de FinOps também mudou meu entendimento sobre como construir arquiteturas em cloud: não é mais "quanto posso escalar", mas "quanto preciso escalar para entregar valor". Isso naturalmente leva a decisões mais bem pensadas sobre tamanho de instância, regiões, e padrões de arquitetura. Por fim, implemente FinOps como um processo iterativo, não um projeto único. Comece por visibilidade (20% do esforço, 80% do valor), depois otimize (recursos ociosos, RIs), e por último, formalize governança conforme a prática amadurece.

Referências


Artigos relacionados