Kubernetes

Pod and rollout failures as incidents, the cause read from the cluster, and approved rollbacks, restarts and volume growth.

With this connector 3AM watches the namespaces you choose, works out why a workload is failing from the API server alone (no metrics stack needed), and fixes it with your approval. It is also how fixes found by other connectors get carried out: when VictoriaMetrics or Prometheus proves a component is hung, this connector restarts it.

Before you start

  • kubectl access as a cluster admin, once, to create a ServiceAccount and a Role.
  • The namespaces 3AM should watch and act in.
  • Network access from 3AM to the API server (inside the cluster that's https://kubernetes.default.svc).

1. Create a ServiceAccount and a Role

3AM's access is one ServiceAccount, plus a Role in each namespace it watches. Both manifests are in the kubernetes/ folder of each 3AM release. Installed from the Helm repository? curl -fsSL https://get.3am.si | sh downloads a release without installing it.

kubectl apply -f kubernetes/3am-rbac.yaml           # namespace 3am, the ServiceAccount, a token, StorageClass read

for ns in bank-prod payments-prod; do
  sed "s/WATCHED_NAMESPACE/$ns/" kubernetes/3am-role.yaml | kubectl apply -f -
done

2. Collect the token, CA and API address

kubectl -n 3am get secret 3am-connector-token -o jsonpath='{.data.token}' | base64 -d > 3am-k8s-token
kubectl config view --raw --minify -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > k8s-ca.pem
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'; echo

On EKS, AKS and GKE, use the address and CA from your kubeconfig as they are. 3AM authenticates with the ServiceAccount token, so a cloud auth plugin in your kubeconfig doesn't matter.

3. Add the connector

In the console: Connections → Add a connection → Kubernetes. Or in connectors.json:

/etc/3am/connectors.json
{ "name": "k8s", "kind": "kubernetes",
  "settings": { "api_url": "https://10.0.0.1:6443",
                "token": { "file": "/etc/3am/secrets/3am-k8s-token" },
                "ca_file": "/etc/3am/secrets/k8s-ca.pem",
                "namespaces": ["bank-prod", "payments-prod"] } }
kind: kubernetesalerts inactions
SettingWhat to enterRequiredDefault
api_urlAPI server URLyes—
tokensecretService-account tokenyes—
ca_fileAPI server CA certificate (PEM file; empty: system CAs)no—
verify_tlsVerify TLSyestrue
namespacesNamespaces 3AM watches and may act inyes—

4. Verify

Test connection asks the API server, namespace by namespace, whether the token can do each thing 3AM needs:

Test connection
Kubernetes v1.34.0; permissions present in bank-prod, payments-prod

A missing permission is named, with the namespace and what it's for:

Kubernetes v1.34.0, but the token cannot: list pods in payments-prod (see pod state)

What it detects

SignalWhen
KubePodCrashLoopingA container is waiting in CrashLoopBackOff
KubeContainerOOMKilledA container's last exit was OOMKilled, in the last 30 minutes
KubeImagePullBackOffImagePullBackOff or ErrImagePull
KubeContainerConfigErrorCreateContainerConfigError
KubePodUnschedulablePending and unschedulable for more than 2 minutes
KubeDeploymentRolloutStuckA rollout passed its progress deadline

The names match kube-prometheus, so if your Prometheus already alerts on these, the same causes apply. Three crash-looping replicas of one workload are one incident.

What it proves and fixes

CauseHow 3AM knowsFix
Bad releaseA rollout in the last 6 hours, the previous revision's pods differ, the new pods fail, and the crashed run's logs show no dependency errorsRoll back to the last revision whose pods actually differ. If Argo CD manages the workload, the rollback goes through Argo CD, because self-heal would undo a kubectl rollback
Dependency downThe crashed run's logs show it can't reach something (connection refused, timeout, unknown host)None. Restarting won't help; 3AM names the dependency
Memory limit too lowLast exit OOMKilled in the last 30 minutesAdvice with the current limit. Rolls back instead if a release caused it
Missing configCreateContainerConfigError naming the ConfigMap or SecretAdvice: create it
Image unavailableThe image pull failsAdvice: tag, registry or pull secret. Rolls back if the image came with a recent release
UnschedulableThe scheduler's reasonAdvice: capacity, node selector, affinity or taints
Volume filling upKubePersistentVolumeFillingUp, kubelet stats under 15% freeGrow the PVC by half, if its StorageClass allows it. Two approvers

"Bad release" and "dependency down" exclude each other: restarting pods whose database is down is the classic wrong move. How fixes are approved and verified is the same for every connector: see How 3AM decides.

Actions

ActionParametersNotes
rollbacknamespace, nameSkips restart-only revisions, unlike kubectl rollout undo
restartnamespace, kind, namekubectl rollout restart for a Deployment, StatefulSet or DaemonSet
scalenamespace, kind, name, replicas0–100. Never a DaemonSet
restart_podnamespace, podController-managed pods only. Waits until the replacement is Ready
expand_volumenamespace, pvc, sizeThe StorageClass must allow it; larger, and at most 4× the current size. Fails if the volume didn't actually grow
locateaddressRead-only. The pod, workload and volume behind a URL, host:port, pod IP, or Service or pod DNS name
volume_statusnamespace, pod or pvcRead-only. Capacity, StorageClass, whether it can grow
logsnamespace, pod, previousRead-only. previous=true reads the crashed run

Every change runs first with dryRun=All: the API server and your admission webhooks validate it and nothing changes. 3AM refuses namespaces outside its list, and the Role would refuse them anyway.

Troubleshooting

the token is invalid or expired

Re-read the token from the 3am-connector-token Secret (step 2). Tokens from kubectl create token expire.

the API server's certificate is not trusted: set ca_file

Set CA certificate to k8s-ca.pem from step 2.

the token cannot: list pods in <namespace>

The Role isn't applied in that namespace. Run the loop from step 1 for it.

An action fails with the 3AM Role does not allow this

That namespace's Role is missing a rule, or you removed it on purpose. Re-apply 3am-role.yaml if you didn't.

A failing pod opens no incident

Its namespace isn't in Namespaces.

Certification

Live, on Kubernetes 1.34 with exactly this RBAC and only 3AM's token (2026-10-04):

  • Connector, 32 checks. Signals, workload resolution and health reporting.
  • End to end, 30 checks. Two broken releases (a config panic, a missing image) were rolled back and verified healthy. A release whose database was down was left alone. An OOM and a missing ConfigMap got advice, and nothing ran.
  • Fixes for other connectors, 54 checks. With 3AM inside the cluster, hung components were each located, restarted and verified: vmagent, one vmstorage pod, Alertmanager, Prometheus and two exporters. A volume-growth request on a driver that can't grow volumes was reported as failed, not as done.

On this page