🤖 Generated with Claude Code, at the maintainer's request.
Goal
Switch OpenCost from the current flat customPricing to the native hcloud provider for exact, per-instance, per-location Hetzner pricing pulled from the Hetzner Cloud API.
Why
Today opencost/helm-release.yaml uses a single CX33-derived customPricing (CPU 0.9441, RAM 0.4720 USD/month, 50/50 split). That's exact for the six CX33 control-plane/worker nodes, but a single per-CPU/per-GB rate can't capture Hetzner's economy-of-scale across instance types:
| type |
€/vCPU/mo |
| CX23 |
€2.00 |
| CX33 |
€1.62 |
| CX43 |
€1.50 |
| CX53 |
€1.41 |
So autoscale nodes that aren't CX33 are priced a few % off. The native provider reads each node's hcloud://<id> providerID and looks up the real per-instance/per-location rate, eliminating the approximation.
Blocker (why this is a tracking issue, not a PR)
opencost#3710 (the hcloud provider) is still open — based on develop, not merged, and not present in the deployed OpenCost 1.120.3 (chart 2.5.x). Swapping provider/relying on hcloud:// auto-detection now would leave OpenCost with no matching provider and break the cost model. Adopt only once #3710 merges and ships in an OpenCost release.
Already in place
- Hetzner API token is seeded into OpenBao (
vault-seed/seed-hcloud.yaml) and materialized as the hcloud Secret for CCM/CSI — so exposing it to the opencost namespace is a small ESO step.
Steps when #3710 ships in a release
- Bump the
opencost HelmRelease chart to the version whose appVersion includes the hcloud provider.
- Add an ESO
ExternalSecret materializing a read-only HCLOUD_TOKEN into the opencost namespace from the OpenBao path (don't reuse the CCM/CSI Secret cross-namespace).
- Set
opencost.exporter.env HCLOUD_TOKEN (fallback CLOUD_PROVIDER_API_KEY); the provider auto-detects from hcloud:// providerIDs.
- Remove the
customPricing block.
- Re-derive the Coroot blended per-CPU/per-GB rate (the #1783
coroot-custom-cloud-pricing CronJob) from the new authoritative per-instance numbers so the two cost views stay consistent — Coroot's model is per-CPU/per-GB only and can't consume the provider directly.
- Validate (
kubectl kustomize prod+local, ksail --config ksail.prod.yaml workload validate) and open a draft PR.
Refs
Goal
Switch OpenCost from the current flat
customPricingto the nativehcloudprovider for exact, per-instance, per-location Hetzner pricing pulled from the Hetzner Cloud API.Why
Today
opencost/helm-release.yamluses a single CX33-derivedcustomPricing(CPU 0.9441,RAM 0.4720USD/month, 50/50 split). That's exact for the six CX33 control-plane/worker nodes, but a single per-CPU/per-GB rate can't capture Hetzner's economy-of-scale across instance types:So autoscale nodes that aren't CX33 are priced a few % off. The native provider reads each node's
hcloud://<id>providerID and looks up the real per-instance/per-location rate, eliminating the approximation.Blocker (why this is a tracking issue, not a PR)
opencost#3710 (the hcloud provider) is still open — based on
develop, not merged, and not present in the deployed OpenCost1.120.3(chart2.5.x). Swappingprovider/relying onhcloud://auto-detection now would leave OpenCost with no matching provider and break the cost model. Adopt only once #3710 merges and ships in an OpenCost release.Already in place
vault-seed/seed-hcloud.yaml) and materialized as thehcloudSecret for CCM/CSI — so exposing it to theopencostnamespace is a small ESO step.Steps when #3710 ships in a release
opencostHelmRelease chart to the version whoseappVersionincludes the hcloud provider.ExternalSecretmaterializing a read-onlyHCLOUD_TOKENinto theopencostnamespace from the OpenBao path (don't reuse the CCM/CSI Secret cross-namespace).opencost.exporter.envHCLOUD_TOKEN(fallbackCLOUD_PROVIDER_API_KEY); the provider auto-detects fromhcloud://providerIDs.customPricingblock.coroot-custom-cloud-pricingCronJob) from the new authoritative per-instance numbers so the two cost views stay consistent — Coroot's model is per-CPU/per-GB only and can't consume the provider directly.kubectl kustomizeprod+local,ksail --config ksail.prod.yaml workload validate) and open a draft PR.Refs