Skip to content

Configuration

This page lists the Helm values, how to manage the secrets, the ready-made profiles, and the environment variables for running without Helm. To install, see installation.md.

The defaults are in helm/values.yaml. To print them for a released version:

helm show values oci://ghcr.io/octopusdeploy/charts/argocd-cost-intelligence --version 0.1.0

Helm values

Set values with --set key=value or with a values file (-f). If the file holds a password, keep it out of version control.

Common settings

Key Default Description
postgres.auth.password "" Database password. Needed on first install unless postgres.auth.existingSecret is set. Later upgrades read it back from the Secret.
openCost.baseURL http://opencost.opencost:9003 OpenCost API URL.
costIntelligence.clusterScopeApp "" The Argo CD Application (<namespace>:<name>) whose viewers see the Namespaces and Chargeback pages and the control-plane fee. Empty uses the Application that installed the chart, or else the access Application below. off turns them off. See installation.md.
costIntelligence.accessApplication.create true When Helm itself installs the chart and clusterScopeApp is empty, create an Argo CD Application to gate cluster-wide costs, in an AppProject that permits no resources. It deploys nothing. It is not created when Argo CD renders the chart, since Argo CD's own Application is the gate then.
costIntelligence.accessApplication.name / .project cost-intelligence-access Names of that Application and its AppProject, in argoCd.namespace.
argoCd.namespace argocd The namespace Argo CD runs in. The hook patches resources there.
namespace.name argocd-cost-intel The namespace for every chart resource. helm --namespace must match it.
namespace.create true Create that namespace. Set it to false when Helm (--create-namespace) or you create it first. With true, an existing namespace makes the install fail.
networkPolicy.enabled true Deploy the NetworkPolicies. Set it to false on CNIs that don't enforce them (Flannel, k3d).

Credentials

Key Default Description
postgres.auth.existingSecret "" A Secret in namespace.name with username and password keys. When set, the chart creates no PostgreSQL Secret and ignores postgres.auth.password and username.
postgres.auth.username cost_user Database user.
postgres.auth.database cost_intelligence Database name.
webhook.existingSecret "" A Secret holding the sync webhook token under the key token, at least 16 characters. When empty, the chart generates argocd-cost-intelligence-webhook and keeps its token across upgrades. Set it when Argo CD or helm template renders the chart.

PostgreSQL

Key Default Description
postgres.enabled true Deploy the bundled StatefulSet. For false, see External PostgreSQL.
postgres.image.repository / .tag postgres / 15-alpine
postgres.sslMode disable Connection mode (DB_SSL_MODE): disable, require or verify-full. Plaintext is fine only for the bundled database inside the cluster.
postgres.service.port 5432
postgres.persistence.size 20Gi Size of the PVC postgres-pvc. A PVC can only grow, and only if its StorageClass allows expansion. A smaller value makes the upgrade fail.
postgres.persistence.storageClassName "" Empty means the cluster default.
postgres.resources 100m / 256Mi requested, 500m / 1Gi limit

The chart can't keep the PVC on uninstall, and it has no switch to run without one.

Backend

Key Default Description
costIntelligence.replicaCount 2 Used only when autoscaling is off.
costIntelligence.autoscaling.* enabled, 2 to 5 replicas, CPU 70%, memory 80% The HorizontalPodAutoscaler. Needs metrics-server.
costIntelligence.port 8080 Listen port (SERVER_PORT), also the Service and NetworkPolicy port.
costIntelligence.dailyHistoryDays 400 How many days of each application's daily cost to keep in PostgreSQL (DAILY_HISTORY_DAYS), about one row per application per day. OpenCost only answers for the days its Prometheus keeps, often 15, so this history is what lets the Trends tab show months. 0 turns recording off.
costIntelligence.backfillConcurrency 4 How many namespaces to measure at once when the service starts and finds Applications without a cost record (BACKFILL_CONCURRENCY). Replicas take turns, so OpenCost never sees more than this many queries from the backfill. 0 turns it off, and applications then show costs only after their next sync.
costIntelligence.pruneRemoteCost false Delete the cost records and daily history stored for Applications that deploy to another cluster (PRUNE_REMOTE_COST). It can't be undone, and an Application that targets this cluster by its API server URL counts as remote; see Known limitations.
costIntelligence.vpa.enabled true Read VPA recommendations for rightsizing (VPA_ENABLED) and give the ClusterRole read access to verticalpodautoscalers. See installation.md.
costIntelligence.database.maxOpenConns / maxIdleConns 25 / 5 Connection pool size per replica. Keep replicas times maxOpenConns below PostgreSQL's max_connections.
costIntelligence.server.readTimeout / writeTimeout / idleTimeout 10s / 10s / 120s HTTP server timeouts. Raise writeTimeout if large Trends queries get cut off.
costIntelligence.image.tag chart appVersion Pin a release.
costIntelligence.resources 100m / 128Mi requested, 500m / 512Mi limit
openCost.timeout 10s How long to wait for OpenCost.

Argo CD integration and UI

Key Default Description
features.autoPatchArgoCd true Run the post-install/post-upgrade hook that registers the extension, the webhook and the token with Argo CD. With false you do all of that yourself.
ui.enabled and features.deployUI true Deploy the UI plugin. Both must be true.
ui.autoRegister true Have the hook add the init container that loads the bundle into argocd-server. Needs features.autoPatchArgoCd.
ui.port / ui.replicas 3000 / 1
ui.image.tag chart appVersion
postInstallHook.image alpine/k8s:1.32.3 An image with kubectl, jq and yq (mikefarah/yq v4), for the hook Job. Pick a tag close to your cluster's Kubernetes minor version.
postInstallHook.extensionInitImage busybox:1.37.0 The image of the argocd-server init container that downloads the UI bundle. It needs sh and wget.
argoCd.rbac.grantAdmin true Have the hook write policy.cost-intel.csv in argocd-rbac-cm, so role:admin can open the extension. With false the hook removes that key, unless you changed it. It never touches policy.csv.

Metrics

Key Default Description
metrics.enabled true Serve /metrics from the API replicas (METRICS_PORT) and deploy the exporter. false turns both off.
metrics.port 9102 The metrics port. It's separate from the API port, which Prometheus must never reach, and must differ from costIntelligence.port.
metrics.podAnnotations true Add prometheus.io/* scrape annotations to the API and exporter pods.
metrics.allowedFrom the monitoring namespace NetworkPolicy from entries that may reach the metrics port, and only that port. An empty list admits nobody. Anyone who can query that Prometheus sees every Application's cost.
metrics.exporter.enabled true Deploy the exporter: one replica, Recreate, the backend image with MODE=exporter.
metrics.exporter.interval 5m How often every Application is measured (EXPORTER_INTERVAL), at least 1m. It costs one OpenCost query per namespace.
metrics.exporter.resources 20m / 64Mi requested, 200m / 256Mi limit
metrics.serviceMonitor.enabled / .interval / .labels false / 1m / {} ServiceMonitors for the Prometheus Operator, one for the API and one for the exporter. labels are the labels your Prometheus selects by, such as release: kube-prometheus-stack.
metrics.prometheusRule.enabled / .labels false / {} A PrometheusRule built from helm/files/prometheus-rules.yaml.

The metrics themselves, with queries and alerts, are in metrics.md.

Networking and scheduling

Key Default Description
networkPolicy.probeCIDRs [] Node address ranges to admit, for CNIs that block kubelet probes. See NetworkPolicy.
ingress.enabled false Create an Ingress for the backend. This bypasses Argo CD's authorization and the NetworkPolicy blocks it, so leave it off.
nodeSelector, affinity, tolerations empty Applied to the backend, exporter and PostgreSQL pods.
security.podSecurityContext / security.containerSecurityContext non-root uid 1000, read-only root filesystem, all capabilities dropped For the backend, exporter and UI pods. PostgreSQL has its own under postgres..
healthChecks.livenessProbe / .readinessProbe enabled, 10s / 5s period For the backend and PostgreSQL probes.
commonLabels, commonAnnotations a part-of label, no annotations Added to every resource (the annotations go on the pods).
rbac.*, serviceAccount.* created, named argocd-cost-intelligence

Secrets

PostgreSQL credentials

The simplest way is to let the chart manage them. Pass the password on first install (--set postgres.auth.password="$(openssl rand -base64 32)"). The chart writes it to the Secret postgres-credentials and reuses that Secret on every upgrade, so later helm upgrade runs don't need the password.

For production and GitOps, create the Secret yourself, outside Helm:

kubectl create namespace argocd-cost-intel

kubectl create secret generic postgres-credentials \
  --namespace argocd-cost-intel \
  --from-literal=username=cost_user \
  --from-literal=password="$(openssl rand -base64 32)"

helm install argocd-cost-intelligence \
  oci://ghcr.io/octopusdeploy/charts/argocd-cost-intelligence \
  --version 0.1.0 --namespace argocd-cost-intel \
  --set namespace.create=false \
  --set postgres.auth.existingSecret=postgres-credentials \
  --wait --timeout 10m

The bundled PostgreSQL only applies the password when it first initialises its volume. If you rotate the Secret later, the database user's password doesn't change. Change both (ALTER USER inside postgres-0).

Webhook token

Argo CD Notifications has to send a bearer token to POST /api/cost-analysis/on-sync, or the backend answers 401. The chart generates the token and keeps it in the Secret argocd-cost-intelligence-webhook (key token). The hook copies it into argocd-notifications-secret as cost-intel-webhook-token. The backend reads it only at startup. If Argo CD or helm template renders the chart, use webhook.existingSecret; see installation.md, which also covers rotating the token.

Profiles

The profile files ship in the chart but aren't part of the OCI install path. To get them:

helm pull oci://ghcr.io/octopusdeploy/charts/argocd-cost-intelligence --version 0.1.0 --untar
# then: -f argocd-cost-intelligence/values-minimal.yaml
Profile Backend PostgreSQL Notes
Default (values.yaml) 2 to 5 replicas (HPA) 20 GiB
values-minimal.yaml 1 replica, HPA off, smaller requests 10 GiB For evaluation and small clusters.
values-production.yaml 3 to 10 replicas (HPA), larger requests, pod anti-affinity 100 GiB on StorageClass fast-ssd A starting point. It also sets a nodeSelector (workload: platform-services) and a placeholder Ingress block, so read it and change the StorageClass before you use it.

Every profile still needs the same postgres.auth.* and namespace.create=false settings as a default install.

External PostgreSQL

Set postgres.enabled=false to skip the bundled StatefulSet, PVC, Service and NetworkPolicy. Then provide postgres.auth.existingSecret (with username and password), postgres.auth.database, and postgres.sslMode=require or verify-full.

The chart has no value for the database host. The backend and exporter always connect to postgres.<namespace.name>.svc.cluster.local on postgres.service.port, so make that name resolve to your database. An ExternalName Service called postgres in the release namespace does it. With verify-full, the server certificate has to match that name.

Running without Helm

The chart sets these variables from its values, so you only need them when you run the image without the chart. .env.example is a template with the rest, such as the database connection, and their defaults.

Variable Default Description
MODE api api serves the REST API. exporter exports every Argo CD Application's cost to Prometheus (see metrics.md).
METRICS_PORT 9102 The port that serves Prometheus /metrics, apart from the API port. 0 turns metrics off (API mode only).
DB_HOST localhost PostgreSQL host. The chart has no value for it.
DB_PASSWORD required Database password.
DB_SSL_MODE disable PostgreSQL SSL mode: disable, require or verify-full.
OPENCOST_BASE_URL http://opencost:9003 OpenCost API endpoint.
SERVER_READ_TIMEOUT / SERVER_WRITE_TIMEOUT / SERVER_IDLE_TIMEOUT 10s / 10s / 120s HTTP server timeouts.
WEBHOOK_SECRET required The bearer token Argo CD Notifications sends to /on-sync, at least 16 characters.
CLUSTER_SCOPE_APP empty The Argo CD Application (<namespace>:<name>) whose viewers may see cluster-wide cost data. Empty finds one and off turns it off; see Choose your settings.
CLUSTER_ACCESS_APP empty The fallback Application (<namespace>:<name>) when none installed the service; see Authorization.
POD_NAMESPACE / DEPLOYMENT_NAME empty The service's own Deployment, whose tracking annotation names the Application that installed it.
ARGOCD_NAMESPACE argocd Where Argo CD runs. A tracking annotation that names an Application without a namespace means one here.
BACKFILL_CONCURRENCY 4 How many namespaces to measure at once when the service starts; 0 turns it off. See Measuring at install.
PRUNE_REMOTE_COST false Delete stored cost for Applications that deploy to another cluster, which can't be undone; see Known limitations.
VPA_ENABLED true Read Vertical Pod Autoscaler recommendations for rightsizing; see Optional: rightsizing.