Skip to main content

Overview

CPLN Advisor watches the workloads in the org it runs in, tracks CPU, memory, replica counts, error rates and billed cost, and turns what it finds into concrete tuning suggestions — memory limits, autoscaling thresholds, replica counts — generated by an LLM. Suggestions appear in a dashboard, and Autopilot can apply the qualifying ones for you, each with a one-click revert. It reports on the org it runs in: Control Plane injects CPLN_ORG into every container, so the advisor knows where it lives without being told. No credential passes through this chart. It creates no credential secret and takes none as a value — it reads two dictionary secrets you create first, and the advisor’s own Control Plane token is entered in the dashboard after install.

What Gets Created

  • Dashboard Workload (RELEASE_NAME-web) — The Next.js UI on port 3000, a serverless workload scaling 1–3. The only public workload, and the only one holding a session key.
  • API Workload (RELEASE_NAME-api) — FastAPI backend on port 8000, standard, pinned to one replica. Verifies the login, runs the database migration at startup, and is reachable only by the dashboard.
  • Worker Workload (RELEASE_NAME-worker) — Runs the scans, applies Autopilot changes, sends the Slack digest. One replica, no inbound traffic.
  • Scheduler Workload (RELEASE_NAME-scheduler) — Fires the crons that create the scans. One replica, no inbound traffic.
  • Redis Workload (RELEASE_NAME-redis) — Task broker and cache on port 6379. Not persistent and not authenticated; its firewall admits exactly the API, worker and scheduler.
  • Bundled Postgres (RELEASE_NAME-postgres plus -pg-vs, -pg-identity, -pg-policy) — The database, from the catalog’s Postgres template pinned at 3.4.1: a stateful workload on its own volume set, with a pg_isready probe and scheduled backups behind a switch. It creates no secret — it reads your database credentials secret.
  • Identity & Policies (RELEASE_NAME-identity, -policy) — reveal on the secret (the advisor credentials you created).
This template does not create a GVC. It deploys into a GVC you already have — every resource lands in the GVC you install into, so cpln workload exec, cpln logs and uninstalling all work against that GVC, and uninstalling can never delete it. The location you configure must already be a location of that GVC, and a GVC location this release did not ask for starts nothing.

The Single Location Requirement

Install the advisor into a GVC with exactly one location. One location is not a simplification: scale bounds are per-location, so a second location would mean a second scheduler firing every cron twice, a second Redis splitting the task queue, and a second API running the same startup migration.

Prerequisites

A GVC with exactly one location, and two dictionary secrets that exist before you install. The advisor’s own Control Plane token is set in the dashboard after install, not here.

The Advisor Credentials Secret

The keys are the application’s own environment variable names.
Set auth.secretName in the values file to the name you used.

The Database Credentials Secret

From version 3.4.0 the bundled Postgres template reads its credentials from a secret instead of taking them inline, which is what lets this chart bundle a database and still keep every credential out of values. Exactly three keys:
Set postgres.config.credentialsSecretName in the values file to the name you used.
These three values must match DATABASE_URL above, and nothing cross-checks them. Helm cannot read secret values at render time, so a mismatch is not a render error — it is an authentication failure at runtime, after everything appears to have installed cleanly. Set DB_PASS once and use it in both commands, as shown.
Secret names are org-wide, so give each release its own pair of secret names.

A Service Account for the Advisor

The advisor’s Control Plane token is deliberately not a value and not in either secret. You set it once in the dashboard after signing in, under Configuration → Control Plane, where it is stored encrypted in the database. Create a service account whose token can, at minimum:
Without org: readUsage the scan still succeeds — it logs billing: charges query failed … falling back to the allocation estimate and reports estimated rather than billed cost.

Installation

Create both prerequisite secrets first, then install by whichever method you prefer:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

The default values.yaml for this template:

Location

global.cpln.gvc is injected by the platform at install time and is never declared in values. There is no gvc key — the chart refuses to render if it finds one.

Images

The API, worker and scheduler run the same backend image with different commands — a scan is executed by the worker and served by the API, so they must never drift apart.

Login and Sessions

The login name and password are keys in your credentials secret, not values. The login is verified by the API, never by the dashboard, so one workload holds the credentials. There is one account for everyone: change history and activity attribute everything to a single user, and there is no per-person audit trail. session.hours is an idle window that slides forward while you work, under a hard ceiling the app enforces. It is in force, not merely rendered: a session cookie issued at the default setting carried an Expires exactly 12 hours after login. session.rememberDays is the equivalent window with “Keep me signed in” selected.

Access

The dashboard is public and there is no values knob to close it. That is not a toggle because it is not really a choice — the dashboard is the only way into this app, and nothing inside the GVC calls it. What stands between the internet and your fleet is the login:
  • the session cookie is HMAC-signed with ADVISOR_SESSION_SECRET, so it cannot be forged
  • both credentials come from a secret you create, so there is no shipped default password to look up
Everything else is closed to the internet, and internal traffic is admitted only from real callers: To narrow the dashboard to an office or VPN range, edit inboundAllowCIDR on the RELEASE_NAME-web workload after installing. Access changes take roughly 30 seconds to a few minutes to propagate.

Public URL

appUrl is empty by default and should stay that way unless you use a custom domain. The app derives its own public URL from Control Plane’s built-in environment variables as https://{web workload}-{gvc alias}.cpln.app, and the chart passes it this release’s actual dashboard workload name so the derivation resolves to the right workload. Both the Slack “View in Advisor” links and the CORS allowlist come from it. Never set it to *: combined with credentials, a wildcard makes the server echo back whichever origin asked.

Resources

A block that exposes both a floor and a limit names them minCpu/maxCpu and minMemory/maxMemory; a block that exposes only the limit uses the API’s own field names, bare cpu/memory. minCpu and minMemory are the floor Capacity AI scales up from, and only the three tiers that enable it set one. The worker and Redis run with Capacity AI off — a long scan should not be resized underneath itself, and a broker should not be resized under load — so a floor there would be inert. The chart checks two limits at render time, because Control Plane enforces both but publishes neither in a schema, so each would otherwise surface as a 400 partway through an install:
  • maxCpu/minCpu must be strictly under 4:1, and memory is bounded the same way at 4:1 inclusive.
  • Unit typos. cpu and memory are bare strings with no numeric bound, so 512Gi written for 512Mi is accepted and the workload then never schedules.
Raising maxCpu or maxMemory on web, api, scheduler or postgres means raising its matching minimum too.

Database

Values under postgres are passed straight through to the bundled Postgres chart, pinned at 3.4.1. Memory is deliberately above that chart’s defaults, because a fleet scan writes in bursts. Three workloads write this database concurrently — the API serves the dashboard, the worker records scan results and Autopilot changes, and the scheduler writes cron state.
postgres.internalAccess: same-gvc is wider than it was in 1.0.0. That version created a dedicated GVC, so same-gvc meant “the advisor and nothing else”. The GVC is now yours and may hold unrelated workloads, any of which can open port 5432 — measured, the dashboard workload reached the database even though it is not a database client.If the GVC is shared, narrow it at install time with the real names. A subchart’s values cannot be templated, so the workload links have to be written out:
Add RELEASE_NAME-postgres-backup to that list if you turn backups on.

Backups and Restore

Backups are off by default and you should turn them on. They are off only because they need a bucket and a cloud account you create first — and a volume is not a backup: losing it loses every scan, score and Autopilot record.
The bucket, cloud account and IAM policy steps are the Postgres template’s, passed through unchanged — see its backup prerequisites. provider: minio needs its own prerequisite dictionary secret holding accessKey and secretKey.
backup.image is coupled to image. Tag 18.1.0 backs up Postgres 18 and 17.1.0 backs up Postgres 17. Change one and change the other, or pg_dump meets a server it cannot read.
Each run writes one gzipped pg_dumpall plain-SQL file, postgres-<UTC-timestamp>.sql.gz, under <bucket>/<prefix>/. pg_dumpall produces a whole-cluster script including CREATE ROLE and CREATE DATABASE, so it restores into an empty server rather than merging into a running one.
1

Stop the writers

Scale the API, worker and scheduler to zero, or they will be writing while you restore.
2

Download the dump

Use your own cloud tooling — the Postgres container has neither aws nor gsutil.
3

Open a tunnel to the database

4

Load it

Use psql version 18 or newer, and pass -v ON_ERROR_STOP=1. The chart pins postgres:18, and a PostgreSQL 18 pg_dumpall wraps its output in the \restrict / \unrestrict meta-commands, which older clients do not have. Running the restore with an older client printed 11 error lines — invalid command \restrict, ERROR: role "advisor" already exists — and then exited 0, which is precisely the silently-wrong-restore case. -v ON_ERROR_STOP=1 turns that into a real failure. If you have no matching client locally, run the restore from inside the Postgres container, which already has one.

Connecting

Both internal workloads are also reachable from your machine without opening anything up:
Use the fully-qualified .cpln.local name for internal access. The short workload name does not resolve reliably from every workload type.

After the First Deploy

1

Sign in

Open the dashboard and use the ADVISOR_USERNAME and ADVISOR_PASSWORD from your credentials secret.
2

Connect Control Plane

Go to Configuration → Control Plane, paste the service account token, and press Test connection. A working connection returns the org and the number of GVCs the token can see. The token round-trips encrypted through the database and reads back masked afterwards.
3

Add an AI provider, and Slack if you want digests

An Anthropic or OpenAI key, on the same page. These are stored encrypted using ADVISOR_SECRET_KEY — which is why losing that key loses them.
4

Enroll workloads and scan

Enable Scan on the workloads you want watched, then Scan now.

Diagnosing a Stuck Install

A missing prerequisite secret produces no log output at all. The container never starts, so cpln logs returns zero lines and the deployment simply looks slow.
Read status.versions[].message — it names the missing secret. Creating the missing secret repairs the deployment on its own, but slowly. A forced redeployment shortcuts it:

Important Notes

  • Install into a single-location GVC.
  • Create both prerequisite secrets before installing. A missing one wedges the deployment silently; Diagnosing a Stuck Install gives the one command that names it.
  • DATABASE_URL and the database credentials secret must agree, and nothing cross-checks them. A mismatch installs cleanly and then fails to authenticate at runtime.
  • Losing ADVISOR_SECRET_KEY loses every credential entered in the UI. They are unrecoverable and must be re-entered. Keep it somewhere durable before you deploy.
  • The dashboard is public and there is no values knob to close it. The login is the boundary. Narrow inboundAllowCIDR on the RELEASE_NAME-web workload after installing if you want it tighter.
  • The bundled database admits any workload in your GVC. If the GVC is shared, narrow postgres.internalAccess — see Database.
  • Backups are off by default and you should turn them on, and restore with a psql of version 18 or newer — see Backups and Restore.
  • A Postgres password is first-boot only. It is read when the data directory initializes; rotating it in the secret afterwards does not change the running server. You must also change it in Postgres itself and update DATABASE_URL to match.
  • Rotating any secret requires a forced redeployment. cpln://secret/… references resolve when a replica starts and are never re-resolved while it lives, so a rotated secret keeps working with the old value indefinitely while everything reports healthy.
  • Redis is not persistent and not authenticated. Everything in it is derived or transient, so a restart at worst skips one scan and repeats one digest. Its firewall admits exactly the three workloads that use it — do not widen it.
  • Autopilot redeploys your workloads. Each applied suggestion patches a live workload and restarts it. It is per-workload and off until you enable it.
  • The advisor’s token is as powerful as you make it. Grant workload: edit only if you want Autopilot and one-click apply; without it the advisor runs read-only.
  • uninstall deletes the database volume set and the scan history with it. It does not delete the GVC — this chart never owns one — and it does not delete your two prerequisite secrets.

External References

CPLN Advisor Template

View the source files, default values, and chart definition

Create a Service Account

Issue the token the advisor uses to read and tune your org

Capacity AI

How resource floors and automatic sizing work on Control Plane

Workload Firewall

Internal and external access controls used by every workload here