ImportCluster manifest is the declarative entry point for onboarding a cluster into Ankra and describing its stacks. Apply it with the CLI:
--cluster targets the cluster you name, by name or id; without it the target is the manifest’s metadata.name. cluster apply honours --cluster from CLI v0.16.0 - earlier versions ignore it and use metadata.name. The same schema is what Ankra reads from a connected GitOps repository.
Full Example
Top Level
spec.git_repository
Connect a Git repository so stacks are stored and synced from Git. Omit the block entirely for a non-GitOps import.
Applying a changed
git_repository block repoints the cluster. Ankra first writes the cluster’s current state - every stack, add-on and manifest it manages, with secrets sealed under your organisation’s key - to the new repository and branch as a commit, overwriting the files it manages there, and only then syncs from it. The new source does not need to be seeded by hand: the switch itself brings it to parity. Any branch works - a cluster is not tied to its repository’s default branch, so one repository with a branch per environment is a supported layout - but the branch must already exist; Ankra does not create branches.
A repoint is refused until you acknowledge it: ankra cluster apply --allow-repoint, plus --allow-repoint-destroying-data when the cluster holds PersistentVolumeClaims. The refusal lists what the cluster runs today; it is not a diff against the target.
Observability sources in Git
spec.prometheus_metrics and spec.log_source connect the cluster’s metrics and log data sources. Both are read back from the cluster document on every sync, so authoring or editing either block in Git connects the source and updates it - the same result as filling in the platform’s metrics or log source settings.
Three rules apply to both members:
- Credentials are never in Git.
username,password,tokenandauth_schemeinside a source block are refused by name, because ignoring them would leave a live secret sitting in your repository while you believe it is in effect. Create the credential in the platform and reference it bycredential_name. - Unknown top-level fields are refused, not ignored, and the error names the offending key and the accepted set. A mistyped field fails the sync rather than silently doing nothing.
- Removing the block does not disconnect the source. Git can create and update a source; only the platform can disconnect one.
spec.prometheus_metrics
The cluster’s metrics data source. See Prometheus for endpoint examples per product.
spec.log_source
The cluster’s log data source. See Log Sources for provider endpoints and field-mapping defaults.
spec.helm_registries[]
Declare the Helm registries the file’s add-ons depend on, so the repository is self-contained: applying the file connects any registry that is not already present before add-ons deploy. A declaration matching an existing registry (same name, same URL - org-scoped or global) is an idempotent no-op; a declaration whose name is taken by a registry with a different URL fails the apply before anything is written. Credentials are referenced by name and must already exist, so secrets stay out of Git.
spec.stacks[]
Each stack groups related manifests, add-ons, and applications.
spec.stacks[].backup
Protecting a stack is one block. Ankra takes scheduled restore points of the stack into the backup vault you name, on the schedule the block gives, through the same capture a manual restore point uses. For each CloudNativePG cluster it also writes the barman-cloud archiver into the cluster’s member and keeps the object store the archiver writes into in a stack member of its own, ankra-backup-policy-<stack>; see Protect a stack for what that does to the cluster.
ankra cluster stacks protect <stack> writes this same block without editing the file; ankra cluster stacks unprotect <stack> sets enabled: false. See Protect a stack.
Protecting a stack does not sweep every volume in it. Databases are captured by default, because a restore point without the database contents is the one nobody forgives. Volumes are captured only when you name them in
selection.persistent_volume_claims, because a stack’s namespaces routinely hold caches, scratch space and metrics storage that nobody wants copied to object storage every night. Use the stack’s data inventory - ankra cluster stacks data list <stack> - to see the asset names.backup leaves the stored policy exactly as it was. That is deliberate: ankra cluster apply replaces a stack with what the file says, and an older CLI or a hand-written file that simply did not know about the block would otherwise unprotect the stack in silence. Removing protection is backup: {enabled: false} - something a person typed. When an apply does narrow protection, the result carries a warning naming what is no longer covered.
The schedule itself is never stored as a stack member: it is read from this block every time the stack is due, so no apply, clone or profile capture can leave a stack with a schedule that no longer matches its policy. The two things protect does write into the stack for a CloudNativePG cluster - the archiver on the Cluster and the ankra-backup-policy-<stack> member holding its object store - are Ankra’s: a clone and a profile capture leave both out and say so. An apply that replaces the stack from a file without them heals in two ways, depending on what the file dropped. If only the object store member went, the next restore point - scheduled or manual - puts it back, because that restarts nothing. If the archiver itself went, scheduled backups are skipped with archiver_not_wired until you protect the stack again or take a restore point by hand; either puts the archiver back and restarts the instances once.
Deploy waves
deploy_wave sequences whole stacks: a stack in wave N starts deploying only after every stack in a lower wave finished successfully, and teardown unwinds in reverse wave order. Stacks in the same wave deploy in parallel, and stacks without a deploy_wave stay independent of the ordering entirely - existing clusters keep their current behaviour.
1, 5, 20 works and leaves room to slot stacks in later. If a stack in wave N fails, later waves stay blocked until it is fixed or removed. Within a stack, parents still control resource-level order.
Include paths
Instead of inline entries, reference files or folders in the repository. Ankra loads every YAML file found:spec.stacks[].manifests[]
Raw Kubernetes YAML resources.
spec.stacks[].addons[]
Helm releases.
settings defaults
Sync behaviour defaults to fully automated. See Add-on Settings for semantics.
spec.stacks[].applications[]
Deployments of Applications created in Ankra.
Parents
parents are the dependency edges that control deployment order: a resource deploys only after all of its parents succeed. Every parent is a kind + name pair - write both keys:
kind must be manifest or addon, and the parent must be defined somewhere in the same file. Namespace manifests must be parents of everything deployed into that namespace.
Parents reference the other resource by name. Because a rename is a delete plus a create (see the manifests warning), renaming a parent also means updating every parents entry that points at it in the same change.
Validation
ankra cluster apply validates the file before sending anything: unknown fields, missing parents, and invalid parent kinds are rejected with the offending path. Use --dry-run to validate without applying.
ankra cluster validate -f cluster.yaml is the server-side pre-flight gate, built for CI: it runs every rule apply enforces without touching the cluster. That covers structure (duplicate names, missing parents, dependency cycles), chart resolution (registry connected, chart exists, pinned version exists), plaintext-secret detection, and the per-resource field rules - add-on namespaces (Kubernetes DNS label: 1-63 characters, lowercase letters, digits and -, starting and ending with a letter or digit), group names, and empty manifest bodies. Pass --cluster <id> to additionally validate against that cluster’s live resources, exactly as an apply to it would.
validate also warns when a declared encrypted_paths entry seals more keys than the one it names (category encrypted_paths_over_match, see What an Entry Actually Matches). The warning is computed from the entries you declare, so a resource with an empty declaration never produces one, and ankra cluster apply does not report it - run validate first when a pipeline drives the API.