Cloudrekeningen groeien regelmatig sneller dan het daadwerkelijke applicatieverkeer. In Azure Kubernetes Service (AKS)-omgevingen stellen engineeringteams vaak te ruime CPU- en geheugenreserveringen in om pod-evictions te voorkomen, configureren ze database-connectiepools verkeerd over tientallen microservices en laten ze ongebruikte opslag gekoppeld aan actieve clusters. Een gestructureerde audit van cloudkosten en performance brengt deze structurele inefficiënties aan het licht en verlaagt de maandelijkse Azure-uitgaven zonder de stabiliteit van workloads in gevaar te brengen.
Fase 1: Pod-Resourceverspilling Diagnostiseren met Prometheus en VPA
Kubernetes plant workloads in op basis van pod-resource requests, niet op basis van daadwerkelijk verbruik. Wanneer een engineeringteam ruime veiligheidsmarges instelt (zoals het aanvragen van 2 CPU-cores en 4 GB RAM voor een API-service die gemiddeld 0,15 cores en 600 MB RAM gebruikt), reserveert de Kubernetes scheduler die capaciteit op de node. De node rapporteert een hoge bezetting terwijl de onderliggende hardware niets doet, waardoor de Azure cluster autoscaler gedwongen wordt dure extra virtuele machines op te starten.
| Resource Veld | Kubernetes Scheduler Gedrag | Runtime Handhaving & Kostenimpact |
|---|---|---|
requests.cpu |
Reserveert nodecapaciteit tijdens schedulingbeslissingen | Bepaalt het totale aantal nodes en de directe Azure VM-kosten |
limits.cpu |
Genegeerd door de scheduler | Handhaaft CFS throttling-quota; overmatige throttling verslechtert de P99-responstijd |
requests.memory |
Reserveert fysiek RAM-geheugen op de worker node | Voorkomt node-overcommit; bepaalt de omvang van node pools |
limits.memory |
Genegeerd tijdens scheduling | Activeert de Linux cgroup Out-Of-Memory (OOM) killer die de container beëindigt |
Stap 1: Kwantificeer CPU- en Geheugenreserves met PromQL
Audit container-allocaties door aangevraagde capaciteit te vergelijken met het daadwerkelijke 95e percentiel-verbruik over een periode van 14 dagen:
# PromQL: Bereken onbenutte CPU-requests per Deployment
sum(kube_pod_container_resource_requests{resource="cpu"}) by (namespace, container)
- sum(quantile_over_time(0.95, container_cpu_usage_seconds_total[14d])) by (namespace, container)
# PromQL: Bereken de overprovisioning-ratio voor geheugen
(sum(kube_pod_container_resource_requests{resource="memory"}) by (namespace, container)
- sum(quantile_over_time(0.95, container_memory_working_set_bytes[14d])) by (namespace, container))
/ sum(kube_pod_container_resource_requests{resource="memory"}) by (namespace, container)
Workloads met meer dan 50% aanhoudende overcapaciteit in CPU of geheugen moeten worden bijgesteld in hun pod-manifesten.
Stap 2: Verzamel Aanbevelingen met de Vertical Pod Autoscaler (VPA)
Implementeer de Kubernetes Vertical Pod Autoscaler in Off-modus. In deze modus berekent VPA historische verbruikspercentielen en schrijft aanbevelingen direct naar de resource status zonder draaiende pods te herstarten.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: order-processing-service-vpa
namespace: production
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: order-processing-service
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 100m
memory: 256Mi
maxAllowed:
cpu: 2000m
memory: 4Gi
controlledResources: ["cpu", "memory"]
Lees de aanbevelingen uit via kubectl get vpa -n production -o yaml. Vergelijk de waarden van target en lowerBound met de huidige specificaties om potentiële node-besparingen te bepalen.
Fase 2: Valkuilen in Database Connection Pooling en Trage Queries
In gedistribueerde .NET-microservices op AKS leidt database-connectiebeheer geregeld tot onnodige kostenstijgingen. Teams schalen pod-replica's op tijdens piekmomenten, waardoor het aantal actieve databaseverbindingen ongemerkt explodeert totdat de database vastloopt of overbelast raakt.
De Vermenigvuldigingsval
Standaard ADO.NET- en Npgsql-connectiepools staan tot 100 verbindingen per proces toe. Wanneer een service onder belasting opschaalt van 3 naar 30 pods, springt het potentiële aantal verbindingen van 300 naar 3.000. Een Azure SQL Database of PostgreSQL Flexible Server bereikt zijn connectielimiet, waardoor teams geneigd zijn om dure hogere tiers te kiezen puur voor connectiegeheugen.
SNAT-Poortuitputting
Kortstondige databaseverbindingen of niet-gepoolde uitgaande HTTP-clients putten de SNAT-poorten van de Azure Load Balancer uit. Onder zware belasting leidt dit tot willekeurige time-outs, wat ten onrechte wordt toegeschreven aan databaseproblemen.
Connectiepools Optimaliseren in .NET Workloads
Beperk de omvang van de client-side pool en plaats een dedicated server-side connection pooler (zoals PgBouncer voor PostgreSQL of Azure SQL Database Elastic Pools) tussen de containers en de database:
// appsettings.Production.json
{
"ConnectionStrings": {
"PrimaryDatabase": "Server=tcp:sql-neneos-prod.database.windows.net,1433;Database=orders;Authentication=Active Directory Default;Max Pool Size=20;Min Pool Size=2;Connection Timeout=15;Pooling=true;"
}
}
Door Max Pool Size=20 per pod in te stellen, blijft het totale aantal verbindingen onder de 400 bij 20 pod-replica's. Hierdoor kan de database op een lagere vCore-tier draaien met een voorspelbaar geheugenprofiel.
Niet-Geïndexeerde Queries Oplossen
Ontbrekende indexen dwingen de database tot volledige table scans, wat leidt tot pieken in IOPS en CPU-gebruik. Bij Azure SQL en Azure Database for PostgreSQL maskeert een hoog compute-verbruik vaak ontbrekende indexen. Organisaties upgraden regelmatig van een 4-vCore instantie (€280/maand) naar een 16-vCore instantie (€1.120/maand) om querypieken op te vangen die met een eenvoudige index opgelost hadden kunnen worden.
Voer tijdens de audit gerichte query-analyses uit om de zwaarste CPU-verbruikers te identificeren:
-- Azure SQL / SQL Server: Top 5 Queries op Basis van Totale CPU-werktijd
SELECT TOP 5
qs.total_worker_time / qs.execution_count AS AvgCpuTimeMicroseconds,
qs.execution_count,
SUBSTRING(st.text, (qs.statement_start_offset/2)+1,
(((CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(st.text)
ELSE qs.statement_end_offset
END) - qs.statement_start_offset)/2) + 1) AS StatementText,
qp.query_plan
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp
ORDER BY qs.total_worker_time DESC;
Fase 3: Noisy Neighbors en Inefficiënte Opslag Aanpakken
Zonder expliciete resourcebeperkingen en opslagbeleid veroorzaken achtergrondtaken en verweesde data verborgen kosten binnen het cluster.
Noisy Neighbors Beheersen via Quality of Service (QoS)
Batchverwerking en synchronisatietaken die op dezelfde nodes draaien als klantgerichte API's veroorzaken CPU-starvation en netwerkvertraging wanneer QoS-klassen ontbreken. Kubernetes kent QoS toe op basis van hoe requests en limits zijn gedefinieerd:
- Guaranteed: CPU- en geheugen-
requestszijn exact gelijk aanlimits. De node-kernel reserveert de resources en voorkomt het wegsturen van deze pods. Gebruik dit voor bedrijfskritische API's. - Burstable:
requestszijn lager danlimits. Pods kunnen onbenutte headroom benutten wanneer beschikbaar. Geschikt voor standaard applicaties met wisselend verkeer. - BestEffort: Geen requests of limits ingesteld. Deze pods worden als eerste beëindigd bij geheugentekort. Sta geen BestEffort-pods toe in productieomgevingen.
Stel LimitRanges in om standaard requests en limits per namespace af te dwingen:
apiVersion: v1
kind: LimitRange
metadata:
name: core-limits
namespace: production
spec:
limits:
- default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 256Mi
type: Container
Verweesde Schijven en Overbemeten Opslag Opschonen
Wanneer PersistentVolumeClaims (PVC's) of AKS-worker nodes worden verwijderd, blijven onderliggende Azure Managed Disks soms ontkoppeld achter terwijl de maandelijkse opslagkosten gewoon doorlopen.
Spoor ontkoppelde managed disks op via de Azure CLI:
# Toon alle ontkoppelde beheerde schijven binnen het abonnement
az disk list \
--query "[?managedBy==null].[id, resourceGroup, name, diskSizeGb, sku.name]" \
--output table
Fase 4: Concrete Maatregelen voor Structurele Run-Rate Verlaging
Nadat individuele workloads zijn geoptimaliseerd, kunnen infrastructurele kostenbesparingen over het hele cluster worden doorgevoerd:
Gespecialiseerde Node Pools & Spot VM's
Scheid continue applicaties van asynchrone achtergrondtaken. Draai achtergrondverwerking en batchtaken op Azure Spot VM node pools voor kortingen tot 70–80% ten opzichte van reguliere prijzen.
Event-Driven Schalen met KEDA
Vervang vaste replica-aantallen door KEDA-scalers op basis van Azure Service Bus- of RabbitMQ-wachtrijlengtes. Schaal verbruikers buiten piektijden terug naar nul en schaal alleen op wanneer er berichten binnenkomen.
Log Analytics Ingestion Filtering
Azure Monitor en Container Insights kunnen aanzienlijke data-ingestiekosten veroorzaken. Filter hoog-frequente HTTP 200 health-checks en uitgebreide debug-logs al op collectorniveau.
Azure Savings Plans & Reserveringen
Na het elimineren van verspilling en het stabiliseren van de basiscapaciteit kunnen 1- of 3-jarige Azure Savings Plans voor Compute worden ingezet om 40–60% korting te borgen op de stabiele basisvoetafdruk.
Audit Checklist: Cloudkosten en Prestaties
Gebruik deze referentiechecklist tijdens periodieke architectuurbeoordelingen en infrastructuuraudits:
Kubernetes & Compute
Databases & Netwerk
Opslag, Logging & Reserveringen
Onafhankelijk Cloud Architectuuradvies
Het auditen van een complex multi-cluster cloudlandschap vereist diepgaande inspectie van applicatiecode, containerorkestratie en cloudconfiguraties.
Onze Software Architecture Assessment, Kubernetes & Cloud Native en Azure Cloud Engineering diensten bieden diepgaande technische inspecties van je infrastructuur en codebase. We brengen verborgen kostenposten in kaart, lossen prestatieknelpunten op en leveren een concreet verbeterplan voor jouw engineeringteam.