Skip to main content
KinetiStack™

FAQ

Top questions from first-time and existing customers. For deep-dives, see QUICKSTART, E2E-RUNBOOK, and OPERATIONS.


Sizing & cost

How much does a typical deployment cost?

Baseline (always-on): ~$15–$45/month depending on options. The deployed Bicep emits an estimatedMonthlyCostUsd output with a per-component breakdown after every deploy.

ComponentTypical cost
Key Vault Standard~$1/mo
Log Analytics workspace$0.10/GB ingested (first 5 GB free)
Control plane Container App (idle)~$15/mo
Container Apps Environment$0 (Consumption tier, default) — or ~$120/$240/$480/mo for WorkloadProfile D4/D8/D16 (v0.14.0+, opt-in for >4 GiB containers and faster cold-start)
3× Private endpoints (if enabled)~$22/mo
ADLS Gen2 storageusage-based ($0.018/GB Hot, $0.01/GB Cool, $0.002/GB Archive)
Container Apps Job executions$0.000024/vCPU-sec + $0.0000025/GiB-sec

A first deploy + first extract on a 100-table schema typically lands under $1.

How long does an extract take?

Schema sizeDuration
< 10 tables, < 1M rows1–2 min
100 tables, ~50M rows10–15 min
1,700 tables, ~1 TB90–120 min

Numbers from docs/E2E-RUNBOOK.md benchmark runs. Your mileage will vary with LOB density, Oracle PROCESSES limit, and chosen parallelism.


Deployment

Do I need to build the Docker images myself?

No. The publisher’s prod ACR (ksoradlsacrprod.azurecr.io) is Standard-tier with anonymous pull enabled — the Bicep template’s default image references work without any auth setup. Only build your own if you’ve forked the publisher.

Can I deploy without Owner / User Access Administrator?

Yes. Set assignRoles: false in the parameters and have a UAA admin run the role assignments separately. The deploy still succeeds and emits a uamiPrincipalId output you hand to your admin to wire up. See QUICKSTART §4 for the exact commands.

Can I use private endpoints from day 1?

Yes. Set peSubnetResourceId to a /28+ subnet in the same VNet as the CAE subnet (must be separate — CAE subnet is delegated and can’t host PEs). The template creates three PEs (blob, dfs, KV) plus the private DNS zones.

When do I need to flip to Workload Profile? (v0.14.0+)

The default Consumption tier caps containers at 2 vCPU / 4 GiB and scales to zero (so idle cost is $0). The failure mode for 4 GiB is silent Linux OOM-kill on the restore Job — the JVM gets killed before Spark can log a diagnostic, and the execution is marked Failed with no error in the logs. You’ll hit this around:

  • Restoring tables with 500K+ rows at the default batchSize=10000
  • Extracting wide tables (100+ columns) or LOB-heavy schemas at the default fetchSize=10000
  • Running parallel concurrent jobs that share the same Consumption-tier ceiling

Two ways out:

  • Quick / no-redeploy: lower the per-job knob from the UI Advanced section (batch_size: 1000 on restore, fetch_size: 2000 on extract). This works on Consumption.
  • Production: set containerAppsEnvironmentTier=WorkloadProfile and workloadProfileName=D4 (or D8/D16) at deploy time. Adds ~$120/mo idle but lifts the container ceiling to 16/32/64 GiB and drops cold-start from ~10 s to ~1 s.

My deploy fails with MissingSubscriptionRegistration

Run ./scripts/register-rps.sh once per subscription. Registers Microsoft.App, ContainerRegistry, KeyVault, ManagedIdentity, OperationalInsights, Storage.


First extract

My extract job started but produced zero tables

Three usual causes:

  1. Wrong schema name in defaultSchemas. Run scripts/discover-schemas.sh --host ... --service ... --user ... --password ... to see what schemas the connecting user can actually read.
  2. Missing EXECUTE on SYS.DBMS_FLASHBACK — silently no-ops if the grant was issued as SYSTEM instead of SYS AS SYSDBA. Failure mode: ORA-00904: "DBMS_FLASHBACK"."GET_SYSTEM_CHANGE_NUMBER": invalid identifier. Re-issue grants as SYSDBA; see scripts/grant-extractor-perms.sh which forces the right connection.
  3. Oracle host unreachable from the CAE subnet. Run the preflight job first: az containerapp job start -g <rg> -n <prefix>-preflight.

Extract failed with Connection refused to 169.254.169.254

You’re using a legacy auth mode that uses the Azure IMDS endpoint which doesn’t work inside Container Apps. Set authMode: auto in parameters (default in v0.5+) — it uses the custom token provider which works on Container Apps MSI, AKS WIF, VM MSI, SP env vars, and dev creds without IMDS.

ORA-00942: table or view does not exist

The connecting user doesn’t have SELECT on the schema’s tables. Either grant SELECT ANY TABLE to the user, or grant explicitly on the specific schemas you intend to archive.

How do I cancel a running extract?

az containerapp job execution list -g <rg> -n <prefix>-extractor \
   --query "[?properties.status=='Running'].name" -o tsv | \
   xargs -r -I{} az containerapp job execution stop \
      -g <rg> -n <prefix>-extractor --execution-name {}

The extractor has no graceful-shutdown protocol; it’s safe to kill mid-run because the manifest is rewritten after every phase and any in-flight Parquet files are simply orphaned (lifecycle policy will tier and delete them).


Querying archived data

I want to query without restoring to Oracle

After every extract, the manifest produces two SQL files in <container>/<job_id>/_catalog/:

  • synapse.sql — paste into a Synapse Serverless SQL pool
  • fabric.sql — paste into a Fabric Lakehouse SQL endpoint

Both expose the archived tables as views via OPENROWSET against Parquet. See SYNAPSE-QUERY-GUIDE.md and FABRIC-QUERY-GUIDE.md.

Can I use Power BI directly against the archive?

Yes, via either Synapse Serverless or Fabric as the query engine. Power BI’s “ADLS Gen2” connector reads Parquet natively too but loses the manifest-driven view abstraction. Use Synapse/Fabric as the SQL layer for production reporting.


Restore

Can I restore to a different Oracle instance?

Yes — that’s the typical case. Set ORACLE_HOST (and ORACLE_USER, ORACLE_PASSWORD) on the restore Job to the target instance. The source archive (in ADLS) and the target Oracle don’t need to be related; you can archive Prod and restore to Dev for testing.

Restore is slower than extract — why?

Oracle’s JDBC INSERT path serializes per table (no parallel writers without partitioning hints). Restore is typically 2–3× slower than extract. To speed up: disable indexes during restore (DISABLE_INDEXES_DURING_RESTORE=true) and recreate them after, or pre-create the target schema with nologging tables.

Can I restore just one table?

Yes. Set TABLES_INCLUDE=SCHEMA.TABLE on the restore Job.


Compliance

Is the archive immutable?

Only when lifecycleProfile: 'compliance' is set at deploy time — that enables Azure storage’s time-based immutability for 2557 days (7 years). The default profile (none) and the standard profile do not enforce immutability.

Even with compliance, the policy is created unlocked at deploy time. To make it truly tamper-resistant, you must explicitly lock the policy afterward (see OPERATIONS §6). Locking is irreversible.

How do I prove the archive wasn’t modified?

Three artifacts together provide the proof:

  1. The manifest (<container>/<job_id>/_manifest.json) records the SCN, row counts, and per-table extract status.
  2. The immutability lock state on the container.
  3. KV access logs + storage access logs in Log Analytics (require enableDiagnostics: true).

OPERATIONS §6 walks through the exact az commands an auditor will ask for.


Security

Where is the Oracle password stored?

In the Azure Key Vault created by the template. The Container Apps Job reads it via a Key Vault reference at job start; the value never appears in the deployed Bicep template state or in env-var output.

How do I rotate the Oracle password?

az keyvault secret set --vault-name <kv> --name oracle-password --value '<new>'

No redeploy needed. The next job execution picks up the new secret at container start. See OPERATIONS §1.

Are images signed?

JAR checksums are pinned and verified at build time (see scripts/verify-jar-checksums.sh). Image-level signing is on the roadmap — track in CHANGELOG [Unreleased] section.

The control plane returns 401 for every request

Easy Auth wasn’t configured. Run scripts/setup-easyauth.sh to create the Entra App Registration, then redeploy with the resulting client ID as easyAuthAppId. The 401 message in the response body links back to this section.


Operations

How do I tear down without losing the archive?

./scripts/teardown.sh <rg> --preserve-archive

Moves the storage account to a quarantine RG <rg>-preserved-archive before deleting the rest. The preserved storage keeps the archived Parquet indefinitely.

What about Key Vault and Log Analytics soft-delete?

KV is soft-deleted for 7 days; LAW for 14 days. The teardown script purges both automatically. If you re-deploy with the same names inside those windows, the redeploy fails — see QUICKSTART §7.

Can I upgrade across versions without losing data?

Yes, within the same major version. Run the new template version’s deploy.sh against the existing RG — Bicep is idempotent and only touches changed resources. Existing manifests and archive Parquet stay put. Breaking changes (rare; major-version bumps only) are called out under ### Breaking in CHANGELOG.md.