Aller au contenu principal
FinOpsCloudOptimisation

Spot Instances, tagging et budgets cloud

30 min de lecture Platform Engineering — Chapitre 6

Spot Instances pour réduire les coûts de 90%, stratégie de tagging, budgets et alertes, et quick wins pour des économies immédiates.

Dans le chapitre précédent, on a vu FinOps : Kubecost, Infracost et right-sizing. Maintenant on passe aux leviers opérationnels.

Le FinOps donne la visibilité. Maintenant, il faut agir. Ce cours couvre les trois leviers les plus puissants pour réduire concrètement ta facture cloud : les Spot Instances qui offrent jusqu’à 90% de réduction sur le compute, une stratégie de tagging qui rend chaque euro traçable, et des budgets avec alertes qui empêchent les dérapages silencieux.

Ces trois éléments fonctionnent ensemble. Sans tagging, tu ne sais pas qui dépense. Sans budgets, tu ne sais pas quand ça dérape. Sans Spot, tu paies le prix fort pour des workloads qui pourraient tourner à une fraction du coût.


Spot Instances — Le compute à prix cassé

AWS, GCP et Azure disposent à tout moment de capacité de calcul inutilisée. Plutôt que de la laisser inactive, ils la revendent sous forme de Spot Instances à un prix réduit de 60 à 90% par rapport au tarif On-Demand. La contrepartie : le cloud provider peut reprendre cette capacité avec un préavis de 2 minutes quand la demande augmente.

Il existe trois modèles de tarification : On-Demand (100% du prix, aucun engagement, flexible), Reserved Instances (30-72% du prix, engagement 1-3 ans, prévisible), et Spot (10-30% du prix, peut être interrompu, idéal pour les workloads tolérants aux interruptions).

La clé pour utiliser les Spot en production, c’est de concevoir une architecture qui tolère les interruptions. Le pattern classique : une base de nœuds On-Demand qui assure la disponibilité minimale (30% du trafic), et des nœuds Spot qui absorbent le reste avec une diversification maximale des types d’instances.

Avec Karpenter (le successeur de Cluster Autoscaler pour EKS), la configuration est déclarative :

# Karpenter NodePool — Nœuds Spot diversifiés
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: spot-pool
spec:
  template:
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot"]
        - key: node.kubernetes.io/instance-type
          operator: In
          values:
            # Diversifier les familles réduit le risque d'interruption
            - m5.large
            - m5a.large
            - m6i.large
            - m6a.large
            - c5.large
            - c5a.large
            - c6i.large
        - key: topology.kubernetes.io/zone
          operator: In
          values: ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    budgets:
      - nodes: "10%"    # Max 10% des nœuds interrompus simultanément
  limits:
    cpu: "100"
    memory: "400Gi"

💡 Tip DevOps : La diversification des types d’instances est cruciale. Si tu ne demandes que des m5.large, quand AWS manque de capacité sur ce type précis, tous tes nœuds Spot tombent en même temps. En diversifiant sur 7-8 types de familles différentes (m5, m5a, m6i, c5, c6i…), la probabilité d’une interruption simultanée devient quasi nulle.

Quand AWS envoie la notification de terminaison, ton application dispose de 2 minutes pour se terminer proprement. Un handler de terminaison doit : arrêter d’accepter de nouvelles requêtes, finir les requêtes en cours, fermer les connexions DB, et flusher les métriques/logs :

#!/usr/bin/env python3
"""Handler de terminaison Spot — graceful shutdown"""
import signal, sys, requests, time, logging

logger = logging.getLogger(__name__)
SPOT_URL = "http://169.254.169.254/latest/meta-data/spot/instance-action"

def graceful_shutdown(signum, frame):
    logger.info("🛑 Graceful shutdown initiated...")
    logger.info("  → Stop accepting new connections")
    logger.info("  → Finishing in-flight requests...")
    time.sleep(10)  # Laisser le temps aux requêtes en cours
    logger.info("  → Closing DB connections")
    logger.info("  → Flushing metrics and logs")
    logger.info("✅ Shutdown complete")
    sys.exit(0)

signal.signal(signal.SIGTERM, graceful_shutdown)

# Polling de l'endpoint metadata pour détecter la terminaison
while True:
    try:
        resp = requests.get(SPOT_URL, timeout=2)
        if resp.status_code == 200:
            logger.warning(f"⚠️ SPOT TERMINATION: {resp.json()}")
            graceful_shutdown(None, None)
    except requests.exceptions.RequestException:
        pass
    time.sleep(5)

⚠️ Attention : Les Spot Instances ne sont jamais adaptées pour les workloads stateful : bases de données, queues de messages (RabbitMQ, Kafka), systèmes de fichiers distribués. Une interruption de 2 minutes sur un leader PostgreSQL peut provoquer une corruption de données ou un split-brain. Réserve les Spot aux workloads stateless : API derrière un load balancer, workers de traitement batch, jobs CI/CD, analyses de données.

🔥 Cas réel : Un client e-commerce utilise un mix 30% On-Demand / 70% Spot pour ses 200 pods de microservices. Coût On-Demand complet : 45 000€/mois. Avec la stratégie Spot : 18 000€/mois. Économie : 27 000€/mois, soit 324k€/an. En 18 mois, ils n’ont eu que 3 interruptions Spot, toutes gérées automatiquement par Karpenter sans impact utilisateur.


Tagging Strategy — La fondation de l’attribution des coûts

Sans tags, le FinOps est aveugle. Tu vois une facture globale de 50 000€/mois mais tu ne sais pas si c’est l’équipe Payments qui explose le budget ou l’équipe Marketing qui a lancé un cluster de test sans le couper. Les tags sont la fondation de toute attribution de coûts.

Voici les tags obligatoires à imposer sur chaque ressource cloud :

  • Environment : production, staging, development, sandbox
  • Team : l’équipe propriétaire (team-payments, team-platform)
  • CostCenter : le centre de coût comptable (CC-ENGINEERING-001)
  • Project : le projet métier (checkout-v2, recommendation-engine)
  • ManagedBy : l’outil de provisioning (terraform, pulumi, manual)
  • Owner : l’email de la personne responsable

L’enforcement se fait en amont via Terraform — un module de tagging qui valide le format et refuse les créations non conformes :

# modules/tagging/main.tf — Tags obligatoires avec validation
variable "required_tags" {
  type = object({
    Environment = string
    Team        = string
    CostCenter  = string
    Project     = string
    ManagedBy   = string
    Owner       = string
  })

  validation {
    condition     = contains(["production", "staging", "development", "sandbox"], var.required_tags.Environment)
    error_message = "Environment doit être: production, staging, development, sandbox"
  }
  validation {
    condition     = can(regex("^CC-[A-Z]+-[0-9]+$", var.required_tags.CostCenter))
    error_message = "CostCenter doit suivre le format CC-XXXXX-000"
  }
  validation {
    condition     = can(regex("^[a-zA-Z0-9._%+-]+@company\\.com$", var.required_tags.Owner))
    error_message = "Owner doit être un email @company.com"
  }
}

locals {
  common_tags = merge(var.required_tags, {
    Terraform   = "true"
    LastUpdated = timestamp()
  })
}

output "tags" { value = local.common_tags }

Pour une gouvernance à l’échelle de l’organisation AWS, les Tag Policies au niveau AWS Organizations bloquent la création de ressources qui ne respectent pas les conventions :

{
  "tags": {
    "Environment": {
      "tag_key": { "@@assign": "Environment" },
      "tag_value": {
        "@@assign": ["production", "staging", "development", "sandbox"]
      },
      "enforced_for": {
        "@@assign": ["ec2:instance", "rds:db", "s3:bucket", "elasticloadbalancing:*"]
      }
    },
    "CostCenter": {
      "tag_key": { "@@assign": "CostCenter" },
      "enforced_for": {
        "@@assign": ["ec2:instance", "rds:db"]
      }
    }
  }
}

🧠 À retenir : Une politique de tagging sans enforcement, c’est du théâtre. Il faut un mécanisme automatisé qui bloque ou alerte quand une ressource est créée sans les tags obligatoires. Terraform validation + AWS Tag Policies + un rapport hebdomadaire des ressources non conformes = la triplette gagnante.


Budgets et alertes — Le filet de sécurité financier

Les budgets cloud fonctionnent comme des garde-fous : ils ne bloquent pas les dépenses (sauf configuration spécifique), mais ils alertent progressivement les bonnes personnes au bon moment.

Le pattern recommandé : trois seuils d’alerte — 50% (information), 80% (attention), et 100% en forecast (action requise). Chaque seuil notifie des destinataires différents, avec une escalade naturelle :

# Budget AWS par équipe avec alertes progressives
resource "aws_budgets_budget" "team_payments" {
  name         = "team-payments-budget"
  budget_type  = "COST"
  limit_amount = "3000"
  limit_unit   = "USD"
  time_unit    = "MONTHLY"

  cost_filter {
    name   = "TagKeyValue"
    values = ["user:Team$team-payments"]
  }

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 50
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["finops@company.com"]
  }

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 80
    threshold_type             = "PERCENTAGE"
    notification_type          = "ACTUAL"
    subscriber_email_addresses = ["finops@company.com", "payments-lead@company.com"]
    subscriber_sns_topic_arns  = [aws_sns_topic.budget_alerts.arn]
  }

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 100
    threshold_type             = "PERCENTAGE"
    notification_type          = "FORECASTED"
    subscriber_email_addresses = ["finops@company.com", "cto@company.com"]
    subscriber_sns_topic_arns  = [aws_sns_topic.budget_alerts.arn]
  }
}

Pour que les alertes soient réellement actionnables, connecte-les à Slack via une Lambda. Un message dans un channel dédié #finops-alerts avec des boutons pour accéder directement à la console de coûts est infiniment plus efficace qu’un email que personne ne lit :

#!/usr/bin/env python3
"""Lambda — Alertes budget vers Slack"""
import json, os, urllib3

def lambda_handler(event, context):
    msg = json.loads(event['Records'][0]['Sns']['Message'])
    slack = {
        "blocks": [
            {"type": "header", "text": {
                "type": "plain_text",
                "text": f"⚠️ Budget Alert: {msg.get('budgetName', '?')}"}},
            {"type": "section", "fields": [
                {"type": "mrkdwn", "text": f"*Seuil:* {msg.get('threshold', '?')}%"},
                {"type": "mrkdwn", "text": f"*Dépensé:* ${msg.get('actualAmount', '?')}"},
                {"type": "mrkdwn", "text": f"*Limite:* ${msg.get('budgetLimit', '?')}"}]},
            {"type": "actions", "elements": [
                {"type": "button", "text": {"type": "plain_text", "text": "📊 AWS Cost Explorer"},
                 "url": "https://console.aws.amazon.com/cost-management/"},
                {"type": "button", "text": {"type": "plain_text", "text": "📉 Kubecost"},
                 "url": "https://kubecost.internal.company.com"}]}
        ]
    }
    urllib3.PoolManager().request('POST', os.environ['SLACK_WEBHOOK_URL'],
        body=json.dumps(slack), headers={'Content-Type': 'application/json'})
    return {'statusCode': 200}

🔥 Cas réel : Une startup a découvert grâce à ses alertes budget qu’un développeur avait lancé un cluster EMR de test avec des instances r5.24xlarge un vendredi soir — coût : 2 400$/jour. L’alerte Slack à 50% du budget a été reçue le samedi matin. Sans budget, la facture aurait dérapé de 15 000$ avant que quelqu’un ne s’en aperçoive le lundi.


Quick wins — Les économies immédiates

Avant de se lancer dans des chantiers de Spot Instances ou de refactoring d’architecture, il existe des gains rapides qui demandent peu d’effort et rapportent gros. Les voici par ordre d’impact :

  1. Éteindre les environnements dev/staging la nuit et le week-end — un simple CronJob Kubernetes ou une Lambda qui scale à 0 entre 20h et 8h économise ~65% sur ces environnements
  2. Supprimer les volumes EBS orphelinsaws ec2 describe-volumes --filters Name=status,Values=available révèle les disques qui facturent sans être attachés à aucune instance
  3. Nettoyer les vieux snapshots — garder 30 jours de snapshots, archiver ou supprimer le reste
  4. Right-sizer les RDS oversized — vérifier si le CPU moyen est <20% sur 2 semaines, downsize d’un cran
  5. Migrer les volumes gp2 vers gp3 — 20% moins cher avec de meilleures performances de base
  6. Auditer les NAT Gateways — souvent la ligne budgétaire la plus sous-estimée
  7. Passer les S3 infrequent access — les objets non accédés depuis 90 jours passent en S3 IA (coût divisé par 2)

💡 Tip DevOps : Crée un script “FinOps Audit” qui tourne chaque lundi matin et génère un rapport des ressources orphelines, des instances sous-utilisées et des volumes non attachés. Envoie-le sur Slack dans #finops-weekly. En 3 mois, tu auras instauré une culture de vigilance financière sans effort managérial.


Résumé

Les Spot Instances sont le levier le plus puissant pour réduire les coûts compute (60-90% d’économies), à condition de concevoir une architecture résiliente aux interruptions avec diversification des types d’instances et séparation On-Demand/Spot. La stratégie de tagging rend chaque euro attribuable à une équipe, un projet et un environnement — c’est la condition préalable à tout FinOps sérieux. Les budgets avec alertes progressives (50% → 80% → 100%) empêchent les dérapages silencieux et responsabilisent chaque équipe.

🧠 À retenir : Le FinOps n’est pas un projet one-shot. C’est un cycle continu d’observation, d’optimisation et de gouvernance. Les quick wins (env dev la nuit, volumes orphelins, migration gp3) financent les chantiers plus ambitieux (Spot, Reserved Instances, architecture multi-region optimisée). Commence par ce qui rapporte le plus vite, mesure l’économie, et réinvestis dans l’optimisation suivante.

Prochain cours : On quitte le Platform Engineering pour plonger dans Proxmox — la virtualisation open-source qui permet de construire ton propre cloud privé.

🖥️ Pratique sur ton propre serveur

Pour suivre Platform Engineering en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.

Obtenir 200$

Articles liés