Coral troubleshooting

What to check, in order, when a cluster doesn’t connect or a node isn’t removed.

Updated 29 October 2026 · Published by Zoorik

Coral is not connecting to my cluster

Short answer. To connect, you need a supported cluster, the right access, a new connect command, and a cluster that can reach Zoorik. Check them in the order below. Once the agent registers, the cluster appears on Overview, and its figures follow within minutes.

Check the cluster is supported

Look at: the cluster’s cloud, its Kubernetes version and its nodes.

What it means: Coral works on AKS on Azure and EKS on AWS. Other clusters connect as “Local”, without cloud prices. The cluster needs Kubernetes 1.30 or later, and at least one Linux node, on amd64 or arm64.

What to do: Make sure the cluster meets these before you connect it. A cluster that shows as “Local” still connects, but its figures have no cloud prices.

Check the command points at the right cluster

Look at: the kubeconfig context the connect command uses.

What it means: To connect, you need cluster-admin on the cluster, through a kubeconfig context.

What to do: Add --kube-context <name> to the command to pick the cluster. Run it as a user with cluster-admin.

Check the connect command is new

Look at: when you copied the command, and whether you ran it before.

What it means: The command carries a connect token. The token works only once, and only for a short time after you get it.

What to do: On Overview, open “Connect cluster” again and copy a new command. If you installed with Helm, connect again with a new token:

helm upgrade coral-agent \
  oci://ghcr.io/getzoorik/charts/coral-agent \
  --kube-context <context> --namespace default \
  --reuse-values --set connectToken.value=<new connect token>

With connectToken.existingSecret, replace the token in the Secret, then restart the agent:

kubectl --context <context> -n zoorik-agent rollout restart deployment/zoorik-agent

Check your cloud tools and permissions

Look at: your cloud’s command-line tool, and your permissions in your cloud account.

What it means: zoorikctl lists every change it will make in your cloud and asks you once. To connect, you need:

ClusterToolPermissions
AKS
The Azure CLI (az), signed in
Owner, or Contributor with User Access Administrator, on the cluster’s subscription
EKS
The AWS CLI (aws), signed in
Permission to create IAM roles and EKS Pod Identity associations
EKS, when connect installs Karpenter
Also Helm 3.8 or later
Also SQS, EventBridge and cluster updates

What to do: Sign in, or ask for these permissions, then run the command again. To see what connect will change first, add --dry-run. It prints every cloud command and everything the agent setup installs, and changes nothing.

Check the network

Look at: what the cluster can reach on the internet.

What it means: The agent always starts the connection to Zoorik itself, over HTTPS. Nothing outside the cluster connects in. So the cluster must be able to reach these over HTTPS:

  • Zoorik.
  • ghcr.io and pkg-containers.githubusercontent.com, for the images.
  • Your cloud’s APIs, for node removal: Azure Resource Manager and Entra ID, or AWS STS and Auto Scaling.

What to do: Allow these, then wait for the agent’s first report.

Check what connect set up in your cloud

Look at: your answer when zoorikctl asked about the cloud changes.

What it means: If you said no, the agent still installs. Pools that an autoscaler runs are optimized as usual. Fixed-size pools wait until you give the permission to remove nodes.

On AKS, connect turns on NAP only if the cluster has no autoscaler. NAP needs Azure CNI networking and doesn’t work with kubenet. On kubenet with no autoscaler, nothing adds nodes until you set one up.

What to do: Give the permission to remove nodes when you are ready:

zoorikctl cluster grant-node-deletion

To set up an autoscaler later, run zoorikctl cluster prepare.

Wait for the first report

Look at: Overview, and the cluster’s own pages.

What it means: After you approve, zoorikctl installs the agent and waits for it to register. The cluster then appears on Overview, and its figures follow within minutes. Until data arrives, pages show “Waiting for the agent’s first report…”, then “Calculating”.

What to do: Keep the page open: it updates by itself. Until data arrives, figures read “Calculating” or “Fetching prices”, never a guess. If the page keeps waiting, check the network again.

Check your Helm install

Look at: your helm install command and its values.

What it means, and what to do: If you installed with the coral-agent Helm chart rather than zoorikctl, check these.

IfWhat it meansWhat to do
You installed into zoorik-agent or zoorik-node
The chart creates those two namespaces itself, so the install fails with an ownership error.
Install the release in any other namespace, such as default.
The cluster was connected with zoorikctl before
Helm doesn’t own the objects zoorikctl created, so helm install won’t take them over.
Run zoorikctl cluster disconnect first. Then install the chart with a new connect token.
controlPlaneUrl has a path or a trailing slash
It must be the base address only, exactly as the console shows it.
Remove the path and the trailing slash.
You set connectToken.existingSecret
The agent pod waits until that Secret exists.
Create it in zoorik-agent, with the token under the key bootstrap-token.
EKS, with Pod Identity
The agent gets AWS credentials only if the association exists when its pod starts.
Create the association first. If the agent already runs, restart it once: kubectl --context <context> -n zoorik-agent rollout restart deployment/zoorik-agent
helm install --wait is slow to return
It waits until the agent has stayed ready for a while.
Nothing. This is expected.

If the cluster shows “Not reporting”

Look at: the cluster’s entry in the console.

What it means: After a disconnect, the cluster stays in the console as “Not reporting”. The data Zoorik already received stays with it.

What to do: If you disconnected it, connect it again with a new command from “Connect cluster”. If you didn’t, email us.

If the Agent release card says “Re-run connect”

Look at: the “Agent release” card on the cluster’s Dashboard.

What it means: The agent updates itself to each Zoorik release. It can’t give itself new permissions, so a release that needs more shows “Re-run connect”. An agent that Argo CD, Flux or Helm manages doesn’t update itself.

What to do: Run the connect command again. With Helm, helm upgrade to a newer chart version updates the agent.

Coral is not removing a node

Short answer. As Coral rebalances your cluster, it empties nodes you don’t need, and your autoscaler removes them. A node often stays because a switch is off, a pod can’t move safely, there’s no room elsewhere, or the pool is at its minimum. Node list → “What’s holding them” shows the reason for each held node.

Check Node optimization and the Evictor are on

Look at: Settings, and the Evictor’s “Advanced settings”.

What it means: With Node optimization off, Coral plans no node removal. With the Evictor off, Coral still drains nodes while Node optimization is on.

The Evictor moves pods off lightly used nodes, and has its own switch in Settings → General. In “Dry run”, it only writes the nodes it would empty to the Event log.

What to do: Switch Node optimization on. When you are ready for the Evictor to move pods, switch it on and untick “Dry run”.

Check the node’s pool is enabled

Look at: the pool’s “Enabled” switch in Configuration → Node pools.

What it means: When it is off, Coral leaves that pool’s nodes alone.

What to do: Switch the pool on if Coral may empty its nodes.

Check what is holding the node

Look at: Node list → “What’s holding them”. Its “Nodes held” figure counts the nodes Coral can’t empty.

What it means: A held node is one Coral won’t empty, because a pod on it can’t be moved safely. The common reasons, and the fix for each, are below. How each one holds a node in Kubernetes is in Cluster Autoscaler not scaling down.

ReasonFix
The PodDisruptionBudget allows no disruption.
Add replicas or relax the PodDisruptionBudget.
A kube-system pod has no PodDisruptionBudget.
Add a PodDisruptionBudget that allows at least one disruption.
Data on the node’s own disk (hostPath).
Move the data to a persistent volume, or mark the pod safe to evict.
Nothing would recreate the pod.
Run it under a Deployment or StatefulSet.
Marked do-not-disrupt, not safe to evict, or excluded.
Remove the marker if moving it is fine.

What to do: Apply the fix for each reason. These markers keep a pod, or its node, in place:

  • karpenter.sh/do-not-disrupt: "true", on a pod or a node.
  • cluster-autoscaler.kubernetes.io/safe-to-evict: "false", on a pod.
  • coral.zoorik.com/removal-disabled: "true", on a node or a pod.

Which autoscaler reads which marker is in Safe-to-evict and do-not-disrupt.

Check the other nodes have room

Look at: the room on the cluster’s other Ready nodes, and the Optimization constraints page.

What it means: Before it moves anything, the agent checks the live cluster. Every pod on the node must fit on another Ready node, with its affinity, taints, spread, ports and zones. If a pod doesn’t fit, the node stays.

What to do: If the other nodes have no room, the node is still needed. If placement rules hold a pod here, open Optimization constraints. It lists workload setups that make optimization risky, such as topology spread, with the fix for each.

Check the pool is above its minimum

Look at: how many nodes the pool has, and your autoscaler’s minimum for it.

What it means: Every pool keeps at least one node. Coral also respects your autoscaler’s minimum pool size.

By default, the agent may reduce a pool’s minimum. With the Terraform module’s lower_minimums = false, it can’t.

What to do: The last node in a pool stays.

  • If you set lower_minimums = false, set it back to true, the default, to let the agent reduce the minimum.
  • If Terraform manages your node pools, each apply undoes what the agent changes. Tell Terraform to ignore those fields in your own code, as Your own node pool code shows.

Check who removes the empty node

Look at: a node Coral has emptied that is still in the cluster.

What it means: Coral empties the node, and your autoscaler removes it.

  • After “Wait before removing empty nodes”, Coral hands the empty node to your autoscaler. Its own timers decide when the node goes.
  • Pools that Karpenter or NAP already consolidates are left to them.
  • Coral deletes the machine itself only in fixed-size pools that nothing else manages.

What to do: Check your autoscaler’s own settings. To change Coral’s wait, set “Wait before removing empty nodes” in Configuration → Node scaling.

For a fixed-size pool, Coral needs the permission to remove nodes. If you declined it at connect, run:

zoorikctl cluster grant-node-deletion

If you installed with Helm, Install Coral with Terraform + Helm creates the same permission as code.

Check the node is not cordoned

Look at: the node’s state, and any cluster upgrade under way.

What it means: Coral skips cordoned, NotReady and deleting nodes. It never drains a node someone else cordoned. During a cluster upgrade, it keeps working but stays out of the upgrade’s way.

What to do: If you cordoned the node yourself, Coral leaves it to you. Uncordon it if Coral may empty it. During an upgrade window, we recommend pausing Node optimization and the Evictor.

Check the drain finished

Look at: the Event log, which lists everything Coral did or saw, newest first.

What it means: Coral cordons and drains one node at a time. If a drain can’t finish in time, the node goes back into service.

What to do: Find the node in the Event log. Then check what is holding it, as above.

Still stuck?

The Coral product guide and the Coral FAQ have the full detail.

Email founders@zoorik.com, or pick a time to talk (opens in a new tab). Tell us what you ran and what the console shows, and for a node, what Node list and the Event log show. Remove tokens, keys and other secrets from anything you send.

Find your own number

One line in your cloud console. One PDF report with your estimated saving at list price.

Estimate your saving

Talk to the builders

Thirty minutes with the people who build Coral.

Book a demo (opens in a new tab)

Or write to founders@zoorik.com