Skip to content
Rod Christiansen edited this page Oct 8, 2026 · 2 revisions

Cost

No dollar figures here — pricing varies by region and changes without notice. What follows is which parts of this module actually drive spend, and which variables you turn down for a small fleet. Check the Azure pricing calculator for the numbers.

The big four

In rough order of contribution for a default deployment:

  1. The API container app. 2 vCPU and 4 GiB per replica, with api_min_replicas running continuously and up to api_max_replicas under load. This is the largest single allocation in the module and it is billed whether or not the CPU is doing anything.
  2. PostgreSQL Flexible Server. Compute is db_sku_name; storage is auto-growing and therefore monotonic; backup storage beyond the included allowance is charged per GB and doubled if geo-redundant.
  3. Log Analytics and Application Insights. Charged per GB ingested and per GB retained beyond the free retention period.
  4. Front Door, if enabled — a fixed monthly floor plus usage charges.

The dashboard container (0.5 vCPU / 1 GiB, 1–5 replicas) is comparatively cheap. Its sizing is hardcoded in the containers module, not a variable.

Levers, by resource

API container

Variable Default Effect on cost
api_min_replicas 1 The floor you pay for continuously. Cannot go below 1 without the API cold-starting on every request
api_max_replicas 5 The ceiling. Lowering it caps burst spend, but the plan precondition ties it to the connection budget
api_db_pool_max 40 Doubles as the HTTP scale rule's concurrency threshold. Raising it means each replica absorbs more before a second one starts, so fewer replicas for the same traffic

For a small fleet, the highest-yield change is lowering api_max_replicas. Raising api_db_pool_max reduces scale-out but raises the Postgres connection demand, and the precondition will tell you when the two no longer fit.

The 2 vCPU / 4 GiB per-replica sizing is not exposed as a variable. If you are running a few hundred devices rather than a few thousand, that is the number to edit in modules/containers/main.tf, and it is the one that will save the most.

Database

Variable Default Effect on cost
db_sku_name B_Standard_B1ms Burstable B-series is already the cheap tier. General Purpose is a step change upward
db_storage_mb 262144 (256 GB) Create-time floor. For a small fleet, set this far lower on a new deployment — auto-grow will raise it as needed and it can never come back down
db_backup_retention_days 35 Backup storage above the included allowance is charged per GB. Dropping toward the 7-day minimum is a direct saving, at the cost of your restore window
db_geo_redundant_backup false Roughly doubles backup storage. Already off; leave it off unless you need it, because turning it on later is a rebuild

The 256 GB default exists to match an already-large production server. On a fresh small deployment it is the single most over-provisioned default in the module.

Monitoring

Variable Default Effect on cost
log_daily_quota_gb 2 Hard ceiling on ingestion. This is a runaway backstop — ingestion pauses for the rest of the UTC day when hit, so do not set it below your normal volume
log_retention_days 30 Retention beyond the workspace's included period is billed per GB-month
app_insights_daily_cap 1 Same shape, for Application Insights

Application Insights is already configured at 50% sampling, which halves telemetry ingest. The module's comments describe a real incident where a single container emitted ~19 GB in 30 days, most of it one log line per HTTP header — the caps exist because of that.

Edge

enable_custom_domain is the switch. Off, you pay nothing and reach the dashboard on its Container Apps FQDN. On, you get a Front Door Standard profile with a fixed monthly base plus per-GB egress and per-million-request charges. For an internal-facing fleet dashboard, running without Front Door is a legitimate configuration.

Registry

use_custom_registry defaults to false, which means you pull from the registry named by existing_registry_server and create no ACR at all. Setting it true creates a Basic-tier ACR — a small fixed cost plus storage. Only turn it on if you build modified images.

Functions

enable_functions defaults to false. On, you get a Flex Consumption plan (pay per execution and per GB-second, with a free grant) plus a second storage account. The alerting and archive workloads it hosts are low-frequency, so this is a small line item — but it is not zero, and the storage account persists regardless of invocation count.

Key Vault

enable_key_vault defaults to true. Vault cost is per-operation and negligible at this scale. Turning it off to save money is not worth it: it also strips the dashboard's NEXTAUTH_SECRET and AZURE_AD_CLIENT_SECRET.

A small-fleet starting point

For a deployment measured in hundreds of devices rather than thousands, the changes with the best cost-to-risk ratio, in order:

  1. api_max_replicas down.
  2. db_storage_mb down — only on a new deployment, since storage cannot shrink.
  3. db_backup_retention_days down toward 7, if your recovery expectations allow it.
  4. log_retention_days down.
  5. enable_custom_domain left false.
  6. Edit the API container's CPU and memory in modules/containers/main.tf.

Leave the daily quotas where they are. They are protection against a logging regression billing without limit, and lowering them below normal volume trades a small saving for a blind spot.

Clone this wiki locally