Skip to content

Thomas6013/kubeadjust

KubeAdjust

See what your Kubernetes workloads actually use vs what they request — and get suggestions to right-size them.

License Go Next.js Kubernetes


KubeAdjust dashboard

Alpha software — This is a personal project, maintained by a single developer with the help of an AI coding agent. Expect rough edges. Contributions welcome, response times may vary.

Read-only — KubeAdjust never modifies your cluster. It only reads resource data. If you apply the suggestions manually, be aware that changing requests/limits on a running Pod triggers a restart.


Why?

Most clusters waste resources because requests and limits are set once and never revisited.

Before KubeAdjust: your Pod requests 2Gi memory, but only uses 180Mi. You don't know — it just runs.

After KubeAdjust: you see the over-provisioning instantly, with a concrete suggestion: "Reduce memory request to 256Mi (current P95: 195Mi)".

KubeAdjust shows for every Deployment, StatefulSet and CronJob:

  • CPU and memory requests / limits / actual usage side-by-side
  • Color-coded status (critical / warning / over-provisioned / healthy)
  • Actionable right-sizing suggestions with confidence levels
  • Optional sparklines from Prometheus (1h to 7d trends)
  • Cluster-wide node overview with capacity, usage, limit overcommit indicator, node conditions (DiskPressure / MemoryPressure / PIDPressure), age, kubelet version, kernel, and OS image
  • Namespace limit/request ratios — CPU ×N.N and MEM ×N.N at a glance above the workload list
  • Cluster overview stats — live total and per-namespace average CPU/RAM consumed across all visible namespaces (falls back to requests when metrics-server is unavailable)
  • Multi-cluster support — configure multiple clusters via CLUSTERS env var; tokens are stored per cluster so switching between visited clusters requires no re-authentication
  • OIDC / SSO authentication — optional SSO login via Keycloak, Dex, Google, or any OIDC provider. Works on managed clusters (EKS, GKE, AKS) with no K8s API server configuration required
  • Managed cluster mode — configure a Service Account token (SA_TOKEN) to skip the login form entirely. Users land directly on the dashboard with no token entry required
  • Shareable URLs — dashboard state (cluster, view, namespace) is reflected in query parameters. Share a link like /dashboard?cluster=prod&view=namespaces&ns=payments to point someone directly to the right context

Requirements

Requirement Minimum version
Kubernetes 1.21 (batch/v1 CronJobs)
metrics-server any (optional, enables live usage)
Prometheus any (optional, enables sparklines + P95)
Go 1.26+ (build only)
Node.js 25+ (build only)

Install

Helm (production)

The Helm chart lives in a dedicated repository — kubeadjust-helm.

helm repo add kubeadjust https://thomas6013.github.io/kubeadjust-helm
helm repo update

helm install kubeadjust kubeadjust/kubeadjust \
  --namespace kubeadjust --create-namespace \
  --set ingress.enabled=true \
  --set ingress.host=kubeadjust.your-domain.com

Get a login token:

kubectl create token kubeadjust -n kubeadjust

Docker Compose (local)

git clone https://github.com/thomas6013/kubeadjust.git && cd kubeadjust

export KUBE_API_SERVER=https://<your-cluster-api>
export KUBE_INSECURE_TLS=true   # if self-signed cert

docker compose up --build

Open http://localhost:3000, paste your token, done.

Local dev

# Backend (Go 1.26+)
cd backend && KUBE_API_SERVER=https://<your-cluster> go run .

# Frontend (Node 25+)
cd frontend && npm install && npm run dev

Configuration

Variable Default Description
KUBE_API_SERVER https://kubernetes.default.svc Kubernetes API URL
KUBE_INSECURE_TLS false Skip TLS verification
PROMETHEUS_URL (empty) Prometheus URL for sparklines (optional)
ALLOWED_ORIGINS * CORS origins (comma-separated)
PORT 8080 Backend listen port
OIDC_ENABLED false Enable OIDC/SSO login
OIDC_ISSUER_URL (empty) OIDC provider issuer URL
OIDC_CLIENT_ID (empty) OIDC client ID
OIDC_CLIENT_SECRET (empty) OIDC client secret
OIDC_REDIRECT_URL (empty) https://<host>/auth/callback
SESSION_SECRET (empty) ≥32-char random string for signing session tokens
SA_TOKEN_<CLUSTER> (empty) SA token for a named cluster, e.g. SA_TOKEN_PROD (OIDC multi-cluster)
SA_TOKENS (empty) Multi-cluster SA tokens: prod=token1,staging=token2
SA_TOKEN (empty) SA token override for the default cluster (normally not needed — uses in-cluster token)
OIDC_GROUPS (empty) Comma-separated OIDC group names for access control

Prometheus: set PROMETHEUS_URL to enable sparklines and P95-based suggestions. Works with or without http:// prefix.

metrics-server: required for live usage data. If not installed, enable the sub-chart: --set metrics-server.enabled=true.

Multi-cluster: configure clusters as a Helm map (backend.clusters.prod, backend.clusters.staging, …). Each cluster stores its token independently in sessionStorage — switching between clusters requires no re-authentication. Full Helm values reference is in kubeadjust-helm.

OIDC / SSO: see docs/oidc.md for a full setup guide. Works with any OIDC provider and on managed clusters (EKS, GKE, AKS) — no K8s API server configuration required.


Architecture

Browser → Next.js (port 3000) → /api/* proxy → Go backend (port 8080)
                                                  ├── Kubernetes API
                                                  ├── metrics-server
                                                  └── Prometheus (optional)

Token mode (default): stateless — no database, no cache. Your K8s token is forwarded on every request, never stored server-side.

OIDC mode: the backend validates the OIDC ID token and issues a signed session JWT. A pre-configured Service Account token is used for all K8s API calls.


Security

  • Read-only RBAC — the Helm ClusterRole only has get, list, watch permissions
  • Token in sessionStorage — cleared on tab close, never logged or persisted
  • PromQL injection prevention — strict whitelist validation on all label values
  • 10MB response capio.LimitReader on all upstream responses
  • Nonce-based CSP — per-request nonce via proxy.ts, no unsafe-inline or unsafe-eval
  • K8s API retry — exponential backoff on transient 5xx/network errors (max 3 attempts)
  • URL-encoded path parameters — all K8s API path segments escaped to prevent path traversal

Docs

Contributing

See CONTRIBUTING.md.

License

Apache 2.0 — see LICENSE.

About

Lightweight Kubernetes dashboard to visualise and right-size resource requests & limits per workload, pod and container.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors