Skip to main content
Closed beta. Connecting to a service is part of Managed services, which is in closed beta and enabled per organisation on request. Contact support to have it turned on for your organisation.
A managed service answers only inside its own cluster, at fixed addresses in its namespace. It keeps the credentials it generated in a Secret in that namespace, and a workload can read a Secret only in its own namespace. Ankra connects your application for you when it runs on the same cluster as the service: once the service is ready, Ankra copies the connection into the application’s namespace, and the application’s containers read it as environment variables such as DATABASE_URL. The copy happens inside the cluster, and Ankra never sees the values. An application on another cluster is not connected for you: give it the values yourself, as in Connect from another cluster.

How your application receives the connection

Every application environment a service was set up for, on the service’s cluster, receives the service’s connection in two parts:
  1. A Secret named <service>-connection in the application’s namespace, with <service> standing for the service name. Ankra copies its values inside the cluster from the service’s own credentials Secret.
  2. A reference to that Secret, which a deploy of the application adds to every container and init container of its Deployments, StatefulSets and DaemonSets through envFrom, so each of the Secret’s keys becomes an environment variable. The names are listed under Variable names. A deploy adds the reference while the service is still being set up too. The reference is optional, so the application starts while the Secret does not exist yet.
Once the service has generated its credentials, Ankra writes the Secret by itself, without redeploying or restarting anything, but only while no running pod of the application references the Secret: pods restarting one by one would otherwise read different values. What the application needs then depends on its state:
  • The workloads reference the Secret but none of their pods runs, for example because they are scaled to zero: Ankra writes the Secret, and each pod reads the variables when it starts.
  • The workloads do not reference the Secret, because the application was deployed before the service was connected: Ankra writes the Secret, and the application reads it after its next deploy adds the reference.
  • Running pods reference the Secret, for example because the application was deployed while the service was being set up: Ankra leaves the Secret to a deploy. Deploy the application once the service is ready: the deploy writes the Secret and rolls the workloads that reference it together onto it.
  • Running pods read the Secret but started before it existed: they run without its variables until they restart. Ankra never restarts them by itself.
  • A variable the connection would add is defined twice, by the connection and by another source the workloads read, such as one of the application’s environment secrets: the connection is not delivered, by Ankra on its own or by a deploy, until you remove the other definition or choose another service, or none, to provide those names, as under Variable names.
The service’s page shows each environment’s state under Use it in <application>, with the platform’s reason beside it. The label follows pickup, described below, when the platform sent one, and the delivery’s state when it did not: A deploy usually connects the workloads, but not every one: see the note on Jobs, CronJobs and ankra.io/deploy-overrides below. The same state is in the API, on each of consumers in Get a managed service instance, as connection_delivery with the secret_name, the variables the application receives and a reason. Its pickup says how far the environment is from running with the connection, and reason says what to do: pickup is absent when Ankra could not read it, and for a consumer it does not connect, such as one on another cluster. A workload annotated ankra.io/deploy-overrides: "none" keeps the manifest you committed, so it gets no envFrom reference. The <service>-connection Secret is still written to its namespace: reference it from the workload yourself. Jobs and CronJobs are not given the reference either. When a service is deleted, the application’s next deploy removes its <service>-connection Secret and the reference to it. To take one application off a service that keeps running for its other applications, disconnect it. Its next deploy removes the reference and rolls its workloads, and Ankra removes the <service>-connection Secret once no pod reads it.
Do not also set a delivered variable as an environment secret. If the application already has, say, DATABASE_URL as an environment secret, Ankra does not deliver the connection, on its own or in a deploy, and name_collisions names the variable. Delete the copy with ankra application env-secrets delete <application-id> DATABASE_URL and apply the secrets again with ankra application env-secrets apply <application-id>, or choose another service, or none, to provide DATABASE_URL. If a name is set twice after the connection was delivered, reason says how to resolve it.

Variable names

Each service delivers the variables its kind of client conventionally reads: Every service also delivers each variable under its own prefix: the service name in capitals, with hyphens as underscores. A PostgreSQL service named orders-db delivers ORDERS_DB_DATABASE_URL, ORDERS_DB_PGHOST and so on. The names without a prefix go to one service of each kind per application environment: the one connected first, recorded the first time a deploy gives it those names. An application with one database reads DATABASE_URL. When a second PostgreSQL service is added for the same environment, DATABASE_URL keeps pointing at the first, and the second is read through its prefixed names only. Valkey and any other Redis-compatible service count as one kind, as they share REDIS_URL. The names without a prefix never move to another service by themselves. If the service that provides DATABASE_URL is retired while another PostgreSQL service still serves the environment, the application’s next deploy is refused and nothing is deployed: giving DATABASE_URL to the other database would make the application read and write a different database without anyone choosing that. The service’s page shows the same warning on the application. Choose which service provides the names, or choose none so the application reads only the prefixed names, then deploy again:
  • Ankra AI or MCP: set_service_connection_default with the application, cluster, namespace, the kind (postgres, redis, nats, opensearch, s3, victorialogs or victoriametrics) and the service’s instance id, or none: true.
  • API: PUT /api/v1/org/service-admission/connection-defaults with application_id, cluster_id, namespace, protocol and instance_id (null for none).
If no other service of that kind serves the environment, the deploy goes ahead without the names and says so on its result. A service of that kind connected later then provides them. The refusal starts as soon as the deletion of the service that provides the names has begun, not only once it has finished: from then on, while another service of that kind serves the environment, its deploys are refused, so the running application keeps what it read at its last deploy. While no other service of that kind serves it, deploys keep delivering the names from the service being deleted until its credentials are removed, and the deploy that stops delivering them says so. A service set up again under the name of a retired one is a new service, not the old one: it does not hold the retired service’s data. If the retired one provided DATABASE_URL, the deploy is refused in the same way and says so; choose the new service explicitly once you have moved the data. Removing the application’s deployment from the namespace forgets which service Ankra recorded as providing the names, so a new deployment there starts fresh; a service you chose yourself stays chosen.

Find the connection details

Open the service in My services. Its Connect section shows:
  • the namespace, which is the service name;
  • each address, with a Copy button;
  • the name of the Secret that holds the credentials;
  • under Read a credential yourself, for each key in that Secret, an Ankra CLI command that prints its value, with a Copy button. The command names the service’s cluster and also uses jq, as in Read a value.
The portal never shows the values themselves. The details are derived from the service’s package, not observed on the cluster, so they are shown as soon as the service is set up: the addresses answer once the service is running. The section is not shown for a deleted service or while a service is being deleted. The same details are on the service in the API, as connection on Get a managed service instance: the namespace, the named endpoints and the secret with its name and keys. They follow a fixed pattern for each service, below, with <service> standing for the service name.

Addresses and Secrets

The addresses resolve from any namespace on the service’s cluster, and not from outside it. On a cluster with a custom DNS domain, use the shorter <name>.<service>.svc form, for example valkey.<service>.svc:6379. Of the delivered variables, DATABASE_URL, JDBC_DATABASE_URL, PGHOST, S3_ENDPOINT, AWS_ENDPOINT_URL_S3 and OPENAI_BASE_URL, and their prefixed copies, use the full svc.cluster.local form, so on such a cluster they do not resolve: give the application short-form values for them yourself, as in Connect from another cluster, under variable names the delivery does not use. The other delivered addresses, in REDIS_URL, REDIS_HOST, NATS_URL, OPENSEARCH_URL, VICTORIA_LOGS_URL and VICTORIA_METRICS_URL, already use the short form and resolve there. Resolving is not reaching: on their current package versions, PostgreSQL, Valkey, NATS, OpenSearch and SeaweedFS admit their client port only from the service’s own namespace, the namespace of the cluster’s Ankra agent and the namespaces of the applications connected to the service, where the cluster’s network plugin enforces NetworkPolicy. See How a service runs.

Read a value

You need a value only to connect something Ankra does not connect for you. Select the service’s cluster, then read the Secret by name with --reveal, using the Secret and namespace from the table:
Without --reveal, every value comes back as a sha256: digest. --reveal needs the kubernetes.secrets_reveal permission on the cluster, which the operator, admin and owner roles carry, and every reveal is recorded in the organisation’s audit log. Values under data stay base64-encoded. For a PostgreSQL service named orders-db, this prints its password:
A key with a dot in its name, such as OpenSearch’s ca.crt, works the same way:

Connect from another cluster

An application on another cluster than the service is not connected for you, and the service’s addresses do not resolve there. Reaching the service from another cluster needs a network path between the clusters that you provide, and the address that path exposes. A service whose client port admits only the namespaces named under Addresses and Secrets also needs a NetworkPolicy of your own in its namespace that admits the traffic of that path. Give the application the values as environment secrets, from the service page’s Use it in <application> button, which opens the application’s Settings › Secrets, or from the CLI. Piping the value keeps it out of your shell history:
Storing a value does not reach a running workload: env-secrets apply seals the stored values into the application’s deployments and rolls them. The URL keys, such as PostgreSQL’s fqdn-uri, name the in-cluster address, so build the URL your application uses from your own network path’s address rather than copying them. For a workload that is not an Ankra application, keep the Secret in Git and encrypt it with SOPS. A value you copy this way is yours: deleting the service does not remove it from the application. Delete it yourself once the application no longer uses the service.

Notes per service

  • PostgreSQL. DATABASE_URL and JDBC_DATABASE_URL carry the operator’s fqdn-uri and fqdn-jdbc-uri. The operator also writes uri, jdbc-uri and host keys, but they name the short host postgresql-rw, which resolves only inside the service’s own namespace. You connect as app, the owner of the database app, and superuser access is off. The read-only address reaches replicas only, so it answers only when instances is above 1, and no variable names it. The image includes the pgvector and pgaudit extensions.
  • Valkey. Authenticate as the app user, which REDIS_USERNAME carries, with REDIS_PASSWORD; REDIS_URL is a complete redis:// URL that carries both. Write to the primary address. The read-replicas address serves reads from every pod.
  • NATS. Connect as app. NATS_URL carries no credentials, so pass NATS_USER and NATS_PASSWORD separately. JetStream is on; memory-backed streams are disabled.
  • OpenSearch. Use HTTPS with basic auth as admin, the only user. The certificate is signed by a private CA generated in the cluster: have your client trust OPENSEARCH_CA_CERT, which holds that CA’s certificate.
  • SeaweedFS. Use the S3 API over plain HTTP inside the cluster, with path-style addressing. The admin key pair, the one delivered, can read, write, list and administer buckets. The read-only key pair can only read, and is in the service’s Secret only.
  • VictoriaLogs. Send logs over HTTP with basic auth, as JSON lines, Loki push, OpenTelemetry or Elasticsearch bulk, and query them with LogsQL. No log collector is installed, so ship logs with your own agent.
  • VictoriaMetrics. Push metrics with basic auth using Prometheus remote_write, OpenTelemetry, InfluxDB or another supported protocol, and query with PromQL or MetricsQL on the Prometheus HTTP API. It scrapes nothing itself, so push from vmagent, a Prometheus agent or an OpenTelemetry Collector.

OpenAI-compatible inference

A gpu-chat service speaks the OpenAI API, so any OpenAI client library or tool that accepts a base URL works against it unchanged. A connected application receives: Most OpenAI SDKs read OPENAI_BASE_URL and OPENAI_API_KEY from the environment by themselves. From a pod in a connected namespace:
With embeddings set to 1, the same endpoint also answers POST /v1/embeddings with the bge-m3 model. The endpoint is not exposed outside the cluster. api-key is a client key the service creates for its consumers; it cannot mint, change or revoke keys. With chat_ui set to 1 the service also runs the Open WebUI chat UI, reachable from inside the service’s namespace only. See Managed Service Settings for the models each model_tier runs.

Check that the service answers

A finished deployment is not yet a ready service. The service’s Service health section says whether its workload runs as planned, which does not prove a client can connect. Ankra checks that a client can connect for every service it publishes, about every five minutes, and shows the result as the service’s Readiness: see Health and readiness. Until readiness reads Ready, or while it reads Not verified because the cluster’s agent is too old to run the check, check the service yourself before you rely on it. Its pods run in its namespace:
A PostgreSQL service can report its deployment finished 30 to 100 seconds before the database accepts connections. Check the database itself until its Ready condition is True:
About every five minutes, a service’s namespace also holds a short-lived pod: labelled app.kubernetes.io/name=ankra-postgres-connection-test for PostgreSQL, and app.kubernetes.io/name=ankra-service-canary for every other service. That is Ankra’s readiness check, which connects the way an application would; it is deleted when it finishes.

Next steps

Managed service settings

What each setting changes, with its range and default.

Managed services

How the services run, their health and readiness, and their current limits.

Disconnect an application

Take one application off a service that keeps running for the others.

Delete a managed service

What deleting removes and keeps, and how to confirm it.