[ CORRUPTED_GLITCH // TRANSMISSION_project-04-k8s-autoscaling-efk ]

DATE ......

READ_TIME . 3 MIN

WORDS ..... 495

CHANNEL ... DEVOPS / INFRASTRUCTURE

REVISED ...

Project 04: Kubernetes Autoscaling & the EFK Observability Stack

Full build log: HPA/VPA autoscaling that cut cloud waste 20%, plus a centralized Elasticsearch–Fluentd–Kibana pipeline that drove MTTR down.

The mission: stop paying for idle pods and stop debugging production by kubectl logs-ing one pod at a time. Two builds, one outcome: a cluster that scales itself and explains itself.

[ CLUSTER PARAMS ]

SCALING
HPA (traffic) + VPA (right-sizing)
LOGGING
Fluentd DaemonSet → Elasticsearch → Kibana
RESULT
−20% cloud over-provisioning
MTTR
minutes, not hours

#Architecture

          ┌─────────────── K8S CLUSTER ───────────────┐
 traffic ─▶ ingress ─▶ [ pods ×N ] ◀── HPA (CPU/RPS)  │
          │               │  ▲                        │
          │               │  └────── VPA (requests)   │
          │          stdout/stderr                    │
          │               ▼                           │
          │        [ fluentd DaemonSet ]              │
          └───────────────┼───────────────────────────┘
                          ▼
                 [ elasticsearch ] ──▶ [ kibana ]
                   (retention ILM)      (dashboards
                                         + alerts)

#Step 1 — HPA on a Signal Users Feel

CPU-only autoscaling lies for I/O-bound services. Scale on requests-per-second alongside CPU:

k8s/hpa.yaml YAML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 3
  maxReplicas: 40
  metrics:
    - type: Pods
      pods:
        metric: { name: http_requests_per_second }
        target: { type: AverageValue, averageValue: "80" }
    - type: Resource
      resource:
        name: cpu
        target: { type: Utilization, averageUtilization: 65 }
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300  # no flapping

#Step 2 — VPA in Recommendation Mode First

VPA in Auto mode restarts pods to resize them. Run it in Off (recommend-only) for two weeks, then set requests from its data:

ops/vpa-recommendations.sh BASH
1
2
3
4
5
6
kubectl get vpa api-vpa -o jsonpath='{.status.recommendation.containerRecommendations[0]}' | jq
# {
#   "target":     { "cpu": "210m", "memory": "340Mi" },
#   "upperBound": { "cpu": "540m", "memory": "512Mi" }
# }
# Old request: cpu 1000m / mem 1Gi  →  we were paying 4x for nothing

#Step 3 — EFK: One Query Instead of Forty Pods

Fluentd runs as a DaemonSet, tails every container, enriches with pod metadata, ships to Elasticsearch:

efk/fluentd-values.yaml YAML
fluentd:
  configMapConfigs:
    - fluentd-prometheus-conf
  fileConfigs:
    01_sources.conf: |
      <source>
        @type tail
        path /var/log/containers/*.log
        <parse> @type cri </parse>
      </source>
    02_enrich.conf: |
      <filter kubernetes.**>
        @type kubernetes_metadata   # namespace, pod, labels
      </filter>

Retention is an ILM policy — hot 7 days, warm 30, delete at 90. Log storage stopped being a surprise line item.

#Results

MetricBeforeAfter
Cloud over-provisioningbaseline−20%
MTTR (prod incidents)hoursminutes
Log searchper-pod ssh/kubectlone Kibana query
Scale eventsmanual, reactiveautomatic, boring

[ RELATED_SIGNALS ]