cost-optimization

Cloud cost optimization with concrete examples for right-sizing containers, CDN caching, database query costs, serverless tuning, spot instances, reserved capacity, and build time reduction.

Container Right-Sizing

Monitor CPU and memory for 7 days before setting limits. Set requests to P50, limits to P99.

BAD: Guessing resource limits. Over-provisioned containers waste money.

resources:
  requests:
    memory: "1Gi"
    cpu: "1000m"
  limits:
    memory: "2Gi"
    cpu: "2000m"

GOOD: Use actual usage data from monitoring.

kubectl top pod myapp-12345 --containers

If P50 is 200Mi/100m and P99 is 400Mi/300m:

resources:
  requests:
    memory: "200Mi"
    cpu: "100m"
  limits:
    memory: "400Mi"
    cpu: "300m"

Vertical Pod Autoscaler

Get sizing recommendations from real workload data.

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: myapp-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  updateMode: "Off"  # Recommendation mode only

Check recommendations:

kubectl describe vpa myapp-vpa

Cost Calculation

Example: 10 pods running 24/7 with 1Gi memory, 1 CPU.

  • Memory: 10 pods x 1 GiB x $0.0004/hr = $29/month
  • CPU: 10 pods x 1 core x $0.04/hr = $292/month
  • Total: $321/month

Right-size to 200Mi memory, 100m CPU:

  • Memory: 10 pods x 0.2 GiB x $0.0004/hr = $5.80/month
  • CPU: 10 pods x 0.1 core x $0.04/hr = $29.20/month
  • Total: $35/month

Savings: 89% ($286/month)

Horizontal Pod Autoscaler

Scale replicas based on actual load. Do not run excess capacity during low traffic.

BAD: Fixed replica count. Wastes money overnight and weekends.

spec:
  replicas: 10

GOOD: HPA scales from 2 to 10 based on CPU usage.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

Cost Impact

If baseline traffic needs 2 pods and peak traffic needs 10 pods for 2 hours/day:

  • Fixed 10 replicas: 10 x 24hr = 240 pod-hours/day
  • HPA (2 baseline + 8 peak for 2hr): 2 x 24 + 8 x 2 = 64 pod-hours/day

Savings: 73% (176 pod-hours/day)

CDN Caching

Cache static assets with long TTLs. Use content hashes for cache busting.

BAD: No cache headers. Every request hits the origin.

GET /app.js
Cache-Control: no-cache

GOOD: 1-year cache with content hash in filename.

GET /app.abc123.js
Cache-Control: public, max-age=31536000, immutable

API Response Caching

Even 60 seconds of caching eliminates burst traffic.

GET /api/categories
Cache-Control: public, max-age=60, s-maxage=60

Stale-While-Revalidate

Serve cached content while fetching fresh data in the background.

Cache-Control: max-age=60, stale-while-revalidate=300

Cost Impact

Example: 1M requests/month to origin at $0.01/10k requests = $100/month. With 90% cache hit rate: origin requests drop to 100k ($1/month). Savings: 99%.

Database Query Cost

Monitor query frequency x duration. A 10ms query running 10,000/min costs more than a 1s query running once.

BAD: N+1 query in a loop.

const orders = await db.orders.findMany();
for (const order of orders) {
  order.user = await db.users.findUnique({ where: { id: order.userId } });
}

GOOD: Single query with join.

const orders = await db.orders.findMany({ include: { user: true } });

Slow Query Logging

Enable slow query log. Investigate queries over 100ms.

-- PostgreSQL
SET log_min_duration_statement = 100;

-- MySQL
SET long_query_time = 0.1;

Use EXPLAIN ANALYZE to find missing indexes.

EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123;

Serverless Cold Starts

BAD: Java Lambda with 1GB memory, VPC attached. Cold start: 5 seconds.

GOOD: Node.js Lambda with 512MB memory, no VPC. Cold start: 200ms.

Lambda allocates CPU proportional to memory. Under-provisioned memory = slower execution = higher duration costs.

Provisioned Concurrency

Eliminate cold starts for latency-sensitive functions. Cost: ~$26/month for 5 concurrent x 512MB. Use only for critical functions.

Build Time Optimization

Cache dependencies. Download once, reuse until lockfile changes.

BAD: Installing dependencies on every build.

COPY . .
RUN npm install

GOOD: Cache dependencies in a separate layer.

COPY package*.json ./
RUN npm ci
COPY . .

Parallel Build Steps

Run linting, type checking, and tests concurrently in CI. Total time = max(build, lint, test), not sum.

Turborepo Remote Cache

Share build artifacts across CI machines. First build uploads cache, subsequent builds skip rebuilding. Savings: ~70% on CI costs.

Spot Instances, Reserved Capacity, and Cost Monitoring

AWS spot instances (70-90% savings), reserved instances (40% savings), budget alerts, resource tagging, and non-production shutdown automation. See references/cloud-examples.md for detailed configs and scripts.