AWS-Kostenoptimierung: So senkst du deine Ausgaben, bevor sie außer Kontrolle geraten
Warum reaktives Kostenmanagement gefährlich ist, wie AWS dich tatsächlich abrechnet und wie du mit Tagging, AWS Data Exports (ehemals CUR) und den richtigen Compute-Entscheidungen die Kosten unter Kontrolle bringst.
Mory Kaba24 Min. LesezeitCloud-Kosten sind ein notorisch komplexes Thema. Nicht aus technischer Sicht, sondern eher aus organisatorischer Perspektive. Die meisten Gespräche über Cloud-Ausgaben finden erst statt, wenn eine bestimmte “Schwelle” erreicht wurde. Das passiert in der Regel, nachdem ein oder mehrere Stakeholder festgestellt haben, dass die Cloud-Ausgaben außer Kontrolle geraten sind. Diese Erkenntnis basiert oft auf einem “Bauchgefühl”, dass das, was man betreibt, eigentlich nicht so teuer sein sollte. Oder das Unternehmen läuft nicht gut und versucht aktiv, Kosten zu senken. Ein Kostenkontroll-Mandat wird erlassen, und die IT-Infrastruktur ist die naheliegendste Schicht, bei der man beginnt.
Der Punkt ist: Kosten werden meist erst dann relevant, wenn sie problematisch werden. Diese Denkweise ist aus zwei Gründen gefährlich. Erstens hält eine kostenbewusste Engineering-Kultur die Arbeit auf umsatzgenerierende Maßnahmen fokussiert. Teams, die beim Bauen an Kosten denken, treffen bessere Architekturentscheidungen, nicht nur günstigere. Zweitens ist das nachträgliche Umbauen von Infrastruktur aus Kostengründen mühsam und komplex. Eine Datenpipeline neu zu architekturieren oder eine Datenbank nach Abschluss eines Projekts in einen günstigeren Storage-Tier zu migrieren ist deutlich schwieriger, als von Anfang an darauf zu achten.
In diesem Artikel untersuchen wir, warum diese Denkweise schädlich ist und wie du deine AWS-Rechnungen mit einem proaktiveren Ansatz unter Kontrolle bringen kannst.
Wichtigste Erkenntnisse
- Du zahlst für das, was existiert, nicht nur für das, was läuft: Idle-Ressourcen, reservierte IPs und vergessene Snapshots verursachen weiterhin Kosten
- Jede AWS-Gebühr kombiniert drei Primitive: zeitbasiert, volumenbasiert und funktionsbasiert
- Kostenzuordnung ist ohne eine Tagging-Strategie von Anfang an unmöglich
- AWS Data Exports, abgefragt via Athena, ist das richtige Tool für Workload-bezogene Kostenanalyse
- Für die meisten Daten-Workloads sind DuckDB oder Athena deutlich günstiger als ein Spark- oder EMR-Cluster
Wie AWS dich tatsächlich abrechnet
Ein Blick auf deine AWS-Rechnung kann verwirrend sein. Du siehst eine Reihe von Cloud-Services aufgelistet und daneben einen Dollarbetrag, der die Kosten für den jeweiligen Service widerspiegelt. Die Rechnung beantwortet in der Regel nicht, welche spezifischen Services, Ressourcen und Workloads deiner IT-Infrastruktur diese Kosten verursachen.
Schauen wir uns an, wie AWS dich abrechnet und welches mentale Modell erforderlich ist, um dieses Thema richtig anzugehen.
Das mentale Modell von Cloud-Kosten
Du zahlst dafür, was existiert, nicht nur dafür, was läuft. In traditionellen Rechenzentren kaufst du Hardware mit einer bestimmten Kapazität im Voraus, und sie steht dann als Investitionsausgabe da. Bei Cloud-Anbietern wie AWS startet jede Ressource, die du erstellst, einen Zähler.
Du hast vor sechs Monaten eine Datenbank zu Testzwecken aufgesetzt und sie vergessen? Du zahlst weiterhin für diese Ressource, auch wenn sie keine einzige Abfrage bearbeitet hat. Dasselbe gilt für andere Ressourcen: IP-Adressen, die reserviert, aber nicht zugewiesen sind, kosten Geld. Snapshots aus einer abgeschlossenen Migration von letztem Jahr laufen weiterhin Kosten auf.
AWS räumt nicht nach dir auf. Wenn du es nicht tust, erscheint es auf deiner Rechnung.
Was sind die drei AWS-Abrechnungsprimitive?
Alles auf deiner AWS-Rechnung lässt sich auf eine kleine Menge von Primitiven reduzieren.
Zeitbasierte Gebühren sind die häufigsten. Eine Ressource existiert, und für jede Zeiteinheit, in der sie weiterhin existiert, fallen Kosten an. Die Einheit kann je nach Service pro Sekunde, pro Minute oder pro Stunde sein. Sobald du die Ressource erstellst, startet eine Uhr, die erst stoppt, wenn du sie löschst.
Volumenbasierte Gebühren fallen an, sobald du eine messbare Menge verbrauchst: Gigabyte übertragene Daten, Anzahl der API-Anfragen, Lambda-Aufrufe. Diese skalieren mit dem Verbrauch und entstehen nur, wenn tatsächlich etwas passiert, zum Beispiel wenn du eine Datei aus S3 herunterlädst oder eine Lambda-Funktion aufrufst. Die meisten Services nutzen gestaffelte Preise statt eines festen Einheitspreises, daher sinken die Kosten pro Einheit bei höheren Volumen oft.
Funktionsbasierte Gebühren entstehen, sobald du eine bestimmte Funktion auf einer Basisressource aktivierst. Das Aktivieren von Multi-AZ-Replikation, erweitertem Monitoring oder Datenbank-Performance-Monitoring (über CloudWatch Database Insights auf RDS) fügt jeweils eine Kostenschicht auf die zugrunde liegende Ressourcenkosten hinzu.
Was sind die drei Dimensionen von AWS-Workload-Kosten?
Über die Abrechnungsprimitive hinaus erzeugt jeder Workload, den du erstellst, Kosten in drei unabhängigen Dimensionen. Das Schlüsselwort ist unabhängig: Die Optimierung einer Dimension reduziert die anderen nicht automatisch.
Compute ist das, wofür du jedes Mal zahlst, wenn etwas ausgeführt wird: ein Server, der Anfragen verarbeitet, eine Lambda-Funktion, die ausgeführt wird, ein Redshift-Cluster, der Zeilen scannt. Es korrespondiert direkt mit den Ressourcen, die du provisionierst, und ist die am einfachsten zu bearbeitende Dimension. Autoscaling, Right-Sizing, der Wechsel zu Spot-Instances, der Umstieg auf Serverless: all das hat einen sofortigen, messbaren Effekt. Das Risiko: Compute bekommt so viel Aufmerksamkeit, dass die anderen beiden Dimensionen vollständig vernachlässigt werden.
Storage repräsentiert Daten im Ruhezustand: Datenbanken, S3-Objekte, EBS-Volumes, RDS-Snapshots, CloudWatch-Logs, Glacier-Archive. Cloud-Anbieter haben Storage wie eine Commodity erscheinen lassen, und der Preis pro Einheit ist günstig, bis du anfängst, die Einheiten zu zählen. Daten häufen sich unbemerkt an. Logs wachsen unkontrolliert, Snapshots multiplizieren sich über Accounts hinweg, alte Backups werden nie bereinigt, weil niemand den Cleanup-Prozess besitzt. Was Storage besonders trügerisch macht: Die Kosten sind vollständig von den Zugriffsmustern entkoppelt. Archivierte Daten, die du seit drei Jahren nicht berührt hast, kosten genauso viel wie ständig abgefragte Daten, es sei denn, du verschiebst sie explizit in einen günstigeren Tier. Die Cloud erledigt das nicht für dich.
Network ist die kontraintutivste Dimension, da sie asymmetrisch funktioniert. Daten in AWS zu verschieben ist fast immer kostenlos. Daten herauszubewegen (ins Internet, in eine andere Region oder zwischen Komponenten in verschiedenen Availability Zones) kostet Geld. Traffic zwischen Services innerhalb derselben AZ mit privaten IPs ist kostenlos. Diese Asymmetrie ist beabsichtigt. AWS will deine Daten in seinem Ökosystem halten und berechnet dir Gebühren dafür, sie herauszunehmen.
Eine Anwendung, die Daten lokal verarbeitet und ein kleines Ergebnis zurückgibt, hat ein fundamental anderes Kostenprofil als eine, die große Payloads über Availability Zones hinweg streamt oder Antworten an viele Internet-Konsumenten verteilt. Netzwerkkosten sind oft unsichtbar, bis sie es nicht mehr sind. Sie erscheinen nicht in Instance-Dashboards, sie summieren sich byte-weise über Dutzende von Service-Interaktionen, und sie lassen sich ohne bewusstes Instrumentierung kaum nachvollziehen.
Wie du deine Kosten transparent und analysierbar machst
Die Dimensionen zu kennen ist nützlich, aber nicht ausreichend. Eine Organisation muss in der Lage sein, diese Kostendimensionen aufzuschlüsseln und sie bestimmten Workloads zuzuordnen. Nur so lässt sich der ROI des Betriebs bewerten und schnell handeln, wenn etwas geändert werden muss.
AWS bietet diese Sichtbarkeit standardmäßig nicht. Die Konsole zeigt dir, dass EC2 letzten Monat 14.000 Dollar gekostet hat. Sie sagt dir nicht, welcher Workload welches Teams, welche Umgebung (Produktion vs. Staging) oder welche spezifische Pipeline diese Zahl verursacht hat. Um diese Ebene der Zuordnung zu erreichen, braucht es eine bewusste Tagging-Strategie, aufgesetzt bevor Kosten zum Problem werden, nicht danach.
Was ist die richtige Tagging-Strategie für AWS-Ressourcen?
AWS erlaubt es, beliebige Key-Value-Tags an jede Ressource zu hängen. Ein minimales Schema, das in der Praxis tatsächlich funktioniert, muss mindestens vier Dimensionen abdecken: env (prod, staging, dev), team, project und managed-by (terraform, manual usw.).
Mit diesen vier Tags, die konsequent angewendet werden, kannst du Fragen beantworten wie: „Was kostet unsere Staging-Umgebung eigentlich?” oder „Wie viel gibt die Ingestion-Pipeline pro Monat aus?” Ohne diese Tags sind solche Fragen allein aus der Rechnung nicht zu beantworten.
Cost Allocation Tags
Ressourcen zu taggen ist nur die halbe Arbeit. Du musst diese Tags auch als Cost Allocation Tags in der AWS Billing Console unter „Cost allocation tags” aktivieren. Einmal aktiviert, werden sie zu filterbaren Dimensionen im Cost Explorer und zu Spalten in AWS Data Exports.
AWS unterscheidet zwischen von AWS generierten Tags (wie aws:createdBy) und benutzerdefinierten Tags. Benutzerdefinierte Cost Allocation Tags können bis zu 24 Stunden brauchen, um auf der Aktivierungsseite zu erscheinen, und nochmals bis zu 24 Stunden, um nach der Aktivierung in den Abrechnungsdaten wirksam zu werden. Es lohnt sich, sie früh im Projektverlauf zu aktivieren, nicht erst wenn du die Daten brauchst.
Tagging-Durchsetzung via SCP und Terraform
Tags funktionieren nur, wenn sie konsequent angewendet werden, und manuell konsequent Tags zu setzen funktioniert in der Praxis nicht. Die Durchsetzung muss auf zwei Ebenen stattfinden.
Auf Organisationsebene können AWS Service Control Policies (SCPs) das Erstellen von Ressourcen blockieren, wenn erforderliche Tags fehlen. Beachte, dass SCPs AWS Organizations voraussetzen und nicht für das Management-Konto (Root) selbst gelten; sie gelten nur für Mitgliedskonten und OUs. Die folgende Policy verweigert gängige Ressourcenerstellungsaktionen, wenn die Tags env, team oder project fehlen:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyWithoutEnvTag",
"Effect": "Deny",
"Action": ["ec2:RunInstances", "rds:CreateDBInstance", "ecs:CreateService"],
"Resource": "*",
"Condition": {
"Null": { "aws:RequestTag/env": "true" }
}
},
{
"Sid": "DenyWithoutTeamTag",
"Effect": "Deny",
"Action": ["ec2:RunInstances", "rds:CreateDBInstance", "ecs:CreateService"],
"Resource": "*",
"Condition": {
"Null": { "aws:RequestTag/team": "true" }
}
},
{
"Sid": "DenyWithoutProjectTag",
"Effect": "Deny",
"Action": ["ec2:RunInstances", "rds:CreateDBInstance", "ecs:CreateService"],
"Resource": "*",
"Condition": {
"Null": { "aws:RequestTag/project": "true" }
}
}
]
}Jede Anweisung verweigert die Aktion unabhängig, wenn das jeweilige Tag fehlt. Da Deny in AWS IAM Vorrang vor Allow hat, blockiert jedes einzelne fehlende Tag die Anfrage.
Um diese SCP via Terraform zu deployen und an eine Organizational Unit anzuhängen:
resource "aws_organizations_policy" "require_tags" {
name = "RequireResourceTags"
description = "Deny resource creation without required tags"
type = "SERVICE_CONTROL_POLICY"
content = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "DenyWithoutEnvTag"
Effect = "Deny"
Action = ["ec2:RunInstances", "rds:CreateDBInstance", "ecs:CreateService"]
Resource = "*"
Condition = { Null = { "aws:RequestTag/env" = "true" } }
},
{
Sid = "DenyWithoutTeamTag"
Effect = "Deny"
Action = ["ec2:RunInstances", "rds:CreateDBInstance", "ecs:CreateService"]
Resource = "*"
Condition = { Null = { "aws:RequestTag/team" = "true" } }
},
{
Sid = "DenyWithoutProjectTag"
Effect = "Deny"
Action = ["ec2:RunInstances", "rds:CreateDBInstance", "ecs:CreateService"]
Resource = "*"
Condition = { Null = { "aws:RequestTag/project" = "true" } }
}
]
})
}
resource "aws_organizations_policy_attachment" "require_tags" {
policy_id = aws_organizations_policy.require_tags.id
target_id = var.organizational_unit_id
}Auf der Infrastructure-as-Code-Ebene können Terraform-Module Tags als Pflichtinputs erzwingen, sodass jeder Konsument des Moduls die Tag-Struktur automatisch erbt:
variable "tags" {
description = "Required resource tags"
type = object({
env = string
team = string
project = string
})
validation {
condition = contains(["prod", "staging", "dev"], var.tags.env)
error_message = "env must be one of: prod, staging, dev."
}
}
locals {
common_tags = merge(var.tags, {
managed-by = "terraform"
})
}Jeder Ressource-Block im Modul übergibt dann local.common_tags an sein tags-Argument. Wenn ein neuer Engineer einen Service über dieses Modul aufsetzt, werden die erforderlichen Tags angewendet, ohne dass er darüber nachdenken muss.
Beide Ebenen zusammen sind notwendig. SCPs erfassen alles, was außerhalb von Terraform provisioniert wird. Modul-Defaults decken den Großteil des alltäglichen Volumens ab.
Wie Tags die Kostenzuordnung strukturierter machen
Sobald Tagging eingerichtet und Cost Allocation Tags aktiviert sind, kannst du deine Rechnung nach beliebigen Tag-Kombinationen aufschlüsseln. Im Cost Explorer kannst du nach team=data-platform und env=prod filtern, um genau zu sehen, was die Produktions-Dateninfrastruktur kostet, unabhängig von Staging oder anderen Teams.
Das praktische Muster für tiefergehende Analysen ist: AWS Data Exports einrichten, es in S3 schreiben lassen und mit Athena abfragen. Der Export enthält jede Zeile deiner Rechnung auf Ressourcenebene, mit allen aktivierten Tags als Spalten. Daraus lässt sich ein Dashboard bauen, das nach Team, Workload, Umgebung und Zeitraum filterbar ist, mit echten Zahlen zu echten Workloads statt Bauchgefühlen.
AWS Data Exports (ehemals Cost and Usage Report / CUR)
Cost Explorer ist ein sinnvoller Ausgangspunkt für Stichproben. AWS Data Exports ist der Ort, an dem du echte Analysekraft bekommst.
Data Exports ist der aktuelle AWS-Service zum Exportieren von Abrechnungsdaten nach S3, der die bisherigen Cost and Usage Reports (CUR) ablöst. Er schreibt kontinuierlich einen Flat-File-Report nach S3, der jede Zeile deiner Rechnung auf Ressourcenebene enthält, mit allen aktivierten Cost Allocation Tags als Spalten. Du fragst ihn mit Athena ab, lädst ihn in Redshift Spectrum oder verbindest ihn mit einem BI-Tool. Der nachgelagerte Workflow ist derselbe wie beim bisherigen CUR.
Data Exports unterstützt zwei Formate. Das Legacy-CUR-Format bewahrt das bestehende Spalten-Schema für Teams, die vom alten Service migrieren. Das FOCUS-1.0-Format (FinOps Open Cost and Usage Specification) ist ein herstellerneutraler offener Standard, der es einfacher macht, AWS-Abrechnungsdaten mit Ausgaben anderer Cloud-Anbieter zu kombinieren. Für neue Setups ist FOCUS die bessere Wahl.
Um einen Data Export via Terraform bereitzustellen (erfordert AWS Provider >= 5.40):
resource "aws_bcmdataexports_export" "main" {
export {
name = "cur-main"
data_query {
query_statement = "SELECT * FROM COST_AND_USAGE_REPORT"
table_configurations = {
"COST_AND_USAGE_REPORT" = {
"TIME_GRANULARITY" = "HOURLY"
"INCLUDE_RESOURCES" = "TRUE"
"INCLUDE_MANUAL_DISCOUNT_COMPATIBILITY" = "FALSE"
"INCLUDE_SPLIT_COST_ALLOCATION_DATA" = "FALSE"
}
}
}
destination_configurations {
s3_destination {
s3_bucket = aws_s3_bucket.cur.bucket
s3_prefix = "cur"
s3_region = "us-east-1"
s3_output_configurations {
compression = "PARQUET"
format = "PARQUET"
output_type = "CUSTOM"
overwrite = "OVERWRITE_REPORT"
}
}
}
refresh_cadence {
frequency = "SYNCHRONOUS"
}
}
}"INCLUDE_RESOURCES" = "TRUE" ist das Äquivalent des alten additional_schema_elements = ["RESOURCES"]; ohne diese Einstellung enthalten die Einträge keine Ressourcendetails, und der Export ist für die Workload-Zuordnung deutlich weniger nützlich. Die SYNCHRONOUS-Refresh-Kadenz schreibt neue Daten, sobald AWS sie bereitstellt, was dir die aktuellste Ausgabenübersicht gibt.
Wie der Report aussieht
Sobald der Export in S3 gelandet und von Glue gecrawlt wurde, repräsentiert jede Zeile der Parquet-Datei eine Abrechnungszeile. Die für die Kostenzuordnung relevantesten Spalten sind:
| Spalte | Beispielwert | Was sie zeigt |
|---|---|---|
line_item_product_code | AmazonEC2 | Welcher AWS-Service |
line_item_resource_id | i-0abc123def456 | Die spezifische Ressource |
line_item_usage_type | BoxUsage:m5.xlarge | Was verbraucht wurde |
line_item_unblended_cost | 2.34 | Kosten in USD für diese Zeile |
line_item_line_item_type | Usage | Gebührentyp (Usage, Tax, Credit, etc.) |
resource_tags_user_team | data-platform | Dein team-Tag |
resource_tags_user_env | prod | Dein env-Tag |
resource_tags_user_project | ingestion | Dein project-Tag |
line_item_usage_start_date | 2026-05-01 00:00:00 | Stunde der Nutzung |
Tag-Spalten folgen dem Muster resource_tags_user_<tagname>. Ein Tag-Key team wird zu resource_tags_user_team. Tags, die nicht als Cost Allocation Tags aktiviert wurden, fehlen im Export.
Die nützlichste Einstiegsabfrage zeigt die Gesamtkosten nach Team, Umgebung und Service für den aktuellen Monat, ohne Steuerzeilen:
SELECT
resource_tags_user_team AS team,
resource_tags_user_env AS env,
resource_tags_user_project AS project,
line_item_product_code AS service,
ROUND(SUM(line_item_unblended_cost), 2) AS total_cost_usd
FROM cur_main
WHERE
line_item_line_item_type != 'Tax'
AND year = '2026'
AND month = '5'
GROUP BY 1, 2, 3, 4
ORDER BY total_cost_usd DESC;Das ergibt eine gerankte Aufschlüsselung, was jedes Team pro Service und Umgebung ausgibt. Von hier aus kannst du in eine beliebige Zeile hineinzoomen, indem du einen WHERE resource_tags_user_team = 'data-platform'-Filter hinzufügst, oder einen täglichen Trend anzeigen, indem du line_item_usage_start_date in SELECT und GROUP BY aufnimmst.
Strategien zur Kostensenkung
Mit der nötigen Transparenz kannst du anfangen zu handeln. Die richtigen Hebel hängen davon ab, was du betreibst.
Data Engineering Workloads
Compute
Die wirkungsvollste Frage für Daten-Teams ist, ob sie tatsächlich die Tools benötigen, auf die sie standardmäßig zurückgreifen. Spark-Cluster und persistente Redshift-Cluster sind die richtige Antwort für die Verarbeitung im Petabyte-Bereich, werden aber regelmäßig für Datensätze eingesetzt, die problemlos auf einer einzelnen Maschine laufen würden.
Bevor du auf eine verteilte Compute-Schicht zurückgreifst, prüfe, ob Polars, DuckDB oder Athena mit einem dbt Connector den Anwendungsfall abdeckt. Diese sind dramatisch günstiger und oft schneller für die Workloads, die die meisten Daten-Teams tatsächlich haben. Für eine Transformation, die auf 50 GB Daten läuft, kostet DuckDB auf einer einzelnen EC2-Instanz einen Bruchteil dessen, was ein EMR-Cluster kostet, und ist in vergleichbarer Zeit fertig.
Wo eine verwaltete Container-Umgebung tatsächlich benötigt wird, ist ECS Fargate mit Autoscaling ein besserer Standard als ein persistenter Cluster. Mit Fargate zahlst du für die zugewiesene vCPU und den zugewiesenen Arbeitsspeicher deiner Task für die Dauer der Ausführung, nicht für Idle-Kapazität auf einem persistenten Cluster. Eine Target-Tracking-Policy hält den Service ohne manuellen Eingriff richtig dimensioniert:
resource "aws_ecs_service" "data_processor" {
name = "data-processor"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.data_processor.arn
desired_count = 1
launch_type = "FARGATE"
network_configuration {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs.id]
assign_public_ip = false
}
tags = local.common_tags
}
resource "aws_appautoscaling_target" "ecs_target" {
max_capacity = 10
min_capacity = 1
resource_id = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.data_processor.name}"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}
resource "aws_appautoscaling_policy" "scale_on_cpu" {
name = "scale-on-cpu"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.ecs_target.resource_id
scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension
service_namespace = aws_appautoscaling_target.ecs_target.service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageCPUUtilization"
}
target_value = 70.0
}
}Die Policy skaliert den Service hoch, wenn die CPU-Auslastung 70 % überschreitet, und wieder herunter, wenn die Last sinkt, mit einem Minimum von einer Task. Das Skalieren auf null ist mit einem CPU-basierten Metric nicht möglich: Wenn die Task-Anzahl 0 beträgt, gibt es keine CPU zu messen, und die Policy hat kein Signal zum Hochskalieren. Echtes Scale-to-Zero erfordert einen externen Trigger, etwa einen SQS-Queue-Depth-Alarm in Kombination mit einer Step-Scaling-Policy.
Storage
S3-Objekt-Lifecycle-Regeln sind der primäre Hebel für Datenspeicherkosten. Ohne sie häufen sich Objekte unbegrenzt im STANDARD-Speicher an, unabhängig davon, wie oft auf sie zugegriffen wird.
Das allgemeine Modell sind drei Tiers: heiß (STANDARD für häufig zugegriffene Daten), warm (STANDARD_IA nach 30 Tagen für gelegentlich abgerufene Daten) und kalt (GLACIER_IR oder DEEP_ARCHIVE für die Archivierung). Eine Lifecycle-Regel, die das automatisch handhabt:
resource "aws_s3_bucket_lifecycle_configuration" "data_lifecycle" {
bucket = aws_s3_bucket.data.id
rule {
id = "transition-to-cheaper-tiers"
status = "Enabled"
filter {}
transition {
days = 30
storage_class = "STANDARD_IA"
}
transition {
days = 90
storage_class = "GLACIER_IR"
}
transition {
days = 365
storage_class = "DEEP_ARCHIVE"
}
expiration {
days = 2555 # ~7 Jahre; an deine Datenaufbewahrungsrichtlinie anpassen
}
}
}Der filter {}-Block ohne Prefix wendet die Regel auf alle Objekte im Bucket an. Wenn die Regel nur auf ein bestimmtes Prefix angewendet werden soll, ersetze ihn durch filter { prefix = "raw/" }.
Drei Caveats, die vor einer breiten Anwendung dieser Regel bekannt sein sollten. Erstens hat STANDARD_IA eine Mindestaufbewahrungsdauer von 30 Tagen; Objekte, die vorher gelöscht oder gewechselt werden, werden für die vollen 30 Tage berechnet. Zweitens hat STANDARD_IA eine minimale verrechenbare Objektgröße von 128 KB; kleinere Objekte werden berechnet, als wären sie 128 KB groß. Bei Buckets mit vielen kleinen, kurzlebigen Dateien kann STANDARD_IA die Kosten erhöhen statt senken. In solchen Fällen überspringe den STANDARD_IA-Wechsel und wechsle direkt zu GLACIER_IR, sobald die Objekte wirklich kalt sind. Drittens hat GLACIER_IR eine eigene Mindestaufbewahrungsdauer von 90 Tagen, sodass Objekte, die vorher gewechselt oder gelöscht werden, für die vollen 90 Tage berechnet werden. DEEP_ARCHIVE hat eine Mindestdauer von 180 Tagen aus demselben Grund; die obige Lifecycle-Regel wechselt erst ab Tag 365, daher ist dies kein Problem, es sei denn, du verkürzt diesen Wert.
Über Lifecycle-Regeln hinaus sollte die Standard-Architektur für Datenspeicher sein: Daten so lange wie möglich in Object Storage halten und nur dann in ein Data Warehouse laden, wenn du die zusätzliche Abfragestruktur für die Ausspielung benötigst. Alles in Redshift zu speichern, weil es bequemer ist, ist einer der schnellsten Wege, eine hohe Rechnung anzuhäufen.
Allgemeine Infrastruktur
Compute
Für langlebige Workloads wie Kubernetes Node Groups, persistente EC2-Instanzen oder EMR-Cluster, die nach einem vorhersehbaren Zeitplan laufen, bieten Reserved Instances und Compute Savings Plans erhebliche Rabatte gegenüber On-Demand-Preisen. Standard Reserved Instances können auf Drei-Jahres-Laufzeiten bis zu 72 Prozent Rabatt erreichen, im Austausch gegen eine ein- oder dreijährige Verpflichtung. Die Verpflichtung klingt riskant, ist aber in der Regel gerechtfertigt für alles, was in der Produktion kontinuierlich läuft.
Auf der Architekturseite reduziert das Halten von Daten in der Nähe des Ortes, an dem sie verbraucht werden, direkt die Egress-Kosten. Eine Compute-Schicht, die große Datensätze aus einer anderen Region abrufen muss, zahlt bei jeder Ausführung für diesen Cross-Region-Transfer. Quelldata und Processing-Compute in derselben Region und, wo möglich, in derselben Availability Zone zu halten, vermeidet eine Kostenkategorie, die sonst unsichtbar bleibt, bis sie auf der Rechnung erscheint.
Storage
Verwaltete Datenbanken wie RDS, Aurora und Redshift unterstützen ebenfalls reservierte Preismodelle (Reserved DB Instances bzw. Reserved Nodes), und die Einsparungen sind erheblich für alles, was rund um die Uhr läuft. DynamoDBs Reserved Capacity funktioniert anders: Sie gilt nur im Provisioned-Throughput-Modus und wird pro WCU/RCU-Einheit erworben, nicht pro Instanz. Der Fehler, den Teams machen, ist, RI-Käufe als einmalige Entscheidung zu behandeln. RI-Portfolios müssen regelmäßig überprüft werden, mindestens quartalsweise, um sie an veränderte Kapazitätsanforderungen anzupassen. Eine RI, die für einen Redshift-Cluster gekauft wurde, der inzwischen durch Athena ersetzt wurde, ist reine Verschwendung.
Der gemeinsame Faden durch all das ist, dass Kostenkontrolle eine operative Disziplin ist, keine einmalige Bereinigungsübung. Beginne mit dem richtigen mentalen Modell: Du zahlst für das, was existiert. Erzwinge eine Tagging-Strategie vom ersten Tag an. Richte AWS Data Exports ein und baue die Werkzeuge, um Kosten abfragbar zu machen, bevor jemand eine dringende E-Mail über die Rechnung schreibt. Teams, die diese Arbeit im Voraus leisten, verbringen deutlich weniger Zeit mit teuren, zeitkritischen Migrationen.
Wenn du zwei Dinge mitnimmst: Denke bei jedem neuen Projekt von Anfang an an Kosten, und standardisiere deine Tagging-Strategie, bevor du mehr als eine Handvoll Ressourcen hast, die du nachträglich damit ausstatten müsstest.
Häufig gestellte Fragen
Warum sollte AWS-Kostenmanagement proaktiv statt reaktiv sein?
Reaktives Kostenmanagement erzwingt teure, zeitkritische Migrationen. Engineering-Teams, die Kosten von Anfang an als erstklassige Anforderung behandeln, treffen bessere Architekturentscheidungen und vermeiden das nachträgliche Umbauen von Infrastruktur, die nie auf Kosteneffizienz ausgelegt war. Ein Mandat, das erst nach überhöhten Ausgaben kommt, ist zu spät, um die harte Arbeit zu verhindern.
Wie identifiziere ich, welche AWS-Workloads die Kosten treiben?
Richte AWS Data Exports mit aktiviertem Ressourcen-Detail ein und schreibe es nach S3. Frage es mit Athena ab und filtere nach deinen Cost Allocation Tags. Ohne eine vorab eingerichtete Tagging-Strategie ist eine Workload-bezogene Zuordnung allein aus der Rechnung nicht möglich. Cost Explorer kann dir nur sagen, dass EC2 14.000 Dollar ausgegeben hat, nicht welches Team oder welche Pipeline das verursacht hat.
Wann sollte ich Reserved Instances statt On-Demand-Preisen verwenden?
Nutze Reserved Instances für jeden Workload, der kontinuierlich in der Produktion läuft: persistente EC2-Instanzen, dauerhaft aktive RDS-Datenbanken oder EMR-Cluster nach einem vorhersehbaren Zeitplan. Standard Reserved Instances können die Kosten auf Drei-Jahres-Laufzeiten um bis zu 72 Prozent senken. Alles mit variablem oder unvorhersehbarem Bedarf ist besser auf On-Demand oder Spot Instances aufgehoben.
Was ist der günstigste Weg, Datentransformationen auf AWS auszuführen?
Für Datensätze unter wenigen hundert Gigabyte ist DuckDB oder Polars auf einer einzelnen EC2-Instanz deutlich günstiger als ein Spark- oder EMR-Cluster und oft schneller. Für SQL-basierte Transformationen über S3-Daten ist Athena mit einem dbt-Connector eine weitere kosteneffiziente Option. Verteiltes Compute sollte für wirklich großvolumige Workloads reserviert bleiben.
Wie verhindere ich, dass S3-Speicherkosten unbemerkt ansteigen?
Setze S3-Lifecycle-Regeln, um Objekte nach 30 Tagen nach STANDARD_IA, nach 90 Tagen nach GLACIER_IR und nach 365 Tagen nach DEEP_ARCHIVE zu wechseln. Ohne Lifecycle-Regeln verbleiben alle Objekte dauerhaft im STANDARD-Speicher, unabhängig von der Zugriffshäufigkeit. Die Cloud räumt nicht nach dir auf.
Was ist der Unterschied zwischen Cost Explorer und AWS Data Exports (CUR)?
Cost Explorer ist ein Dashboard für Stichproben und grobe Trends. AWS Data Exports (der Nachfolger des bisherigen Cost and Usage Report) ist ein Flat-File-Export jeder Abrechnungszeile auf Ressourcenebene, geschrieben nach S3. Er enthält alle aktivierten Cost Allocation Tags als Spalten und ist das richtige Tool für Workload-bezogene Zuordnung, den Aufbau von BI-Dashboards und Anomalieerkennung. Data Exports unterstützt sowohl das bisherige CUR-Spalten-Schema als auch das neuere offene FOCUS-1.0-Standardformat.