> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abbyy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-Managed Kubernetes

> Deploy Vantage 3.0 self-hosted on Kubernetes infrastructure that you provision and operate.

This guide deploys Vantage 3.0 self-hosted on a Kubernetes cluster that you provision and operate. It defines the interfaces Vantage requires from the cluster and uses Linkerd, Traefik, and External Secrets with HashiCorp Vault as examples. You can use equivalent components that satisfy the same requirements.

This guide starts with a running Kubernetes cluster. It does not install Kubernetes, the service mesh, ingress controller, secret-management system, databases, storage, or registries for you.

<Note>
  The `vantage-operator` and `vantage-selfhosted` charts must use the same version. The examples on this page use version `0.70.13` for both charts.
</Note>

## Reference architecture

| Concern                  | Vantage requirement                                                                                            | Example implementation                                                |
| ------------------------ | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| Kubernetes               | A supported Kubernetes version with working DNS, networking, and persistent volumes.                           | Kubernetes that you operate.                                          |
| Deployment orchestration | ArgoCD with ApplicationSet Progressive Syncs enabled.                                                          | ArgoCD 3.4.3.                                                         |
| Service mesh             | Workload-to-workload mTLS in the Vantage namespace.                                                            | Linkerd.                                                              |
| Ingress                  | HTTPS ingress that implements the Vantage path and rewrite contract and preserves the original request scheme. | Traefik with cert-manager.                                            |
| Secrets                  | Native Kubernetes `Secret` resources in the Vantage namespace.                                                 | External Secrets Operator materializing Secrets from HashiCorp Vault. |
| Database                 | SQL Server or PostgreSQL, with a separate logical database for each Vantage service.                           | PostgreSQL.                                                           |
| Cache                    | Redis.                                                                                                         | Redis 7.4.                                                            |
| Mail                     | SendGrid by default, or an SMTP server.                                                                        | SendGrid.                                                             |
| Storage                  | A pre-existing Kubernetes `StorageClass` suitable for your availability and durability requirements.           | A customer-provided persistent storage class.                         |
| Registries               | A source registry supplied for Vantage artifacts and a destination registry that you operate.                  | Any OCI-compliant private registry.                                   |
| Autoscaling and metrics  | KEDA plus Prometheus when KEDA support is enabled.                                                             | KEDA 2.17.3 and Prometheus Operator.                                  |

For supported and tested component versions, see [Compatibility](/vantage/self-hosted/v3.0/compatibility). For the complete infrastructure inventory and sizing baseline, see [Prerequisites](/vantage/self-hosted/v3.0/prerequisites).

## Before you begin

Have the following values and resources ready:

| Variable                                                 | Description                                                       |
| -------------------------------------------------------- | ----------------------------------------------------------------- |
| `$operator_namespace`                                    | Namespace for the Vantage operator.                               |
| `$install_namespace`                                     | Namespace for Vantage workloads.                                  |
| `$operator_version`                                      | `vantage-operator` chart version. Use `0.70.13` for this guide.   |
| `$selfhosted_version`                                    | `vantage-selfhosted` chart version. Use `0.70.13` for this guide. |
| `$charts_uri`                                            | OCI URI that ABBYY provides for the Vantage operator chart.       |
| `$chart_uri`                                             | OCI URI that ABBYY provides for the `vantage-selfhosted` chart.   |
| `$release_name`                                          | Helm release name for Vantage.                                    |
| `$your_vantage_hostname`                                 | DNS hostname for Vantage.                                         |
| `$your_mailfrom`                                         | Sender address for outbound mail.                                 |
| `$your_platformadmin_email`                              | Initial platform administrator email.                             |
| `$your_oci_host`                                         | Destination OCI registry that you operate.                        |
| `$abbyy_oci_source_host`, `$abbyy_oci_source_repository` | Source registry and repository supplied for Vantage artifacts.    |

You also need:

* A DNS record for `$your_vantage_hostname` that resolves to your ingress entry point.
* A valid TLS certificate for that hostname.
* Kubernetes registry pull Secrets when your registry requires authentication.
* Every application Secret listed under [Secret aliases](/vantage/self-hosted/v3.0/secrets-and-keyvault#secret-aliases).
* A distinct logical database name for each database alias. Each service's migrator creates its database on first run.
* Nodes labeled for TechCore workers.

## Prepare the cluster

### Configure ArgoCD

Install ArgoCD and enable [ApplicationSet Progressive Syncs](https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Progressive-Syncs/#enabling-progressive-syncs). ArgoCD also needs an OCI repository connection that can pull the Vantage component charts from your destination registry.

Register the destination registry as an OCI Helm repository by following the [ArgoCD private repository documentation](https://argo-cd.readthedocs.io/en/stable/user-guide/private-repositories/). Keep the registry credential in your existing secret-management system rather than placing credentials directly in an ArgoCD `Application` manifest.

### Configure the service mesh

Vantage requires mTLS between its workloads. Install and operate a supported service mesh, then enable mesh injection for `$install_namespace` before installing Vantage.

For example, with Linkerd:

```bash theme={null}
kubectl create namespace $install_namespace --dry-run=client -o yaml | kubectl apply -f -
kubectl label namespace $install_namespace linkerd.io/inject=enabled --overwrite
```

Confirm that newly created test pods in the namespace receive the mesh sidecar before continuing. If you use another mesh, follow its namespace- or workload-injection procedure.

### Configure TechCore worker nodes

TechCore worker workloads select nodes with the following label:

```bash theme={null}
kubectl label node <node-name> k8s.abbyy.com/techcore=true
```

Without at least one matching node, TechCore pods remain `Pending`. For training-worker isolation and the sizing baseline, see [Kubernetes node requirements](/vantage/self-hosted/v3.0/prerequisites#kubernetes-node-requirements).

### Configure persistent storage

Create or select a `StorageClass` before installing Vantage. The storage implementation must meet your production availability, durability, capacity, expansion, backup, and recovery requirements.

Reference it in the Vantage values:

```yaml theme={null}
vantage:
  storage:
    custom:
      storageClass: <storage-class-name>
      size: 300Gi
```

The `StorageClass` name is Kubernetes-distribution-neutral. Do not copy a development cluster's local storage class into production without evaluating the loss and failover characteristics.

## Prepare databases

Vantage supports SQL Server and PostgreSQL. Set the provider exactly as shown; the value is case-sensitive:

```yaml theme={null}
vantage:
  databaseProvider: PostgreSQL
```

Valid values are `SqlServer` and `PostgreSQL`. A value such as `Postgresql` or `PostgreSql` can fail at runtime because it does not match the application data-provider name.

Every Vantage service must use a distinct logical database. Services run their own migrations, and pointing multiple services at one database causes their migration state to collide. Use the database inventory under [Database aliases](/vantage/self-hosted/v3.0/secrets-and-keyvault#databases) to plan the database names and connection strings. You do not need to create the databases by hand: each service's migrator creates its database on first run.

<Warning>
  Reporting is available only with SQL Server. When using PostgreSQL, leave `vantage.reportingEnabled` set to `false`.
</Warning>

PostgreSQL connection strings must be a single line without leading, trailing, or embedded newline characters.

## Prepare Kubernetes Secrets

The Kubernetes secrets provider reads native Kubernetes `Secret` resources from `$install_namespace`. Vantage does not connect directly to Vault or another external secret store. If you use External Secrets Operator, a CSI driver, or another synchronization tool, configure it to materialize the required Kubernetes Secrets before installing Vantage.

Select the Kubernetes provider:

```yaml theme={null}
vantage:
  secrets:
    kubernetes: {}
```

By default, Vantage uses its documented Secret names. Use `objects` to map an alias to a different Secret:

```yaml theme={null}
vantage:
  secrets:
    kubernetes:
      objects:
        authSigningTlsCrt:
          secretName: vantage-auth-signing
        authSigningTlsKey:
          secretName: vantage-auth-signing
        authDeactivatedTlsCrt:
          secretName: vantage-auth-deactivated
        authDeactivatedTlsKey:
          secretName: vantage-auth-deactivated
        subscriptionDatabaseConnectionString:
          secretName: vantage-db-subscriptions
```

The two auth keypairs sign application tokens. They are separate from the certificate that terminates public HTTPS at the ingress controller. See [Certificate aliases](/vantage/self-hosted/v3.0/secrets-and-keyvault#certificate-aliases) for their required keys and formats.

When several services consume the generic `Database__ConnectionString` key, create a separate Secret for each service and map each database alias through `vantage.secrets.kubernetes.objects`. Your secret-management system can derive these Secrets from a common connection-string template, but every resulting connection string must name a different database.

<Note>
  The operator validates the secrets configuration during preflight. The matched `vantage-operator` and `vantage-selfhosted` charts grant the operator read access to Secrets through a ClusterRole that is bound only in the Vantage release namespace. If you customize the operator namespace or controller ServiceAccount, make the corresponding `operator` values in the Vantage chart match that installation. A custom `resourceNames` restriction must include every Secret referenced by the Kubernetes provider.
</Note>

## Configure registry access

Registry access has three separate consumers:

| Consumer                     | Required access                                                                           |
| ---------------------------- | ----------------------------------------------------------------------------------------- |
| Vantage operator             | Pull the operator image. Configure `manager.imagePullSecrets` when needed.                |
| OCI migration job            | Pull its job image, read from the source registry, and write to the destination registry. |
| Vantage workloads and ArgoCD | Pull workload images and component charts from the destination registry.                  |

Create registry Secrets in the namespace where each consumer runs. Do not put plaintext registry passwords in your values file.

For OCI migration, reference source and destination credential Secrets:

```yaml theme={null}
vantage:
  ociMigration:
    enabled: true
    serviceAccountName: <vantage-service-account>
    imagePullSecrets:
      - name: <operator-image-pull-secret>
    sources:
      - host: <source-registry>
        repository: <source-repository>
        credentialsRef:
          name: <source-registry-credentials>
    destination:
      host: <destination-registry>
      credentialsRef:
        name: <destination-registry-credentials>
```

Add the destination registry pull Secret to the `imagePullSecrets` of the ServiceAccount named by `vantage.serviceAccountName`, the default ServiceAccount for Vantage workloads.

<Note>
  If a component pod runs under another ServiceAccount, that ServiceAccount also needs registry pull access. Check the pod's `spec.serviceAccountName` before changing the namespace's `default` ServiceAccount.
</Note>

## Configure autoscaling and metrics

KEDA support is optional and recommended. Use KEDA 2.17.3: KEDA 2.18 and later removed a scaler field used by the current Vantage workload charts and cannot create the required HPAs.

Some Vantage `ScaledObject` resources query Prometheus at this fixed address:

```text theme={null}
http://prometheus-operated.observability.svc.cluster.local:9090
```

Before enabling KEDA:

1. Install KEDA 2.17.3.
2. Install Prometheus Operator and a Prometheus instance in the `observability` namespace.
3. Confirm its governing Service is named `prometheus-operated` and exposes port `9090`.
4. Configure Prometheus to discover the Vantage `ServiceMonitor`.

Enable KEDA on the `Vantage` resource and enable the chart's `ServiceMonitor` through the separate top-level `observability` stanza:

```yaml theme={null}
vantage:
  keda:
    enabled: true

observability:
  prometheus:
    namespace: observability
    serviceMonitor:
      create: true
```

`observability` is a top-level key; do not nest it under `vantage`. For trigger strategies, verification, and capacity planning, see [Autoscaling with KEDA](/vantage/self-hosted/v3.0/performance/autoscaling). For mesh-specific scraping configuration, see [Monitoring with Prometheus](/vantage/self-hosted/v3.0/monitoring/prometheus).

## Configure ingress and TLS

The chart's built-in ingress is for Istio. When using Traefik or another ingress controller, disable it:

```yaml theme={null}
ingress:
  enabled: false
```

Your ingress configuration must:

* Terminate HTTPS for `vantage.dnsRecord` with a trusted certificate.
* Route the Vantage UI, API, authentication, help, SCIM, URL-shortener, workspace, verification, and Try Any Skill paths to their corresponding Services.
* Apply the `/api/vN/` to `/publicapi/vN/`, `/api/`, SCIM, and heartbeat rewrites used by Vantage.
* Match more-specific routes before the UI catch-all route.
* Forward the original host and scheme, including `X-Forwarded-Proto: https` when TLS terminates at the ingress controller.

Traefik implements these requirements with an `IngressRoute` and ordered `Middleware` resources. Treat the route manifest as versioned Vantage configuration: parameterize the hostname, namespace, certificate Secret, and generated Service names for your release rather than copying values from another environment.

### Route contract

Resolve the generated Kubernetes Service names in `$install_namespace`, then implement these routes in the listed order. Regex and exact routes must take precedence over prefix and catch-all routes.

| Public path                                                                                                                                      | Vantage component | Rewrite or behavior                                                 |
| ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------- | ------------------------------------------------------------------- |
| `^/api/v[0-9]+(/\|$)`                                                                                                                            | API gateway       | Rewrite `/api/vN/...` to `/publicapi/vN/...`.                       |
| `^/verification/(markup\|manualreview)/<id>/notifications`                                                                                       | Verification      | No rewrite.                                                         |
| `^/workspace/(v1/files\|skilloperations/notifications\|projects/<id>/notifications\|skills/<id>/notifications\|catalogoperations/notifications)` | Workspace         | No rewrite.                                                         |
| `/api/heartbeat/scenarios`                                                                                                                       | Heartbeat         | Rewrite to `/api/scenarios`.                                        |
| Exact `/try-any-skill`                                                                                                                           | Try Any Skill     | Permanently redirect to `/try-any-skill/`.                          |
| `/try-any-skill/`                                                                                                                                | Try Any Skill     | No rewrite.                                                         |
| `/ad/` and `/ss/`                                                                                                                                | AD frontend       | No rewrite; use the Service port exposed by the generated workload. |
| `/auth2`                                                                                                                                         | Auth identity     | No rewrite.                                                         |
| `/help`                                                                                                                                          | Documentation     | No rewrite.                                                         |
| `/scim/`                                                                                                                                         | SCIM adapter      | Remove the `/scim` prefix.                                          |
| `/surl`                                                                                                                                          | URL shortener     | No rewrite.                                                         |
| `/api` and `/api/`                                                                                                                               | API gateway       | Remove the `/api` prefix.                                           |
| `/`                                                                                                                                              | Vantage frontend  | Catch-all route; evaluate last.                                     |

The chart's built-in Istio ingress also blocks `/api/status` and `/api/status/config`, which expose internal status information that clients do not need. Blocking these paths is recommended but not required for Vantage to run. If your ingress controller cannot return a direct denial response, you can route them to a dedicated deny backend before the general `/api` rule.

### Forwarded HTTPS scheme

When TLS terminates at an ingress controller and the backend connection is HTTP, the Vantage authentication services must honor `X-Forwarded-Proto`. Ensure the following environment variable is present on the application containers for `auth-identity`, `auth-adminapi2`, `api-gateway`, and `api-registry`:

```text theme={null}
ASPNETCORE_FORWARDEDHEADERS_ENABLED=true
```

If the current workload charts do not expose an environment-variable override, use your standard admission mutation mechanism, such as Kyverno or an equivalent mutating webhook. Apply the mutation before creating the Vantage pods. Without it, the OIDC discovery document can advertise `http://` endpoints and browser sign-in fails.

## Install the operator

Install one operator instance in the cluster:

```bash theme={null}
helm upgrade --install vantage-operator $charts_uri/vantage-operator \
  --version 0.70.13 \
  --namespace $operator_namespace \
  --create-namespace \
  --wait
```

When the operator registry requires a pull Secret, add this option to the command before `--wait`:

```bash theme={null}
  --set "manager.imagePullSecrets[0].name=<operator-image-pull-secret>"
```

## Install Vantage

Create a values file that combines the configuration prepared above. This abbreviated example shows the self-managed-specific values; add the complete Secret mappings and registry credentials for your environment:

```yaml theme={null}
operator:
  namespace: <operator-namespace>

ingress:
  enabled: false

vantage:
  dnsRecord: <vantage-hostname>
  mailFrom: <sender-email>
  platformAdminEmail: <platform-admin-email>
  serviceAccountName: <vantage-service-account>
  databaseProvider: PostgreSQL
  reportingEnabled: false
  updatePolicy:
    manual: {}

  secrets:
    # Add an objects mapping when your Secret names differ from the defaults.
    kubernetes: {}

  storage:
    custom:
      storageClass: <storage-class-name>
      size: 300Gi

  keda:
    enabled: true

  ociMigration:
    enabled: true
    serviceAccountName: <vantage-service-account>
    imagePullSecrets:
      - name: <operator-image-pull-secret>
    sources:
      - host: <source-registry>
        repository: <source-repository>
        credentialsRef:
          name: <source-registry-credentials>
    destination:
      host: <destination-registry>
      credentialsRef:
        name: <destination-registry-credentials>

observability:
  prometheus:
    namespace: observability
    serviceMonitor:
      create: true
```

Install the matching `vantage-selfhosted` chart:

```bash theme={null}
helm upgrade --install $release_name $chart_uri/vantage-selfhosted \
  --version 0.70.13 \
  --namespace $install_namespace \
  --create-namespace \
  --values values-self-managed.yaml \
  --wait
```

After the operator creates the workload Services, apply your ingress-controller configuration and verify that the TLS certificate is ready.

## Monitor installation

Wait for the custom resource to report `Ready`:

```bash theme={null}
kubectl -n $install_namespace wait \
  --for=condition=Ready vantages.vantage.abbyy.com/$release_name \
  --timeout=30m
```

Then verify the generated ArgoCD applications and workloads. Do not rely on `Ready` alone:

```bash theme={null}
argocd app list -l vantage.abbyy.com/managed-by=vantage-operator
kubectl -n $install_namespace get pods
kubectl -n $install_namespace get scaledobjects,hpa
```

When OCI migration is enabled, monitor it separately:

```bash theme={null}
kubectl -n $install_namespace wait --for=create job/$release_name-oci-migration --timeout=2m
kubectl -n $install_namespace wait --for=condition=Complete job/$release_name-oci-migration --timeout=20m
```

Skill installation runs in a separate job and can continue after Vantage reports `Ready`:

```bash theme={null}
kubectl -n $install_namespace wait --for=create job/$install_namespace-skill-installer-job
kubectl -n $install_namespace wait --for=condition=Complete job/$install_namespace-skill-installer-job
```

Finally, confirm that:

* Every generated ArgoCD application is `Synced` and `Healthy`.
* Vantage pods are running and mesh-injected.
* Prometheus reports Vantage `/metrics-text` targets as `UP`.
* KEDA `ScaledObject` resources are `Ready` and HPA metric values are not `<unknown>`.
* The OIDC discovery document and browser redirects use `https://` URLs.
* Vantage is available at `https://$your_vantage_hostname`.

## What's next

<CardGroup cols={2}>
  <Card title="Secrets" icon="key" href="/vantage/self-hosted/v3.0/secrets-and-keyvault">
    Kubernetes Secret aliases, auth keypairs, and database connection strings.
  </Card>

  <Card title="Monitoring" icon="chart-line" href="/vantage/self-hosted/v3.0/monitoring/prometheus">
    Configure Prometheus to scrape Vantage through the service mesh.
  </Card>

  <Card title="Troubleshooting" icon="stethoscope" href="/vantage/self-hosted/v3.0/troubleshooting">
    Diagnose operator, database, registry, ingress, and autoscaling failures.
  </Card>

  <Card title="Upgrading" icon="arrow-up" href="/vantage/self-hosted/v3.0/upgrading">
    Upgrade the operator and Vantage charts together.
  </Card>
</CardGroup>
