> For the complete documentation index, see [llms.txt](https://docs.akamas.io/insights/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.akamas.io/insights/analysis-and-recommendations/node-groups-recommendations.md).

# Node Groups Recommendations

The Node Groups tab within the Cluster Analysis page provides recommendations for optimizing your Kubernetes node pools. This tab helps you identify opportunities to select more cost-effective instance types while maintaining the capacity your workloads require.

## Supported Autoscalers

Akamas Vivo supports node group recommendations for clusters using:

* **Kubernetes Cluster Autoscaler** - The standard autoscaler for Kubernetes clusters;
* **Karpenter** - A flexible, high-performance node provisioner.

## How Node Groups Are Identified

Akamas Vivo identifies node groups by reading Kubernetes node labels. The platform automatically detects the appropriate label based on your cloud provider:

* **EKS**: `eks.amazonaws.com/nodegroup`
* **GKE**: `cloud.google.com/gke-nodepool`
* **AKS**: `agentpool`
* **Karpenter**: `karpenter.k8s.aws/instance-family` and related labels

Nodes without the expected label are grouped together as "Unidentified nodes" and can still receive recommendations. You can also select a custom label if your environment uses non-standard node pool identification.

### When no label identifies your node groups

Some monitoring pipelines drop the label that names the node pool, leaving nothing in the labels to group nodes by. If your node names carry the pool instead, as in `aks-mypool-a1b2c3d4-vmss000000`, you can set a node name pattern for your organization under Settings, Advanced, "Nodepool Identification by Node Name".

The label configuration panel on a cluster's Node groups tab points here as well: whenever node groups are identified automatically and no pattern is set, it says that a node name pattern can group them instead.

The pattern is a regular expression with one capture group selecting the part of the name that names the pool: `^aks-([^-]+)-` groups the node above under `mypool`. With no capture group, the whole match is used. The pattern is matched anywhere in the name, so add `^` to anchor it to the start as in that example. Node names the pattern does not match are grouped together as "Unidentified nodes", exactly as nodes missing the label are. The Node groups tab tells you how many nodes the pattern matched, so a pattern written for a different naming convention does not go unnoticed: if it matches nothing, every node lands in that one group and no meaningful recommendation can be made for it.

Keep the pattern simple: literals, character classes, anchors and one capture group. Lookarounds and backreferences are not accepted, because a node name never needs them and they can make matching extremely slow across a large fleet. Use `(?:...)` to group part of a pattern without capturing it. A pattern that is refused when you save it tells you why, and your previous pattern stays in place.

Naming conventions come from the cloud provider rather than from a single cluster, so one pattern normally covers every cluster of the same provider in your organization. The pattern takes priority over the organization default label, and a label saved for a single cluster on its Node groups tab still takes priority over both.

## Node Groups Analysis

![Cluster Node Groups Tab](https://987903283-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FAxUCNi77PcMdZAmajVK6%2Fuploads%2Fgit-blob-f8dd998b3fb55652fc6830179949bdfe5d515f62%2Fcluster-node-groups-tab.png?alt=media)

The Node groups tab provides recommendations for Kubernetes cluster autoscaler configuration:

**Node Pool Configuration**:

* Current node pool sizes;
* Recommended minimum and maximum nodes;
* Recommended instance types;
* Cost implications of changes.

**Autoscaler Settings**:

* Scale-up and scale-down thresholds;
* Resource utilization targets;
* Buffer capacity recommendations.

## Which instance types are compared

The Instance Comparison table shows ten rows: your **current instance type**, the **three cheapest** alternatives, the **three with the lowest performance-aware cost**, and the **three fastest per core**.

The three sets answer different questions, and they often don't overlap. The cheapest types minimize your bill against the CPU your workloads reserve today. The lowest performance-aware cost minimizes it against the work your workloads actually do — so a faster instance type can be the better deal even when its hourly price is higher, and it would never appear in a plain "cheapest" list. The fastest-per-core types ignore cost altogether and simply name the quickest hardware, on AWS only — useful when raw performance itself is what you're shopping for, independent of what it costs.

When an instance type qualifies on more than one count it appears only once, and each freed place goes to the next-best candidate of the set that lost it, so no row is wasted on a duplicate. If performance data isn't available for a node group — for example on Azure, Google Cloud, and OCI clusters — the six performance places (both sets) are filled by the next-cheapest instance types instead.

You'll see fewer than ten rows only when fewer than nine alternatives are available to compare: narrow **Recommendation filters** (the "N / M instance types matched" badge tells you how many are left) or a minimum-nodes setting that rules types out can both shrink the set.

### The change next to every cost

Each candidate's **Cost** carries the change against what you pay today, in two places: the **percent** sits beside the monthly figure itself, and the same change in **dollars** on the line below it. Both are signed the same way — a cheaper candidate reads "-10%" and "-$120", a pricier one "+12%" and "+$120". A candidate that would cost you *more* says so rather than hiding it. Your current instance type's row shows no change: it is the figure everything else is measured against. A difference too small to show as a whole dollar is left off entirely rather than displayed as "$0".

This applies on every cloud provider. On AWS the **Performance-Aware Cost** column below carries the same annotation on its own figure.

### When your cluster's region isn't detected

Instance prices differ by region on AWS, Google Cloud and Azure, so pricing a node group needs to know where your cluster runs. That comes from the `topology.kubernetes.io/region` label on your nodes.

When no node carries it, costs are priced from a default region instead: `eu-central-1` on AWS, `us-central1` on Google Cloud, `eastus` on Azure. A caption above the table says so and names the region used, because those figures may not match what your cloud provider actually bills you. To get accurate costs, make sure your nodes expose the region label and run the data import again.

Two things you may see as a result. If the price list covers your instance type but not in that default region, the node group reports that it cannot be priced and says which region was tried. And on a provider that has no default region, node groups are not priced at all rather than being priced from a guess.

## Adjusting the Recommendation Filters

Each node pool has a **Recommendation filters** panel that lets you narrow which instance types the engine considers when computing a recommendation.

* The panel header shows an **"N / M instance types matched"** badge: how many of the node pool's available instance types satisfy the filters currently in force, the defaults included. It sits next to the **Recommendation filters** toggle, so you can read it whether the panel is open or collapsed. The badge stays gray while you have set no filter of your own, and is highlighted once one of your filters narrows the set. Gray does not mean nothing is filtered: each minimum starts at a value taken from the node pool's current instance types, and some instance types (burstable, EC2 Flex, older generations) are excluded by default.
* One filter is **off until you switch it on**: **Exclude slower instance types**, on the **Exclude presets** tab. The five minimums (clock speed, network performance, allocatable vCPU, memory, pods) always apply, starting from values taken from this node pool's current instance types. This one does nothing until you turn it on, and it then drops every instance type whose cores are slower than the hardware you run today, measured by the **Performance Index** column. There is no number to enter: a candidate is either at least as fast as today or it is not. It is grayed out where it cannot be applied, and says which of the two reasons applies: no performance data for this node pool, the same ones whose Instance Comparison table shows no performance columns, or performance data for the node pool but for none of the instance types it could move to. If you had already switched it on, the switch stays on and grayed out: the setting is kept, it is not being applied, and it takes effect again once the filter can be used. Two consequences are worth knowing before you switch it on:
  * Instance types with no performance data are dropped too, because we cannot show they are fast enough. The filter can therefore rule out an instance type whose speed is unknown to us rather than known to be low.
  * The comparison is against one baseline for the whole node pool, not against each instance type on its own, so a slower type you run today can be dropped as well.
* Every active filter appears as a **removable chip** in an **ACTIVE** row that stays visible even when the panel is collapsed. Click a chip's **✕** to clear that single filter. When no filter is set, the open panel reads "No custom filters. The engine applies default limits based on this node group's current instance types."
* While you have edits that have not yet been saved, the panel offers a way back: use **"Reset to last saved"** to revert just the Instance properties back to the values that were last applied, or **"Discard changes"** to revert all of your edits to the last saved state. **"Discard changes"** and **"Save and Apply"** stay in the footer at all times and simply enable once you have unsaved edits; the **"Reset to last saved"** link appears only while you have them.

Filters are saved **centrally for the cluster**, so applying them updates the recommendation that everyone viewing this cluster sees. To apply your changes, click **Save and Apply** (available only once you have unsaved changes). A confirmation dialog appears first — confirming saves the filters and recomputes the node groups recommendation, and you'll see a "Filters saved" notification. Nothing is changed for other viewers until you confirm.

{% hint style="warning" %}
Node groups recommendations require additional cluster autoscaler integration and may not be available in all deployments.
{% endhint %}

## Performance-aware costs (AWS)

Not every CPU core does the same amount of work. A newer processor generation, or a different processor vendor, can complete the same workload using fewer CPU cycles — or, moving to an older/slower option, may need more. Two instance types can have identical vCPU counts, memory, and price, and still deliver meaningfully different real-world performance.

For AWS clusters, the Instance Comparison table adds two columns that account for this:

* **Performance Index** — the estimated work done per CPU core by a candidate instance type relative to your current one, expressed as a multiplier: "1.20x" for a candidate whose cores are estimated to do 20% more work than your current core, "0.85x" for a slower one, "1.00x" for parity.
* **Performance-Aware Cost** — what your monthly cost would look like once that performance difference is factored in, presented exactly like the **Cost** column so the two are directly comparable. It assumes every workload's CPU reservation is eventually right-sized to the new hardware's actual capabilities — the full potential of the instance type itself, which is also why it ranks the candidates and drives the **Best price performance** badge: choosing an instance type is a hardware decision, and it shouldn't score differently just because your workloads happen to be more or less instrumented today.

The instance type whose performance-aware cost is lowest carries a **Best price performance** badge next to its name, alongside the **Current** and **Best cost** badges. It is often *not* the cheapest row: a faster instance type can do the same work on fewer nodes, and come out ahead despite a higher hourly price.

When it *is* the cheapest row, that row carries both badges. The two are measuring different things — hourly price, and price once performance is accounted for — so them agreeing means the same instance type is both the cheapest and the best value, which is a stronger result than either badge on its own.

Separately, the instance type with the highest Performance Index carries a **"Best performance"** badge — a different question, answered without regard to cost. Since it ignores price entirely, it can land on a row that costs *more* than your current setup; that's expected, not a bug, for a badge that's naming the fastest hardware rather than the best deal. When two or more candidates tie on Performance Index (rounded to the two decimals you see on screen), the cheaper one carries the badge.

Hovering over a Performance-Aware Cost value shows this tooltip:

> Modeled estimate from industry-standard CPU benchmark and vendor performance data. It assumes the CPU request of every workload is eventually rightsized to the new hardware. The change is against the current observed cost, and assumes freed capacity can be reclaimed.

### What you'll see

* Your **current instance type's row** shows "Baseline" instead of a number in both performance columns — it's the reference point every other row is measured against, not a comparable estimate.
* A candidate instance type with no available performance data shows "Not available" rather than a number or a blank cell. Its ordinary **Cost** and change still appear as usual.
* When performance data is not available for a node group, these two columns are not shown at all, and neither the **Best price performance** nor the **Best performance** badge appears. Today that means Azure, Google Cloud, and OCI clusters: the underlying performance data currently only covers AWS instance types.
* The **Instance Type** column stays fixed on the left as you scroll the table sideways, so you can always tell which row a figure belongs to. The **Performance Index** column can be dragged wider if you want more room for its header.
