AIOps & GenAI
A Kubernetes scheduler that forecasts memory: the same work in 16 minutes, from 37
Who the client is
An internal CodiLime proof of concept, built for teams that run Kubernetes at scale: cloud-native SaaS and platform teams on multi-tenant clusters under cost and SLA pressure, and enterprises moving to Kubernetes that struggle with right-sizing. The best fit is a large development environment with predictable usage patterns and known over-provisioning.
The challenge
Kubernetes places Pods by their declared requests and limits, static numbers that describe a dynamic workload poorly. Set a cyclic application’s request at its peak and the reserved capacity sits idle for most of the cycle; set it lower and Pods risk OOM kills when applications peak together. Teams pick a conservative middle and pay for half-empty nodes, and tuning requests and limits by hand takes engineering time and goes stale as workloads change.
What was at risk:
- Paying for half-empty nodes, OOM kills when workloads peak together, and engineering time spent tuning requests and limits by hand
What we did
- Collected resource-utilization metrics with Prometheus and built analytical models that detect usage patterns and forecast them.
- Learned three kinds of workload: cyclic applications, non-cyclic workloads through time-series forecasting, and Jobs, whose Pods repeat the same resource signature across runs.
- Stored per-workload and aggregated per-node forecasts in InfluxDB, with a node evaluator scoring every node against them continuously.
- Wrote a custom Go plugin that hooks Kubernetes’ filtering and scoring through a REST API, inside the existing scheduling framework, with the scheduler itself unchanged.
- Measured it against the standard scheduler on four 16Gi worker nodes running cyclic applications and three batch Jobs of 50 Pod completions each.
How it works
Learning and scheduling run as separate parts that meet at Kubernetes’ own extension points, in five stages.
- Observe Prometheus collects resource-utilization metrics from every workload in the cluster.
- Learn Analytical models identify each workload’s pattern. Cyclic applications repeat, so they get an hour-by-hour forecast in place of a constant peak reservation. Non-cyclic workloads get time-series forecasting. Jobs and CronJobs run concurrent Pods with the same code, so they show a repeatable signature across runs. Workloads that peak at different times, such as one in the morning and one in the evening, can then share a node.
- Forecast Forecasts are stored in InfluxDB per workload and aggregated per node, so the system knows how much memory each node will use in the coming period.
- Score A node evaluator scores every node continuously against those forecasts.
- Place When a Pod reaches the scheduler, the Go plugin joins the filtering and scoring stages through a REST API, and the standard scheduler binds the Pod to the node with forecast headroom. Static requests, limits, autoscaling and policy constraints all stay in force.
In the lab test the three Jobs had different memory shapes (flat, high-start and low-start, up to 4G per Pod). With requests sized for the peak, the standard scheduler ran one Job Pod per node at a time. The forecasting scheduler recognized both the application cycles and the Job signatures, put more Pods into the valleys and fewer at the peaks, stayed under capacity, and finished in 16 minutes, from 37.
The approach adds software components and analytics compute, and that cost grows with the number of deployments and patterns modelled, so it pays off on large clusters. A move to production goes through shadow scheduling and canary rollouts, with confidence-aware placement, drift detection and a conservative fallback.
Outcomes
Business
16 vs 37 min (same Kubernetes workload with our ML scheduler, lab PoC)
A scheduler plugin that places Pods by forecast usage finished the same Jobs in 16 minutes, from 37, with zero observed OOM kills.
Technical
0 OOM kills
Packing more Pods onto the same nodes caused no observed OOM kills.
Made possible
More Pods in the valleys
Pods placed by forecast usage fill each node’s quiet periods and avoid its peaks, while staying under capacity.
Scale and portability
A plugin, no scheduler fork
The plugin works through Kubernetes’ own scheduling framework, with static requests, limits, autoscaling and policies still in force.
Tech & stack
Telemetry and forecasting
Prometheus
InfluxDB
- Time-series forecasting
- Seasonal pattern detection
- Filtering and scoring extension points
- Custom scheduler plugin
- REST API
Anonymized example — fuller write-up available on request.
