Skip to main content
Ankra makes it easy to manage clusters using GitOps. Define your cluster’s configuration, manifests, and add-ons in YAML files, store them in Git, and let Ankra handle the automation.

What is GitOps?

GitOps is a way to manage your Kubernetes infrastructure using Git as the single source of truth. With Ankra:
  • Store configuration in Git - Your cluster definitions, manifests, and add-ons live in your repository
  • Automatic sync - Ankra detects changes and applies them to your clusters
  • Version control - Track every change, roll back when needed, review via pull requests
  • Team collaboration - Multiple team members can update configurations safely

How It Works

Ankra uses include paths to let you split your configuration into multiple files or folders. This keeps your setup modular, maintainable, and easy to scale.

Why Use Include Paths?

CI/CD Integration

Keep manifests and add-ons in separate files or folders for easy automation in your CI/CD pipelines. Update only what you need, and trigger deployments automatically.

Modularity & Reuse

Organize resources by team, environment, or feature. Reuse the same manifests or add-ons across different stacks or clusters.

Team Collaboration

Let different teams own and update their own YAML files without merge conflicts. Everyone works from the same Git repository.

Scalability

Easily add new resources or stacks by dropping new YAML files into the right folder - no need to edit a giant config file.

Repository Structure

Organize your Git repository with separate folders for manifests and add-ons:
The optional AGENTS.md sibling files hold per-manifest and per-add-on operational learnings for your team and Ankra’s AI - see Teach Your Agents with AGENTS.md.

Cluster Definition Example

Your import-cluster.yaml references files using include paths:
Ankra will automatically load and apply all YAML files from the manifests/ and addons/ folders. You can also include individual files for more control:

Single-File Cluster Definition

For small or self-contained setups you can skip include paths and define everything inline in one file. Manifest and values content is embedded as base64:
Use parents to control deployment order - a resource only deploys after its parents succeed. Prefer include paths once a cluster definition grows beyond a couple of resources. Every field of this file - stacks, manifests, add-ons, applications, parents, and encrypted paths - is documented in the ImportCluster YAML Schema.

Data Sources in the Cluster Document

The cluster’s metrics and log data sources live in the same file, as spec.prometheus_metrics and spec.log_source. Both are read back on every sync, so writing either block in Git connects the source and updates it - you do not have to configure it in the platform first:
Credentials stay out of Git: a username, password, token or auth_scheme inside a source block is refused, and the credential is referenced by credential_name instead. Deleting a block does not disconnect the source - Git can create and update one, only the platform can disconnect it. See spec.prometheus_metrics and spec.log_source.

How Ankra Syncs Your Cluster

  1. You update or add YAML files in your Git repository
  2. Ankra detects the change and automatically syncs your cluster
  3. All included manifests and add-ons are applied in the order you specify

What Ankra Writes Back to Git

Sync is two-way. Changes you commit are applied to the cluster, and changes made through the portal, the CLI, the API or Ankra AI are written back to the cluster’s directory in the repository, so Git stays the record. A platform write lands as a commit authored by ankra-platform[bot] (a change made in the portal, CLI or API) or by Ankra Reconciler with the subject Sync cluster state from Ankra (the reconciler exporting stored state).

The ownership manifest: .ankra-owned.json

Every cluster directory carries a file named .ankra-owned.json. Ankra rewrites it on each platform write. It is a record of what that write rendered - not an inventory of the directory, and not a claim on it:
  • paths lists the files the last write rendered. It bounds deletion: when a stack or add-on is removed, only files listed here are pruned. A file Ankra never rendered is never deleted, only reported.
  • contents maps each rendered file to a digest of the bytes Ankra itself last wrote there. It bounds overwriting: before writing a file, Ankra compares what is in Git with that digest. If they differ, the file was edited since, and Ankra keeps the Git version instead of replacing it.
Because the manifest is regenerated from each render, it grows when the cluster gains stacks or add-ons, and a write scoped to one stack may list a path it chose not to write. Neither means Ankra will overwrite that path; the digest decides.
Never delete or hand-edit .ankra-owned.json. It does not fail safe. With no manifest at head, Ankra has no record of what it wrote, so the overwrite boundary switches off and the next platform write replaces whatever is in Git. If it has been removed, restore it from Git history.

Hand-maintaining a file

To keep a value Ankra would otherwise render - an image tag pinned above a chart’s appVersion for a CVE fix, an updateStrategy, topologySpreadConstraints - edit the file in Git and merge it. Ankra syncs the change into the cluster, and from then on the file’s bytes in Git no longer match the digest Ankra recorded, so no platform write replaces them. This holds for every write path: portal, CLI, API, Ankra AI and the reconciler’s own export. Three limits apply today:
  • SOPS-encrypted files are not covered. Their committed bytes are ciphertext that cannot be reproduced from the render, so Ankra keys them on the embedded content fingerprint instead, and re-encrypts the file whenever its stored values change. A hand edit to an encrypted file sealed under the cluster’s .sops.yaml is imported like any other Git change and then re-sealed by Ankra’s next write - the values survive, the ciphertext does not, so expect one re-seal commit after rotating a sealed Secret by hand (see Rotating by API and SOPS).
  • .sops.yaml in the cluster directory has its own rule. Ankra rewrites the creation rules it generates there on every export, but it no longer replaces the file: rules you add by hand are kept, and kept above Ankra’s own. See Merging the SOPS configuration file below.
  • Preservation is silent. Ankra logs Preserving git content the platform did not write on its side, but the sync status still reads in sync and no portal, CLI or API surface lists the preserved paths yet. While a file is preserved, a change made to it in Ankra does not reach Git - make the change in Git instead, which also brings Ankra’s copy back in line.

Merging the SOPS configuration file

The .sops.yaml in a cluster directory has two authors, so it is not covered by the digest boundary above: it is merged on every platform write instead of replaced, and the file it writes opens with a header saying so.
  • Ankra owns only the rules it generates: a rule carrying a path_regex Ankra generates, an age key, and at most an encrypted_regex - and nothing else. Ankra rewrites those on every sync and lists them last in the file. While the cluster declares encrypted_paths, each generated rule carries an encrypted_regex built from the union of every declaration across the cluster’s stacks, rebuilt on every sync as the declarations change, so a sops -e that applies the rule seals only declared secret keys and leaves every other key readable. It is one union per cluster, so it is broader per file than what Ankra itself seals per resource: a key declared secret for any resource in the cluster is sealed in every matching file.
  • Every other rule is yours. It is preserved verbatim and kept above Ankra’s own. SOPS applies the first matching creation rule, so a rule of yours takes precedence over Ankra’s - including a deliberately keyless first rule, which is the supported way to keep a path out of encryption and make an external sops -e on it fail loudly rather than seal a file that must stay plaintext. Write its path_regex relative to the cluster directory, not the repository root: sops matches a rule against the file’s path relative to the directory holding the .sops.yaml it is using, so for the cluster’s file the path being tested is stacks/<stack>/add-ons/<add-on>/values.yaml. A rule written from the repository root never matches, and a refusal caused by nothing matching is an accident, not protection - see Checking that a keyless rule applies.
  • To override one of Ankra’s rules, write a rule that is not shaped like Ankra’s: keyless, using key_groups, carrying a field other than path_regex, age and encrypted_regex, or on a different path_regex. A rule that is a path_regex Ankra generates plus an age key, with or without an encrypted_regex, cannot be told apart from Ankra’s own output and is replaced whatever its age or encrypted_regex values are - that is what lets a key rotation or a changed declaration reach the file, and it happens silently. To keep your own recipients or your own encrypted_regex on a path Ankra covers, name the recipients with key_groups. The warning below spells it out.
  • Other top-level keys are yours too. stores, kms, shamir_threshold and anything else in the file are carried through untouched.
  • Ankra does not read these rules. Its own encryption is driven per resource by that resource’s encrypted_paths declaration, compiled to a SOPS encrypted_regex when the resource is sealed (see SOPS). The file exists for external tooling that runs sops against the repository.
A .sops.yaml Ankra cannot parse is left exactly as it is, rather than rewritten.

Checking that a keyless rule applies

sops looks for .sops.yaml by walking up from the current directory, not from the file it is given, and matches each path_regex against the file’s path relative to the directory holding that .sops.yaml. Test a rule from the repository root with an explicit --config, writing to stdout (never -i):
What comes back says which rule decided. The wording is from sops 3.13.3 and is not a stable interface; an automated check should key on the positive control below rather than on the text. Pair the check with a positive control in the same run: a neighbouring file that only a rule with recipients covers must encrypt, or the refusal proves nothing about your rule. Ankra’s generated rules are written relative to the cluster directory (.*values\.yaml$ and .*manifests/.*\.yaml$), so on a cluster synced since that change they match and can serve as the control: a values file only they cover must encrypt. A .sops.yaml still carrying the older repo-rooted spellings (<cluster-directory>/.*values\.yaml$) predates the change - those rules match nothing, Ankra’s next write to the cluster replaces them, and until then a control needs a keyed rule of your own, written relative to the cluster directory like the keyless one.
The shape to avoid: one of Ankra’s own path_regex values, an age key, and nothing else except an encrypted_regex. A rule in that shape cannot be told apart from Ankra’s output, so the next platform write replaces it - with no signal anywhere. The sync succeeds, and no portal, CLI or API surface reports it. The only trace is the reconciler’s own Sync cluster state from Ankra commit, where the rule is simply gone from the diff.All three conditions have to hold together - that path_regex, an age key, and no field beyond those two and encrypted_regex - so the only rules at risk are those whose path_regex is character-for-character one of the two Ankra generates:
The older repo-rooted spellings of the same two patterns, prefixed with the cluster’s own directory (<cluster-directory>/.*values\.yaml$, <cluster-directory>/.*manifests/.*\.yaml$), are read as Ankra’s too: clusters synced before the config-relative change still carry them, and the next platform write replaces them with the rules above. The examples below use that older spelling - the ownership test is the same for both.The trap is tidying. A deliberately keyless rule on one of those two patterns is yours and is kept - but give it an age key, to “complete” it or to seal that path with your own recipient, and it becomes Ankra’s shape and disappears on the next write. Adding an encrypted_regex of your own does not take it back out: that field is part of Ankra’s shape, so the rule is still replaced, and your selector with it:
Any one of these keeps a rule out of Ankra’s shape: leave it keyless, name recipients with key_groups, carry a field outside path_regex, age and encrypted_regex (unencrypted_suffix, for example), or write it on a path_regex Ankra does not generate. An encrypted_regex on its own does not: it is part of Ankra’s shape. The header Ankra writes at the top of the file states the same test. The paths in this example show the ownership test only; a rule you rely on sops to apply must be written relative to the cluster directory, as described above.
Removing the last encrypted_paths entry on a cluster deletes .sops.yaml, and your own rules with it. Ankra renders the file only while the cluster has encrypted content. Clear the last encrypted_paths entry from the last add-on or manifest that had one, and the next platform write stops rendering .sops.yaml, so the export prunes it from the cluster directory. Ankra never reads .sops.yaml back in, so there is no copy in the platform to restore from - recover it from Git history.This matters most in the case that leads you there: removing an over-broad entry is the fix for a chart field that was sealed and should not have been (see SOPS). If that entry is the cluster’s last one, keep a copy of .sops.yaml first, and re-commit your rules after Ankra’s next write.

Monitoring Sync Status

Track the status of your GitOps syncs in the cluster settings.

Sync Status Banner

Navigate to your cluster → SettingsGitOps to see the current sync status:

Sync Progress

During a sync, you’ll see the progress through these phases:
  1. Fetching - Pulling latest changes from Git
  2. Validating - Checking YAML syntax and configuration
  3. Applying - Deploying changes to the cluster
  4. Completed - Sync finished successfully

Manual Sync

Click Sync Now to trigger an immediate sync from your Git repository. Use this when:
  • You want to apply changes without waiting for automatic detection
  • Webhook delivery failed
  • You need to force a refresh

Sync History

View a complete history of all GitOps syncs for your cluster.

Accessing Sync History

  1. Go to your cluster → SettingsGitOps
  2. Scroll down to the Sync History table

History Table Features

The sync history table shows: Table Features:
  • Pagination: Navigate through history (10 entries per page)
  • Sorting: Click column headers to sort by any field
  • Commit Links: Click the SHA to view the commit in GitHub

Sync Metadata

Each sync entry includes detailed metadata:
  • Last Commit SHA: The exact commit that was synced
  • Sync Source: webhook (automatic) or manual
  • Timestamp: When the sync occurred
  • Retry Count: Number of retry attempts (if any)
  • IAC Files Link: Direct link to view the configuration files in your repository

Handling Sync Errors

When a sync fails, Ankra provides detailed error information to help you fix issues quickly.

Error Display

Failed syncs show:
  • Validation Errors: Issues with YAML syntax or configuration
  • Field-Level Guidance: Specific fields that need attention
  • Missing Fields: Required fields that weren’t provided
  • Typo Detection: Suggestions for misspelled field names

Common Error Types

YAML syntax issues or invalid configuration values.Solution: Check the error details for the specific field and fix the YAML in your repository.
Required configuration fields weren’t provided.Solution: The error shows which fields are missing with examples of expected values.
A resource already exists or conflicts with another definition.Solution: Check for duplicate resource names or conflicting configurations.

Retrying Failed Syncs

  1. Fix the issues in your Git repository
  2. Commit and push the changes
  3. Click Sync Now or wait for automatic detection
  4. Monitor the new sync in the history table

Best Practices

Keep related resources together. Group manifests and add-ons by environment, team, or feature.
Use clear folder names. Make it obvious what each folder contains (e.g., manifests/, addons/, prod/, dev/).
Automate with CI/CD. Trigger Ankra syncs on pull requests or merges to main.
Review changes in Git. Use pull requests to review and approve updates to your cluster configuration.

Troubleshooting

If Ankra isn’t syncing as expected:
Use the Ankra WebUI to see sync status and any errors. The Operations page shows deployment history and helps identify issues.

Global Helm Registries

Ankra comes with a curated index of preloaded Helm charts that are ready to use out of the box. These registries power the add-on catalog in the Ankra platform.

Community Contributions

Want to add a Helm chart that would benefit the entire Ankra community? Submit a pull request to the ankra-global-resources repository. Your contribution will be available to all Ankra users.
The ankra-global-resources repository contains:
  • Helm Registries - Preloaded chart repositories that appear in the Ankra add-on index
  • Global Resources - Platform-wide resource definitions

Contributing a Helm Registry

  1. Fork the ankra-global-resources repository
  2. Add your Helm registry definition to the helm_registries/ folder
  3. Submit a pull request with a description of the charts and their use cases
  4. Once merged, your charts will be available to all Ankra users
When contributing, ensure the Helm charts are well-maintained, secure, and provide value to the broader Kubernetes community.

  • Stacks - Learn about organizing resources into stacks
  • Add-ons - Install Helm charts as add-ons
  • Manifests - Deploy raw Kubernetes manifests

Still have questions? Join our Slack community and we’ll help out.