← All articles
KUBERNETES / AUTOSCALING / CONTROL THEORY

Fuzzy Logic for
Kubernetes Autoscaling.

A multi-signal, asymmetric scaling controller using Mamdani inference, centroid defuzzification and Kubernetes-native integration.

Engineering deep dive

Updated using the author-provided technical draft: architecture, mathematical model, worked scenarios, implementation outline and production considerations. Illustrative calculations are not benchmark measurements.

The problem: crisp thresholds and limit cycling

Kubernetes HPA uses a proportional calculation against a target metric. When demand oscillates near a target, replica counts can also oscillate. The article explores using fuzzy membership to reason across CPU, latency and queue depth rather than relying on a single hard boundary.

desiredReplicas = ceil(currentReplicas × currentMetricValue / desiredMetricValue)

Architecture: Prometheus → fuzzy controller → Kubernetes

Workload telemetry is collected through Prometheus. A fuzzy inference service computes a recommendation from CPU utilization, latency and queue depth. A metrics adapter can expose an appropriately transformed metric to Kubernetes HPA, which remains responsible for replica limits and scaling events. The controller is a proposed architecture, not a demonstrated production deployment.

Fuzzification

Each input is mapped to degrees of membership in low, medium and high sets. The original example defines CPU membership sets low (0, 0, 50), medium (30, 55, 80), and high (60, 100, 100). These memberships represent degrees of category fit, not probabilities.

μ(x) = 0 outside the triangle
μ(x) = (x − a)/(b − a) for a < x ≤ b
μ(x) = (c − x)/(c − b) for b < x < c

Mamdani inference and centroid defuzzification

Rules combine memberships using the minimum t-norm. Consequents are aggregated by maximum, and the centroid of the output membership surface yields a numerical replica adjustment.

IF CPU is HIGH AND latency is HIGH THEN up_fast
wᵢ = min(μ_cpu_high, μ_latency_high)
z* = Σ[μ_agg(z) × z] / Σ μ_agg(z)

Scenario A: flash-sale spike

Illustrative input: 5 replicas, CPU 78%, latency 340 ms, queue depth 90. The worked example uses firing strengths 0.36 for up_fast and 0.08 for up_slow, with a simplified discrete centroid calculation giving approximately +3 replicas. The intended result is 5 → 8 replicas. This is a hand-worked example, not measured benchmark data.

z* = (0.08 + 0.16 + 1.08 + 1.44) / (0.08 + 0.08 + 0.36 + 0.36)
   ≈ 3.14 → +3 replicas

Scenario B: traffic recedes

With CPU 25%, latency 80 ms and queue depth 5, the low-load rule fires with strength 0.467. The source illustrates a slower scale-down of roughly one or two replicas, with an additional recommendation to cap shrinkage to one replica per cycle. The downscale illustration is intentionally asymmetric to avoid aggressive contraction.

w = min(0.5, 0.467, 0.917) = 0.467
Proposed safety clamp: Δt = clamp(round(z*), −1, 5)

Implementation: Python and scikit-fuzzy

The proposed controller uses NumPy and scikit-fuzzy for membership sets, Mamdani rules and a replica-delta output. The source also sketches a Prometheus polling loop, a metrics-adapter mapping and an autoscaling/v2 HPA manifest. These pieces need integration work and validation before they form a deployable solution.

cpu = ctrl.Antecedent(np.arange(0, 101, 1), 'cpu')
latency = ctrl.Antecedent(np.arange(0, 501, 1), 'latency')
queue = ctrl.Antecedent(np.arange(0, 201, 1), 'queue')
scale = ctrl.Consequent(np.arange(-5, 6, 1), 'scale')

rules = [
  ctrl.Rule(cpu['high'] & latency['high'], scale['up_fast']),
  ctrl.Rule(cpu['high'] & queue['high'], scale['up_fast']),
  ctrl.Rule(cpu['medium'] & latency['high'], scale['up_slow']),
  ctrl.Rule(cpu['low'] & latency['low'] & queue['low'], scale['down_slow']),
]

Engineering validation and operational safeguards

Run the controller in shadow mode across peak traffic before applying its output. Keep the rule base small and version membership functions as code. Validate behavior with known scenarios, metric outages and replica bounds. For steady workloads, standard HPA may be simpler and more maintainable. Published controlled edge-computing studies are cited in the original material, but they do not establish universal gains for production SaaS workloads.

Implementation note

The draft HPA manifest uses an External metric target of 0 while the controller emits a signed replica delta. A zero target is not a valid working proportional HPA target, and a delta is not directly interchangeable with an HPA metric ratio. A production implementation needs a positive target and a correctly defined metric contract or a dedicated scaling controller. The sample also references compute_delta without supplying its complete implementation. Treat the code as an architectural sketch, not copy-paste deployment instructions.

The supplied triangular membership definitions also need boundary handling and numerical validation before treating the hand-calculated scenarios as exact outputs of scikit-fuzzy.

Read the original publication

See the full discussion, references and diagrams on Medium.

Open on Medium ↗

← Back to all articles