diff --git a/content/operate/iris/langcache/_index.md b/content/operate/iris/langcache/_index.md index 4f84438dc6..14c56ea073 100644 --- a/content/operate/iris/langcache/_index.md +++ b/content/operate/iris/langcache/_index.md @@ -19,6 +19,8 @@ LangCache is a semantic caching service available as a REST API that stores LLM For more information about how LangCache works, see the [LangCache overview]({{< relref "/develop/ai/context-engine/langcache" >}}). +To deploy LangCache on your own Kubernetes infrastructure instead of Redis Cloud, see [self-managed LangCache]({{< relref "/operate/iris/langcache/self-managed" >}}). + ## LLM cost reduction with LangCache {{< embed-md "langcache-cost-reduction.md" >}} diff --git a/content/operate/iris/langcache/self-managed/_index.md b/content/operate/iris/langcache/self-managed/_index.md new file mode 100644 index 0000000000..4538a3e816 --- /dev/null +++ b/content/operate/iris/langcache/self-managed/_index.md @@ -0,0 +1,84 @@ +--- +Title: Self-managed LangCache +alwaysopen: false +categories: +- docs +- operate +- iris +description: Deploy, configure, secure, and operate LangCache on a self-managed Kubernetes cluster. +linkTitle: Self-managed +weight: 40 +hideListLinks: true +--- + +LangCache is a semantic caching service that stores LLM responses for faster, +cheaper retrieval. Applications send prompts to LangCache, which either returns a +cached response for a semantically similar prior prompt or calls out to your +embedding provider and stores a new entry when there is no match. + +This guide covers deployment, configuration, security, and operations for +self-managed LangCache. + +The [LangCache API]({{< relref "/develop/ai/context-engine/langcache/api-reference" >}}) +is the shared Data Plane API for Redis Cloud and self-managed deployments. The +[Control Plane API reference]({{< relref "/operate/iris/langcache/self-managed/control-plane-api-reference" >}}) +documents the self-managed admin endpoints for caches. + +{{< note >}} +Self-managed LangCache is available as a private preview. You need a license +key to deploy it. Contact your Redis representative or +[contact sales](https://redis.io/contact/). +{{< /note >}} + +## What you are deploying + +One `helm install` of the `langcache` chart always creates the Data Plane and +the Control Plane, plus either a bundled or an external Identity Service. +There is no lighter-weight install of only the Data Plane for self-managed +LangCache. Every cache is created and managed through the Control Plane, and +every Data Plane request is authenticated by the Identity Service. + +| Component | Purpose | Default service | +| --- | --- | --- | +| LangCache Data Plane | Cache-scoped runtime API for set, search, and flush. | `langcache:9000` | +| LangCache Control Plane | Admin API for creating and managing caches. | `langcache-controlplane:9100` | +| Identity Service | Issues and validates the agent keys the Data Plane requires. Bundled by the chart (default) or an external instance your suite already runs. | `langcache-identity-service:9200` (bundled mode) | +| Cache Redis | Holds cache entries and RediSearch vector indexes. Registered by ID in the Control Plane's database registry — the Data Plane has no database registry of its own. | Customer-provided | +| Metadata Redis | Holds Control Plane cache records. Can be the same Redis instance as Cache Redis, in a separate keyspace. | Customer-provided | + +### How the components work together + +1. Platform admins use the Control Plane to create and manage caches, + selecting a Cache Redis target by `databaseId` from the Control Plane's + own database registry. +1. The Control Plane writes cache records to Metadata Redis, including the + resolved Redis URLs for that cache, and synchronously provisions the + RediSearch vector index in Cache Redis. +1. Platform admins mint agent keys through the Identity Service, granting + `lc-cache:` permissions. +1. Agents and applications call the Data Plane with a cache ID and an agent + key. +1. The Data Plane introspects the key against the Identity Service, reads + the cache's metadata (including its Redis URLs) from Metadata Redis, and + reads or writes entries in Cache Redis. + +### API surfaces + +All Data Plane APIs are scoped to a cache. A cache is the logical isolation +boundary for cached entries. + +| API surface | Endpoint prefix | Purpose | +| --- | --- | --- | +| Cache entries | `/v1/caches/{cacheId}/entries` | Set, search, and delete cached entries. | +| Cache flush | `/v1/caches/{cacheId}/flush` | Flush all entries in a cache. | +| Cache health | `/v1/caches/{cacheId}/health` | Cache-scoped health status. | +| Control Plane | `/v1/caches`, `/v1/embedding-providers` | Self-managed administration for caches. | +| Identity Service | `/v1/api-keys` | Mint, list, update, revoke, and rotate agent keys and their cache grants. | + +The [LangCache API]({{< relref "/develop/ai/context-engine/langcache/api-reference" >}}) +reference does not yet document cache health; for that, use +[API examples]({{< relref "/operate/iris/langcache/self-managed/api-examples" >}}) +until the shared schema is updated. + +Start with [prerequisites]({{< relref "/operate/iris/langcache/self-managed/prerequisites" >}}), +then follow [Deploy self-managed LangCache]({{< relref "/operate/iris/langcache/self-managed/deploy" >}}). diff --git a/content/operate/iris/langcache/self-managed/api-examples.md b/content/operate/iris/langcache/self-managed/api-examples.md new file mode 100644 index 0000000000..7989444cfa --- /dev/null +++ b/content/operate/iris/langcache/self-managed/api-examples.md @@ -0,0 +1,226 @@ +--- +Title: Self-managed API examples +alwaysopen: false +categories: +- docs +- operate +- iris +description: Use curl examples with the LangCache self-managed Control Plane, Identity Service, and Data Plane APIs. +linkTitle: Self-managed API examples +weight: 50 +hideListLinks: true +--- + +These examples show self-managed Control Plane, Identity Service, and Data +Plane requests. They assume agent-key authentication as described in +[Authentication and authorization]({{< relref "/operate/iris/langcache/self-managed/authentication" >}}). + +For the complete shared Data Plane schema, see the +[LangCache API]({{< relref "/develop/ai/context-engine/langcache/api-reference" >}}). +For the self-managed admin schema, see the +[Control Plane API reference]({{< relref "/operate/iris/langcache/self-managed/control-plane-api-reference" >}}). + +## Control Plane API examples + +Set variables: + +```bash +CP_URL="http://localhost:9100" +LC_ADMIN_TOKEN="" +``` + +List caches: + +```bash +curl -sS "$CP_URL/v1/caches" \ + -H "Authorization: Bearer $LC_ADMIN_TOKEN" +``` + +Create a cache: + +```bash +curl -sS -X POST "$CP_URL/v1/caches" \ + -H "Authorization: Bearer $LC_ADMIN_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "my-cache", + "databaseId": "cache-primary", + "defaultSearchThreshold": 0.9, + "defaultTtlMillis": -1, + "attributes": [] + }' +``` + +Response: + +```json +{ + "cacheId": "0123456789abcdef0123456789abcdef" +} +``` + +`databaseId` must match an entry in the Control Plane's configured +`databases` registry. `defaultSearchThreshold` is a float between 0 and 1. +`defaultTtlMillis` accepts `-1` or `0` for no expiration, or a positive +number of milliseconds. + +Get a cache: + +```bash +curl -sS "$CP_URL/v1/caches/" \ + -H "Authorization: Bearer $LC_ADMIN_TOKEN" +``` + +Response fields include `status` (`PROVISIONING`, `READY`, or +`UNAVAILABLE`), the deployment's `embeddingProvider`/`embeddingModel`/ +`embeddingDimensions`, and the resolved `databaseName`. + +Update a cache: + +```bash +curl -sS -X PATCH "$CP_URL/v1/caches/" \ + -H "Authorization: Bearer $LC_ADMIN_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "defaultSearchThreshold": 0.85 + }' +``` + +Flush a cache's entries without deleting the cache: + +```bash +curl -sS -X DELETE "$CP_URL/v1/caches//entries" \ + -H "Authorization: Bearer $LC_ADMIN_TOKEN" +``` + +Delete a cache: + +```bash +curl -sS -X DELETE "$CP_URL/v1/caches/?flush=true" \ + -H "Authorization: Bearer $LC_ADMIN_TOKEN" +``` + +List the deployment's configured embedding providers and models: + +```bash +curl -sS "$CP_URL/v1/embedding-providers" \ + -H "Authorization: Bearer $LC_ADMIN_TOKEN" +``` + +## Identity Service API examples + +Set variables: + +```bash +IDS_URL="http://localhost:9200" +IDS_CONTROL_TOKEN="" +``` + +Mint an agent key scoped to one cache: + +```bash +curl -sS -X POST "$IDS_URL/v1/api-keys" \ + -H "Authorization: Bearer $IDS_CONTROL_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "my-agent-key", + "grants": [ + { + "product": "langcache", + "resourceType": "lc-cache", + "resourceId": "", + "actions": ["read", "write"] + } + ] + }' +``` + +Response: + +```json +{ + "keyId": "0123456789abcdef0123456789abcdef", + "token": "", + "createdAt": 1780000000 +} +``` + +Rotate it later: + +```bash +curl -sS -X POST "$IDS_URL/v1/api-keys//rotate" \ + -H "Authorization: Bearer $IDS_CONTROL_TOKEN" +``` + +## Data Plane API examples + +Set variables: + +```bash +DP_URL="http://localhost:9000" +CACHE_ID="" +LC_AGENT_KEY="" +``` + +### Set a cache entry + +```bash +curl -sS -X POST "$DP_URL/v1/caches/$CACHE_ID/entries" \ + -H "Authorization: Bearer $LC_AGENT_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "prompt": "What is the capital of France?", + "response": "The capital of France is Paris." + }' +``` + +### Search for a cached response + +```bash +curl -sS -X POST "$DP_URL/v1/caches/$CACHE_ID/entries/search" \ + -H "Authorization: Bearer $LC_AGENT_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "prompt": "What'"'"'s the capital city of France?" + }' +``` + +### Delete a specific entry + +```bash +curl -sS -X DELETE "$DP_URL/v1/caches/$CACHE_ID/entries/" \ + -H "Authorization: Bearer $LC_AGENT_KEY" +``` + +### Delete entries matching attributes + +```bash +curl -sS -X DELETE "$DP_URL/v1/caches/$CACHE_ID/entries" \ + -H "Authorization: Bearer $LC_AGENT_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "attributes": { + "topic": "geography" + } + }' +``` + +### Flush all entries in a cache + +```bash +curl -sS -X POST "$DP_URL/v1/caches/$CACHE_ID/flush" \ + -H "Authorization: Bearer $LC_AGENT_KEY" +``` + +### Check cache health + +```bash +curl -sS "$DP_URL/v1/caches/$CACHE_ID/health" \ + -H "Authorization: Bearer $LC_AGENT_KEY" +``` + +For the full request and response schema for cache entries (set, search, +delete, flush), see the +[LangCache API reference]({{< relref "/develop/ai/context-engine/langcache/api-reference" >}}). +That shared reference does not yet cover cache health; the example above +reflects the same Data Plane API. diff --git a/content/operate/iris/langcache/self-managed/authentication.md b/content/operate/iris/langcache/self-managed/authentication.md new file mode 100644 index 0000000000..c5063f1f78 --- /dev/null +++ b/content/operate/iris/langcache/self-managed/authentication.md @@ -0,0 +1,219 @@ +--- +Title: Authentication and authorization +alwaysopen: false +categories: +- docs +- operate +- iris +description: Configure LangCache self-managed Control Plane authentication and Data Plane agent-key authentication through the Identity Service. +linkTitle: Authentication and authorization +weight: 40 +hideListLinks: true +--- + +Self-managed LangCache uses three separate credentials: + +- an **admin token** for the Control Plane's cache-management API; +- an **internal token** the Identity Service uses to validate that a + cache-grant reference is real, by calling back into the Control Plane; +- **agent keys**, issued by the Identity Service, that applications use to + call the Data Plane. + +The Data Plane always authenticates by introspecting agent keys against an +Identity Service. There is no auth-disabled or static-token mode for +self-managed LangCache. + +## Control Plane admin token + +Control Plane management endpoints require: + +```http +Authorization: Bearer +``` + +By default, `controlplane.adminToken.autoGenerate: true` mints this token +into a chart-managed Secret on first install (stable across upgrades). +Retrieve it: + +```bash +kubectl -n get secret langcache-controlplane-admin-token \ + -o jsonpath="{.data.token}" | base64 -d +``` + +To bring your own token instead: + +```bash +kubectl -n create secret generic langcache-controlplane-admin-token \ + --from-literal=token='' +``` + +```yaml +controlplane: + adminToken: + existingSecret: langcache-controlplane-admin-token + autoGenerate: false +``` + +## Control Plane internal token + +The internal token authenticates calls to the Control Plane's internal +grant-validation endpoint (`/internal/v1/grants/validate`). The Identity +Service calls this endpoint to confirm that a grant naming a LangCache cache +resource is valid before it lets an agent key carry that grant. + +Like the admin token, it defaults to `controlplane.internalToken.autoGenerate: true` +and is retrievable the same way: + +```bash +kubectl -n get secret langcache-controlplane-internal-token \ + -o jsonpath="{.data.token}" | base64 -d +``` + +In bundled Identity Service mode, the chart wires this token to the +Identity Service's `product_validation.langcache.credential` automatically. +In external mode, you must give this token to the Identity Service's owner +(see [External Identity Service](#external-identity-service)). + +The admin token and internal token must always be different values; the +Control Plane rejects a configuration where admin token and internal token match. + +## Identity Service modes + +You must choose either Bundled Identity Service or External Identity Service at install time. + +### Bundled Identity Service + +`identityService.mode: bundled` renders the Identity Service +Deployment and Service, auto-generates its control token and the Data +Plane's own runtime introspection credential, and wires everything together +automatically: + +```yaml +identityService: + mode: bundled + bundled: + image: + repository: redislabs/iris-identity-service + tag: "" + metadata: + existingSecret: ids-metadata +``` + +Retrieve the auto-generated Identity Service Control admin token (used for +`/v1/api-keys` calls, not the Data Plane's own runtime credential): + +```bash +kubectl -n get secret langcache-identity-service-control-token \ + -o jsonpath="{.data.token}" | base64 -d +``` + +The chart also auto-generates a separate credential the Data Plane itself +uses to call the Identity Service's introspection endpoint (scoped to +`api-key-introspect` on product `langcache` only): + +```bash +kubectl -n get secret langcache-identity-service-dp-credential \ + -o jsonpath="{.data.token}" | base64 -d +``` + +### External Identity Service + +`identityService.mode: external` renders no Identity Service workload at +all — use this when your suite already runs one, for example alongside +self-managed Redis Agent Memory: + +```yaml +identityService: + mode: external + external: + baseURL: https://suite-identity-service.example.com + credential: + existingSecret: langcache-dp-ids-credential + secretKey: token +``` + +The `langcache-dp-ids-credential` is minted out of band by the suite-level +Identity Service owner, scoped to `api-key-introspect` on product +`langcache`. You must also ask that owner to configure the external +Identity Service's own `product_validation.langcache` against this +release's Control Plane internal Service +(`langcache-controlplane:9100`) and this release's `controlplane.internalToken` +Secret — this chart has no way to reach into an Identity Service it doesn't +own. + +## Minting and managing agent keys + +Mint, list, update, revoke, and rotate agent keys directly against the +Identity Service (not the LangCache Control Plane): + +```bash +IDS_URL="http://localhost:9200" +IDS_CONTROL_TOKEN="" + +curl -sS -X POST "$IDS_URL/v1/api-keys" \ + -H "Authorization: Bearer $IDS_CONTROL_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "my-agent-key", + "grants": [ + { + "product": "langcache", + "resourceType": "lc-cache", + "resourceId": "", + "actions": ["read", "write"] + } + ] + }' +``` + +The response contains the new credential. Store it immediately; credentials +are returned only when a key is minted or rotated. + +Grant actions: + +| Action | Meaning | +| --- | --- | +| `read` | Read and search cache entries. | +| `write` | Mutate cache entries. `write` implies `read`. | +| `full` | Full cache access through the grant. `full` implies `write`. This is a resource permission, not a substitute for the Control Plane admin token; it doesn't grant access to Control Plane administration APIs. | + +Clients send agent keys as Bearer credentials to the Data Plane: + +```http +Authorization: Bearer +``` + +Treat agent keys as opaque credentials. Do not parse their contents. + +## Cache authorization + +For agent-key requests, the Data Plane checks both identity and resource +authorization through the Identity Service: + +1. The key exists and its secret validates. +2. The key has a grant for the requested cache resource, keyed as + `lc-cache:`. +3. The grant includes the permission required by the operation. + +## Gateway and identity provider integration + +Use a gateway when it owns external authentication and coarse policy. For +example, a gateway can authenticate callers through an identity provider +before it forwards requests to LangCache. + +Gateway rules: + +- The gateway owns external authentication and perimeter policy. +- LangCache owns cache-level authorization through the Identity Service. +- LangCache agent keys are stored and forwarded by trusted infrastructure or + trusted applications. +- Callers must not be able to bypass the gateway and reach the Data Plane + directly unless they also present a valid LangCache agent key. + +## Next steps + +With an admin token, internal token, and agent key in hand, see +[API examples]({{< relref "/operate/iris/langcache/self-managed/api-examples" >}}) +to create a cache and start calling the Data Plane, or +[Operations]({{< relref "/operate/iris/langcache/self-managed/operations" >}}) +to rotate these credentials going forward. diff --git a/content/operate/iris/langcache/self-managed/configuration.md b/content/operate/iris/langcache/self-managed/configuration.md new file mode 100644 index 0000000000..1e7309911d --- /dev/null +++ b/content/operate/iris/langcache/self-managed/configuration.md @@ -0,0 +1,155 @@ +--- +Title: Configuration +alwaysopen: false +categories: +- docs +- operate +- iris +description: Configure the LangCache Data Plane, Control Plane, and Identity Service through Helm values and config overlay Secrets. +linkTitle: Configuration +weight: 20 +hideListLinks: true +--- + +The `langcache` chart splits configuration into two layers for the Data +Plane, the Control Plane, and (in bundled mode) the Identity Service: + +- **Non-secret structure**, set as Helm values (`dataplane.configData`, + `controlplane.configData`, `identityService.bundled.configData`) and + rendered into a ConfigMap by default. +- **Redis URLs, the database registry, and the embedding credential**, + which never go in `values.yaml` or a rendered ConfigMap. Each component + reads its own pre-created overlay Secret, deep-merged over its rendered + base config at container startup. The chart passes each overlay as an + additional `--config` flag, so later files win. + +You always create the overlay Secrets yourself; the chart only tells each +component where to mount and read them. + +## Data Plane overlay + +Create `dp-overlay.yaml`. Provide Metadata Redis and, when +`dataplane.embedding.credentials.type: static`, the embedding credential. +The Data Plane has no database registry of its own — it resolves each +cache's Cache Redis target from the `databaseUrls` the Control Plane already +persisted in Metadata Redis at cache-creation time. + +```yaml +metadata: + urls: + - rediss://default:@metadata-redis:6380 + +embedding: + credentials: + api_key: "" +``` + +```bash +kubectl -n create secret generic dp-overlay \ + --from-file=overlay.yaml=./dp-overlay.yaml +``` + +Point the chart at it, alongside the public (non-secret) embedding facts: + +```yaml +dataplane: + secrets: + secretName: dp-overlay + embedding: + provider: openai + endpoint: + baseURL: https://api.openai.com/v1 + credentials: + type: static + models: + defaultEmbeddingModel: text-embedding-3-small + dimensions: 1536 +``` + +## Control Plane overlay + +Create `cp-overlay.yaml`. Provide the same Metadata Redis as the Data Plane, +plus the `databases` registry — one entry per Cache Redis target, keyed by a +logical ID you choose. The Control Plane never receives an embedding +credential; it only needs the public provider/model/dimensions contract +that the chart renders from `dataplane.embedding.*`. + +```yaml +metadata: + urls: + - rediss://default:@metadata-redis:6380 + +databases: + cache-primary: + name: cache-primary + urls: + - rediss://default:@cache-primary:6380 +``` + +```bash +kubectl -n create secret generic cp-overlay \ + --from-file=overlay.yaml=./cp-overlay.yaml +``` + +```yaml +controlplane: + secrets: + secretName: cp-overlay + configData: + profile: prod +``` + +The `databases` map must use the same logical IDs your operators will pass +as `databaseId` when creating caches through the Control Plane API. The +chart derives the Control Plane's `embedders` config from +`dataplane.embedding.provider` and `dataplane.embedding.models.*`. On-prem +cache creation uses that single provider/model/dimensions contract and +does not accept per-cache embedding credentials. + +## Identity Service metadata (bundled mode only) + +When `identityService.mode: bundled` is set, the bundled Identity +Service needs its own Metadata Redis connection. This connection can be the same Redis +instance as the Control Plane's Metadata Redis, in a separate namespace. + +```yaml +metadata: + urls: + - rediss://default:@metadata-redis:6380 +``` + +```bash +kubectl -n create secret generic ids-metadata \ + --from-file=metadata.yaml=./ids-metadata.yaml +``` + +```yaml +identityService: + mode: bundled + bundled: + metadata: + existingSecret: ids-metadata +``` + +If you use `identityService.mode: external` instead, there is no Identity +Service overlay to create here; see +[Authentication and authorization]({{< relref "/operate/iris/langcache/self-managed/authentication" >}}). + +## Multiple overlay Secrets + +`dataplane.secrets.additionalSecrets` and +`controlplane.secrets.additionalSecrets` accept a list of extra pre-created +Secret names, layered in order after the primary overlay (later wins). Use +this to split, for example, Redis connection details from the embedding +credential across separately rotated Secrets. + +## Treat overlay content as sensitive + +Store `dp-overlay.yaml`, `cp-overlay.yaml`, and `ids-metadata.yaml` outside +your values files and outside git, the same as any other credential +material. + +## Next steps + +With your overlay Secrets and values ready, continue to +[Deploy self-managed LangCache]({{< relref "/operate/iris/langcache/self-managed/deploy" >}}). diff --git a/content/operate/iris/langcache/self-managed/control-plane-api-reference.md b/content/operate/iris/langcache/self-managed/control-plane-api-reference.md new file mode 100644 index 0000000000..df398de63e --- /dev/null +++ b/content/operate/iris/langcache/self-managed/control-plane-api-reference.md @@ -0,0 +1,16 @@ +--- +Title: LangCache Control Plane API reference +linkTitle: Control Plane API reference +layout: apireference +type: page +weight: 80 +params: + sourcefile: ./openapi-control-plane.json + sortOperationsAlphabetically: false +--- + +All Control Plane API requests require the admin bearer token: + +```http +Authorization: Bearer +``` diff --git a/content/operate/iris/langcache/self-managed/control-plane-api-reference/openapi-control-plane.json b/content/operate/iris/langcache/self-managed/control-plane-api-reference/openapi-control-plane.json new file mode 100644 index 0000000000..7b65833bf4 --- /dev/null +++ b/content/operate/iris/langcache/self-managed/control-plane-api-reference/openapi-control-plane.json @@ -0,0 +1,1187 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "LangCacheControlPlaneService", + "version": "1.0.0", + "description": "Administrative API for the on-prem Redis LangCache control plane." + }, + "paths": { + "/v1/caches": { + "get": { + "operationId": "ListCaches", + "responses": { + "200": { + "description": "ListCaches 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListCachesResponseContent" + } + } + } + }, + "401": { + "description": "AuthenticationError 401 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationErrorResponseContent" + } + } + } + }, + "403": { + "description": "ForbiddenError 403 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForbiddenErrorResponseContent" + } + } + } + }, + "500": { + "description": "UnexpectedError 500 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnexpectedErrorResponseContent" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError 503 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent" + } + } + } + } + } + }, + "post": { + "operationId": "CreateCache", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCacheRequestContent" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "CreateCache 201 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCacheResponseContent" + } + } + } + }, + "400": { + "description": "BadRequestError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestErrorResponseContent" + } + } + } + }, + "401": { + "description": "AuthenticationError 401 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationErrorResponseContent" + } + } + } + }, + "403": { + "description": "ForbiddenError 403 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForbiddenErrorResponseContent" + } + } + } + }, + "424": { + "description": "FailedDependencyError 424 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FailedDependencyErrorResponseContent" + } + } + } + }, + "500": { + "description": "UnexpectedError 500 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnexpectedErrorResponseContent" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError 503 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent" + } + } + } + } + } + } + }, + "/v1/caches/{cacheId}": { + "delete": { + "operationId": "DeleteCache", + "parameters": [ + { + "name": "cacheId", + "in": "path", + "schema": { + "type": "string", + "maxLength": 32, + "minLength": 32, + "pattern": "^[0-9a-f]{32}$" + }, + "required": true + }, + { + "name": "flush", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "DeleteCache 200 response" + }, + "400": { + "description": "BadRequestError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestErrorResponseContent" + } + } + } + }, + "401": { + "description": "AuthenticationError 401 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationErrorResponseContent" + } + } + } + }, + "404": { + "description": "NotFoundError 404 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundErrorResponseContent" + } + } + } + }, + "500": { + "description": "UnexpectedError 500 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnexpectedErrorResponseContent" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError 503 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent" + } + } + } + } + } + }, + "get": { + "operationId": "GetCache", + "parameters": [ + { + "name": "cacheId", + "in": "path", + "schema": { + "type": "string", + "maxLength": 32, + "minLength": 32, + "pattern": "^[0-9a-f]{32}$" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "GetCache 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetCacheResponseContent" + } + } + } + }, + "401": { + "description": "AuthenticationError 401 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationErrorResponseContent" + } + } + } + }, + "403": { + "description": "ForbiddenError 403 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForbiddenErrorResponseContent" + } + } + } + }, + "404": { + "description": "NotFoundError 404 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundErrorResponseContent" + } + } + } + }, + "500": { + "description": "UnexpectedError 500 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnexpectedErrorResponseContent" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError 503 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent" + } + } + } + } + } + }, + "patch": { + "operationId": "UpdateCache", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CachePatch" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "cacheId", + "in": "path", + "schema": { + "type": "string", + "maxLength": 32, + "minLength": 32, + "pattern": "^[0-9a-f]{32}$" + }, + "required": true + } + ], + "responses": { + "201": { + "description": "UpdateCache 201 response" + }, + "400": { + "description": "BadRequestError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestErrorResponseContent" + } + } + } + }, + "401": { + "description": "AuthenticationError 401 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationErrorResponseContent" + } + } + } + }, + "404": { + "description": "NotFoundError 404 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundErrorResponseContent" + } + } + } + }, + "500": { + "description": "UnexpectedError 500 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnexpectedErrorResponseContent" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError 503 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent" + } + } + } + } + } + } + }, + "/v1/caches/{cacheId}/entries": { + "delete": { + "operationId": "FlushCache", + "parameters": [ + { + "name": "cacheId", + "in": "path", + "schema": { + "type": "string", + "maxLength": 32, + "minLength": 32, + "pattern": "^[0-9a-f]{32}$" + }, + "required": true + } + ], + "responses": { + "204": { + "description": "FlushCache 204 response" + }, + "400": { + "description": "BadRequestError 400 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestErrorResponseContent" + } + } + } + }, + "401": { + "description": "AuthenticationError 401 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationErrorResponseContent" + } + } + } + }, + "404": { + "description": "NotFoundError 404 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundErrorResponseContent" + } + } + } + }, + "424": { + "description": "FailedDependencyError 424 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FailedDependencyErrorResponseContent" + } + } + } + }, + "500": { + "description": "UnexpectedError 500 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnexpectedErrorResponseContent" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError 503 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent" + } + } + } + } + } + } + }, + "/v1/embedding-providers": { + "get": { + "operationId": "ListEmbeddingProviders", + "responses": { + "200": { + "description": "ListEmbeddingProviders 200 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListEmbeddingProvidersResponseContent" + } + } + } + }, + "401": { + "description": "AuthenticationError 401 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationErrorResponseContent" + } + } + } + }, + "500": { + "description": "UnexpectedError 500 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnexpectedErrorResponseContent" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError 503 response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableErrorResponseContent" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "AuthenticationErrorResponseContent": { + "type": "object", + "description": "Authentication credentials are missing, malformed, or invalid.", + "properties": { + "title": { + "type": "string", + "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)." + }, + "status": { + "type": "integer", + "default": 401, + "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.", + "format": "int32" + }, + "detail": { + "type": "string", + "description": "A human-readable explanation specific to this occurrence of the problem." + }, + "instance": { + "type": "string", + "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced." + }, + "type": { + "$ref": "#/components/schemas/AuthenticationErrorType" + } + }, + "required": [ + "status", + "title", + "type" + ] + }, + "AuthenticationErrorType": { + "type": "string", + "description": "Problem type URI for authentication errors.", + "enum": [ + "/errors/authentication-failed" + ] + }, + "BadRequestErrorResponseContent": { + "type": "object", + "description": "Request validation or input decoding failed.", + "properties": { + "title": { + "type": "string", + "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)." + }, + "status": { + "type": "integer", + "default": 400, + "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.", + "format": "int32" + }, + "detail": { + "type": "string", + "description": "A human-readable explanation specific to this occurrence of the problem." + }, + "instance": { + "type": "string", + "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced." + }, + "type": { + "$ref": "#/components/schemas/BadRequestErrorType" + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldError" + }, + "description": "Optional field-level validation errors." + } + }, + "required": [ + "status", + "title", + "type" + ] + }, + "BadRequestErrorType": { + "type": "string", + "description": "Problem type URI for bad request errors.", + "enum": [ + "/errors/invalid-data" + ] + }, + "CacheFailure": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "occurredAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "message", + "occurredAt" + ] + }, + "CacheOutput": { + "type": "object", + "properties": { + "cacheId": { + "type": "string", + "maxLength": 32, + "minLength": 32, + "pattern": "^[0-9a-f]{32}$" + }, + "name": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "databaseId": { + "type": "string", + "maxLength": 32, + "minLength": 1, + "pattern": "^[A-Za-z0-9-]+$" + }, + "databaseName": { + "type": "string" + }, + "defaultSearchThreshold": { + "type": "number", + "maximum": 1, + "minimum": 0, + "format": "float" + }, + "defaultTtlMillis": { + "type": "integer", + "minimum": -1, + "format": "int64" + }, + "attributes": { + "type": "array", + "items": { + "type": "string", + "maxLength": 32, + "minLength": 1, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "maxItems": 5 + }, + "searchStrategies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchStrategy" + } + }, + "embeddingProvider": { + "type": "string" + }, + "embeddingModel": { + "type": "string" + }, + "embeddingDimensions": { + "type": "integer", + "format": "int32" + }, + "status": { + "$ref": "#/components/schemas/CacheStatus" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "failure": { + "$ref": "#/components/schemas/CacheFailure" + } + }, + "required": [ + "attributes", + "cacheId", + "createdAt", + "databaseId", + "databaseName", + "defaultSearchThreshold", + "defaultTtlMillis", + "embeddingDimensions", + "embeddingModel", + "embeddingProvider", + "name", + "searchStrategies", + "status" + ] + }, + "CachePatch": { + "type": "object", + "properties": { + "defaultSearchThreshold": { + "type": "number", + "maximum": 1, + "minimum": 0, + "format": "float" + }, + "defaultTtlMillis": { + "type": "integer", + "minimum": -1, + "format": "int64" + }, + "searchStrategies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchStrategy" + }, + "maxItems": 2, + "minItems": 1, + "uniqueItems": true + } + } + }, + "CacheStatus": { + "type": "string", + "enum": [ + "PROVISIONING", + "READY", + "UNAVAILABLE" + ] + }, + "CreateCacheRequestContent": { + "type": "object", + "properties": { + "name": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "databaseId": { + "type": "string", + "maxLength": 32, + "minLength": 1, + "pattern": "^[A-Za-z0-9-]+$" + }, + "defaultSearchThreshold": { + "type": "number", + "maximum": 1, + "minimum": 0, + "format": "float" + }, + "defaultTtlMillis": { + "type": "integer", + "minimum": -1, + "format": "int64" + }, + "attributes": { + "type": "array", + "items": { + "type": "string", + "maxLength": 32, + "minLength": 1, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "maxItems": 5 + }, + "searchStrategies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchStrategy" + } + } + }, + "required": [ + "attributes", + "databaseId", + "defaultSearchThreshold", + "defaultTtlMillis", + "name" + ] + }, + "CreateCacheResponseContent": { + "type": "object", + "properties": { + "cacheId": { + "type": "string", + "maxLength": 32, + "minLength": 32, + "pattern": "^[0-9a-f]{32}$" + } + }, + "required": [ + "cacheId" + ] + }, + "EmbeddingModel": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "dimensions": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "dimensions", + "name" + ] + }, + "EmbeddingProvider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "models": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmbeddingModel" + } + } + }, + "required": [ + "models", + "name" + ] + }, + "FailedDependencyErrorResponseContent": { + "type": "object", + "description": "A dependent resource required to process the request is unavailable or unhealthy.", + "properties": { + "title": { + "type": "string", + "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)." + }, + "status": { + "type": "integer", + "default": 424, + "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.", + "format": "int32" + }, + "detail": { + "type": "string", + "description": "A human-readable explanation specific to this occurrence of the problem." + }, + "instance": { + "type": "string", + "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced." + }, + "type": { + "$ref": "#/components/schemas/FailedDependencyErrorType" + } + }, + "required": [ + "status", + "title", + "type" + ] + }, + "FailedDependencyErrorType": { + "type": "string", + "description": "Problem type URI for failed-dependency errors.", + "enum": [ + "/errors/resource-unavailable", + "/errors/database-out-of-memory" + ] + }, + "FieldError": { + "type": "object", + "description": "Validation error details for a single request field.", + "properties": { + "field": { + "type": "string", + "description": "Name of the invalid request field." + }, + "rule": { + "type": "string", + "description": "Validation rule that was violated." + }, + "message": { + "type": "string", + "description": "Human-readable validation error message." + } + }, + "required": [ + "field", + "message", + "rule" + ] + }, + "ForbiddenErrorResponseContent": { + "type": "object", + "description": "The caller is authenticated but not allowed to access the requested resource.", + "properties": { + "title": { + "type": "string", + "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)." + }, + "status": { + "type": "integer", + "default": 403, + "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.", + "format": "int32" + }, + "detail": { + "type": "string", + "description": "A human-readable explanation specific to this occurrence of the problem." + }, + "instance": { + "type": "string", + "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced." + }, + "type": { + "$ref": "#/components/schemas/ForbiddenErrorType" + } + }, + "required": [ + "status", + "title", + "type" + ] + }, + "ForbiddenErrorType": { + "type": "string", + "description": "Problem type URI for authorization errors.", + "enum": [ + "/errors/insufficient-permissions" + ] + }, + "GetCacheResponseContent": { + "type": "object", + "properties": { + "cacheId": { + "type": "string", + "maxLength": 32, + "minLength": 32, + "pattern": "^[0-9a-f]{32}$" + }, + "name": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "databaseId": { + "type": "string", + "maxLength": 32, + "minLength": 1, + "pattern": "^[A-Za-z0-9-]+$" + }, + "databaseName": { + "type": "string" + }, + "defaultSearchThreshold": { + "type": "number", + "maximum": 1, + "minimum": 0, + "format": "float" + }, + "defaultTtlMillis": { + "type": "integer", + "minimum": -1, + "format": "int64" + }, + "attributes": { + "type": "array", + "items": { + "type": "string", + "maxLength": 32, + "minLength": 1, + "pattern": "^[A-Za-z0-9_-]+$" + }, + "maxItems": 5 + }, + "searchStrategies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchStrategy" + } + }, + "embeddingProvider": { + "type": "string" + }, + "embeddingModel": { + "type": "string" + }, + "embeddingDimensions": { + "type": "integer", + "format": "int32" + }, + "status": { + "$ref": "#/components/schemas/CacheStatus" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "failure": { + "$ref": "#/components/schemas/CacheFailure" + } + }, + "required": [ + "attributes", + "cacheId", + "createdAt", + "databaseId", + "databaseName", + "defaultSearchThreshold", + "defaultTtlMillis", + "embeddingDimensions", + "embeddingModel", + "embeddingProvider", + "name", + "searchStrategies", + "status" + ] + }, + "ListCachesResponseContent": { + "type": "object", + "properties": { + "caches": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CacheOutput" + } + } + }, + "required": [ + "caches" + ] + }, + "ListEmbeddingProvidersResponseContent": { + "type": "object", + "properties": { + "embeddingProviders": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmbeddingProvider" + } + } + }, + "required": [ + "embeddingProviders" + ] + }, + "NotFoundErrorResponseContent": { + "type": "object", + "description": "The requested resource does not exist.", + "properties": { + "title": { + "type": "string", + "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)." + }, + "status": { + "type": "integer", + "default": 404, + "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.", + "format": "int32" + }, + "detail": { + "type": "string", + "description": "A human-readable explanation specific to this occurrence of the problem." + }, + "instance": { + "type": "string", + "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced." + }, + "type": { + "$ref": "#/components/schemas/NotFoundErrorType" + } + }, + "required": [ + "status", + "title", + "type" + ] + }, + "NotFoundErrorType": { + "type": "string", + "description": "Problem type URI for not-found errors.", + "enum": [ + "/errors/resource-not-found" + ] + }, + "SearchStrategy": { + "type": "string", + "enum": [ + "exact", + "semantic" + ], + "x-enumNames": [ + "SearchStrategyExact", + "SearchStrategySemantic" + ] + }, + "ServiceUnavailableErrorResponseContent": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)." + }, + "status": { + "type": "integer", + "default": 503, + "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.", + "format": "int32" + }, + "detail": { + "type": "string", + "description": "A human-readable explanation specific to this occurrence of the problem." + }, + "instance": { + "type": "string", + "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced." + }, + "type": { + "$ref": "#/components/schemas/ServiceUnavailableErrorType" + } + }, + "required": [ + "status", + "title", + "type" + ] + }, + "ServiceUnavailableErrorType": { + "type": "string", + "enum": [ + "/errors/service-unavailable" + ] + }, + "UnexpectedErrorResponseContent": { + "type": "object", + "description": "The service failed with an unexpected internal error.", + "properties": { + "title": { + "type": "string", + "description": "A short, human-readable summary of the problem\n type. It SHOULD NOT change from occurrence to occurrence of the\n problem, except for purposes of localization (e.g., using\n proactive content negotiation; see [RFC7231], Section 3.4)." + }, + "status": { + "type": "integer", + "default": 500, + "description": "The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.", + "format": "int32" + }, + "detail": { + "type": "string", + "description": "A human-readable explanation specific to this occurrence of the problem." + }, + "instance": { + "type": "string", + "description": "A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced." + }, + "type": { + "$ref": "#/components/schemas/UnexpectedErrorType" + } + }, + "required": [ + "status", + "title", + "type" + ] + }, + "UnexpectedErrorType": { + "type": "string", + "description": "Problem type URI for unexpected internal errors.", + "enum": [ + "/errors/unexpected-error" + ] + } + } + } +} diff --git a/content/operate/iris/langcache/self-managed/deploy.md b/content/operate/iris/langcache/self-managed/deploy.md new file mode 100644 index 0000000000..da7a38ae57 --- /dev/null +++ b/content/operate/iris/langcache/self-managed/deploy.md @@ -0,0 +1,216 @@ +--- +Title: Deploy self-managed LangCache +alwaysopen: false +categories: +- docs +- operate +- iris +description: Deploy self-managed LangCache with the langcache Helm chart. +linkTitle: Deploy +weight: 30 +hideListLinks: true +--- + +One `helm install` of the `langcache` chart deploys the Data Plane, the +Control Plane, and either a bundled Identity Service or a connection to an +external Identity Service. There is no separate lighter-weight install +path; every self-managed LangCache deployment uses the Data Plane, Control +Plane, and one Identity Service mode. + +Before you begin, review [prerequisites]({{< relref "/operate/iris/langcache/self-managed/prerequisites" >}}) +and prepare the config overlays described in +[Configuration]({{< relref "/operate/iris/langcache/self-managed/configuration" >}}). + +## Choose an Identity Service mode + +Decide before you install: + +| Mode | Use when | Values | +| --- | --- | --- | +| Bundled | This is your first LangCache install, or your suite doesn't already run an Identity Service. | `identityService.mode: bundled` | +| External | Your suite already runs an Identity Service (for example, alongside self-managed Redis Agent Memory) and you want LangCache to share it. | `identityService.mode: external` | + +This guide uses bundled mode. For external mode, see +[Authentication and authorization]({{< relref "/operate/iris/langcache/self-managed/authentication#external-identity-service" >}}) +for the values and the coordination required with the Identity Service's +owner. + +## Create the namespace + +```bash +kubectl create namespace +``` + +## Create the required Secrets + +Create the license Secret, shared by the Data Plane and Control Plane: + +```bash +kubectl -n create secret generic langcache-license \ + --from-file=license=./langcache.key +``` + +Create the config overlay Secrets described in +[Configuration]({{< relref "/operate/iris/langcache/self-managed/configuration" >}}): + +```bash +kubectl -n create secret generic dp-overlay \ + --from-file=overlay.yaml=./dp-overlay.yaml +kubectl -n create secret generic cp-overlay \ + --from-file=overlay.yaml=./cp-overlay.yaml +kubectl -n create secret generic ids-metadata \ + --from-file=metadata.yaml=./ids-metadata.yaml +``` + +## Create Helm values + +Create `langcache-values.yaml`: + +```yaml +dataplane: + image: + repository: redislabs/iris-langcache-data + tag: "" + license: + existingSecret: langcache-license + secrets: + secretName: dp-overlay + embedding: + provider: openai + endpoint: + baseURL: https://api.openai.com/v1 + credentials: + type: static + models: + defaultEmbeddingModel: text-embedding-3-small + dimensions: 1536 + +controlplane: + image: + repository: redislabs/iris-langcache-control + tag: "" + secrets: + secretName: cp-overlay + configData: + profile: prod + +identityService: + mode: bundled + bundled: + image: + repository: redislabs/iris-identity-service + tag: "" + metadata: + existingSecret: ids-metadata +``` + +This is a minimal complete install. `controlplane.adminToken`, +`controlplane.internalToken`, and `identityService.bundled.controlToken` +all default to `autoGenerate: true`, so the chart mints those tokens for +you on first install; see +[Authentication and authorization]({{< relref "/operate/iris/langcache/self-managed/authentication" >}}) +to retrieve them, or set `existingSecret` to bring your own. + +The chart renders the Control Plane's embedding contract from +`dataplane.embedding.*`, so set the provider, model, and dimensions only +under `dataplane.embedding`. + +## Install the chart + +Add the Helm repository when installing from the public repository: + +```bash +helm repo add redis-ai https://helm.redis.io/ai +helm repo update redis-ai +helm search repo redis-ai/langcache --versions +``` + +Install with `langcache` as the Helm release name: + +```bash +helm install langcache redis-ai/langcache \ + --version \ + --namespace \ + --create-namespace \ + -f langcache-values.yaml \ + --atomic --wait +``` + +If you installed from a chart package or a local checkout instead, replace +`redis-ai/langcache --version ` with the chart path (for +example `.` from the chart's own root directory). + +On small clusters, install without `--atomic --wait`, then watch pod +status: + +```bash +kubectl -n get pods -w +``` + +## Verify the deployment + +```bash +kubectl -n rollout status deployment/langcache +kubectl -n rollout status deployment/langcache-controlplane +kubectl -n rollout status deployment/langcache-identity-service +``` + +Port-forward the Data Plane: + +```bash +kubectl -n port-forward svc/langcache 9000:9000 +``` + +```bash +curl http://localhost:9000/health +``` + +Port-forward the Control Plane: + +```bash +kubectl -n port-forward svc/langcache-controlplane 9100:9100 +``` + +Retrieve the auto-generated admin token, then create your first cache: + +```bash +kubectl -n get secret langcache-controlplane-admin-token \ + -o jsonpath="{.data.token}" | base64 -d +``` + +```bash +curl -sS -X POST http://localhost:9100/v1/caches \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "name": "my-cache", + "databaseId": "cache-primary", + "defaultSearchThreshold": 0.9, + "defaultTtlMillis": -1, + "attributes": [] + }' +``` + +For the full self-managed admin API schema, see the +[Control Plane API reference]({{< relref "/operate/iris/langcache/self-managed/control-plane-api-reference" >}}). + +Next, mint an agent key through the Identity Service and start calling the +Data Plane; see +[Authentication and authorization]({{< relref "/operate/iris/langcache/self-managed/authentication" >}}) +and [API examples]({{< relref "/operate/iris/langcache/self-managed/api-examples" >}}). + +## Update + +```bash +helm upgrade langcache redis-ai/langcache \ + --version \ + --namespace \ + -f langcache-values.yaml \ + --atomic --wait +``` + +## Next steps + +- [Authentication and authorization]({{< relref "/operate/iris/langcache/self-managed/authentication" >}}) to mint agent keys and configure the Identity Service mode you chose. +- [API examples]({{< relref "/operate/iris/langcache/self-managed/api-examples" >}}) to start calling the Data Plane. +- [Operations]({{< relref "/operate/iris/langcache/self-managed/operations" >}}) for backups, secret rotation, and FIPS posture. diff --git a/content/operate/iris/langcache/self-managed/operations.md b/content/operate/iris/langcache/self-managed/operations.md new file mode 100644 index 0000000000..7ae082f84e --- /dev/null +++ b/content/operate/iris/langcache/self-managed/operations.md @@ -0,0 +1,217 @@ +--- +Title: Operations +alwaysopen: false +categories: +- docs +- operate +- iris +description: Operate self-managed LangCache with backups, secret rotation, updates, FIPS posture, and support bundles. +linkTitle: Operations +weight: 90 +hideListLinks: true +--- + +## Backups + +- Back up Cache Redis according to your cache-retention policy. LangCache + can rebuild the RediSearch index from existing entries, but losing the + underlying hashes loses cached responses. +- Back up Metadata Redis. Losing metadata removes Control Plane cache + records — including the `databaseUrls` the Data Plane depends on to reach + Cache Redis. +- Back up the Identity Service's own metadata Redis (bundled mode). Losing + it removes agent-key and grant records. +- Back up any external secret manager material used to recreate the config + overlay, license, and token Secrets. + +## Secret rotation + +The chart cannot see the contents of Secrets you bring yourself +(`existingSecret` values), so it can't roll pods automatically when you +update one. Every rotatable Secret has a matching `existingSecretChecksum` +value: update the Secret, then bump the checksum and run `helm upgrade` to +force a rollout. + +Rotate the config overlay Secrets (Redis URLs, database registry, embedding +credential): + +```bash +kubectl -n create secret generic dp-overlay \ + --from-file=overlay.yaml=./dp-overlay.yaml \ + --dry-run=client -o yaml | kubectl apply -f - +kubectl -n create secret generic cp-overlay \ + --from-file=overlay.yaml=./cp-overlay.yaml \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +```yaml +dataplane: + secrets: + secretName: dp-overlay + existingSecretChecksum: "" +controlplane: + secrets: + secretName: cp-overlay + existingSecretChecksum: "" +``` + +Rotate the license the same way, using `dataplane.license.existingSecretChecksum`. + +{{< multitabs id="langcache-secret-checksum" +tab1="Linux" +tab2="macOS" >}} + +```bash +sha256sum ./dp-overlay.yaml | awk '{print $1}' +``` + +-tab-sep- + +```bash +shasum -a 256 ./dp-overlay.yaml | awk '{print $1}' +``` + +{{< /multitabs >}} + +Apply the updated values and verify the workloads rolled: + +```bash +helm upgrade langcache redis-ai/langcache \ + --version \ + --namespace \ + -f langcache-values.yaml + +kubectl -n rollout status deployment/langcache +kubectl -n rollout status deployment/langcache-controlplane +``` + +Rotating an auto-generated token (admin token, internal token, Identity +Service control token, or the Data Plane's Identity Service runtime +credential) is different: those Secrets are Helm-managed, not +`existingSecret`, so there is no checksum to bump. The chart looks up the +existing Secret on every `helm upgrade` and keeps its value stable unless +the Secret is gone, so either set `autoGenerate: false` and supply a new +`existingSecret`, or delete the underlying Secret (it carries a +`helm.sh/resource-policy: keep` annotation, so `helm uninstall` won't do +this for you) and let the next `helm upgrade` mint a fresh one. + +Rotate agent keys minted for LangCache caches through the Identity Service; +see [API examples]({{< relref "/operate/iris/langcache/self-managed/api-examples#identity-service-api-examples" >}}). + +## Updates + +For every update: + +1. Update chart version and image tags. +2. Recalculate `existingSecretChecksum` values for any changed overlay or + license Secrets. +3. Run `helm upgrade`. +4. Verify pod rollout and health endpoints. + +```bash +helm upgrade langcache redis-ai/langcache \ + --version \ + --namespace \ + -f langcache-values.yaml \ + --atomic --wait +``` + +On small clusters, avoid `--atomic` unless the timeout and capacity are +known to be sufficient. + +## Helm tests + +The chart can render `helm test` resources when `tests.enabled: true`. This +renders the shared security-profile check and the minimal RBAC it needs: + +```bash +helm upgrade --install langcache redis-ai/langcache \ + --version \ + --namespace \ + -f langcache-values.yaml \ + --set tests.enabled=true + +helm test langcache --logs +``` + +`tests.smoke.enabled: true` independently gates an additional smoke test +that proves authenticated set/search/delete of one uniquely generated cache +entry. It expects a `READY` cache and a valid agent key to already +exist — create the cache through the Control Plane and mint the key +through the Identity Service first, then store the key's plaintext token +in a Secret and reference it: + +```yaml +tests: + enabled: true + smoke: + enabled: true + cacheID: + apiKey: + existingSecret: langcache-smoke-key +``` + +## FIPS-oriented posture + +In a valid `security.profile: fips` deployment, the chart sets +`GODEBUG=fips140=on` on the Data Plane and Control Plane containers: + +```yaml +security: + profile: fips +``` + +Under this posture, the chart: + +- refuses to render with `identityService.mode: bundled` — the bundled + Identity Service's in-cluster Service has no TLS termination of its own, + so its address is always `http://`, which the profile forbids. Use + `identityService.mode: external` with a TLS-fronted Identity Service + instead. +- refuses `identityService.external.baseURL` unless it is `https://`. + `identityService.external.allowInsecureTransport: true` is a real opt-out + outside `fips`, but is not honored under `fips`. + +This is not a formal FIPS 140 compliance or validation claim. Treat it as an +opt-in deployment posture and guardrail that must still be reviewed against +your compliance boundary. + +## Support bundles and preflight + +`supportPackage.enabled: true` (the default) ships a namespace-scoped +[Troubleshoot](https://troubleshoot.sh) spec as a ConfigMap. Collect a +bundle with: + +```bash +kubectl support-bundle --namespace --load-cluster-specs \ + -l troubleshoot.sh/kind=support-bundle +``` + +The bundle excludes Secret contents, license data, Redis URLs, +admin/internal/runtime credentials, API-key material, prompts, responses, +vectors, and cache records — see the redactor spec shipped in the same +namespace (`langcache-support-redactors`) for the exact rules. + +`preflight.enabled: true` (the default) ships a cluster preflight check as +both a ConfigMap and a standalone file (`support/langcache-preflight.yaml` +in the chart source) for `kubectl preflight` before you install: + +```bash +kubectl preflight support/langcache-preflight.yaml +``` + +## Network policy + +For every Identity Service mode, prevent callers from bypassing your +intended access path (gateway, ingress, or trusted-internal-only) and +reaching the Data Plane, Control Plane, or bundled Identity Service Service +directly. Write a NetworkPolicy for your cluster's CNI that default-denies +ingress to the `langcache`, `langcache-controlplane`, and (bundled mode) +`langcache-identity-service` Services, then allow TCP traffic on their +respective ports (`9000`, `9100`, `9200`) from approved callers only. + +## See also + +- [Configuration]({{< relref "/operate/iris/langcache/self-managed/configuration" >}}) for the Redis roles being backed up and rotated here. +- [Authentication and authorization]({{< relref "/operate/iris/langcache/self-managed/authentication" >}}) for how the tokens and agent keys rotated above are used. +- [Configuration and troubleshooting]({{< relref "/operate/iris/langcache/self-managed/reference" >}}) for symptoms and fixes if a rotation or update doesn't take effect. diff --git a/content/operate/iris/langcache/self-managed/prerequisites.md b/content/operate/iris/langcache/self-managed/prerequisites.md new file mode 100644 index 0000000000..448d7034b4 --- /dev/null +++ b/content/operate/iris/langcache/self-managed/prerequisites.md @@ -0,0 +1,199 @@ +--- +Title: Self-managed LangCache prerequisites +alwaysopen: false +categories: +- docs +- operate +- iris +description: Review software, Redis, network, Secret, image, and sizing prerequisites for self-managed LangCache. +linkTitle: Prerequisites +weight: 10 +hideListLinks: true +--- + +LangCache self-managed is distributed as container images on Docker Hub plus +the `langcache` Helm chart. One `helm install` of the chart deploys the +LangCache Data Plane, the LangCache Control Plane, and either a bundled +Identity Service or a connection to an external Identity Service. + +You provide the Redis databases, embedding provider credentials, Kubernetes +exposure, and license material used by the deployment. + +{{< note >}} +This guide is for system administrators deploying LangCache on a self-managed +Kubernetes cluster. +{{< /note >}} + +## What you need + +| Item | Where it comes from | +| ---- | ------------------- | +| Container images | `redislabs/iris-langcache-data`, `redislabs/iris-langcache-control`, and (bundled Identity Service) `redislabs/iris-identity-service` on Docker Hub | +| Helm chart | `langcache` chart, published to `https://helm.redis.io/ai` (the same repository as the self-managed Redis Agent Memory chart), or a chart package provided by Redis. | +| Redis databases | You provide Metadata Redis and one or more Cache Redis databases | +| License key | Contact your Redis representative or [contact sales](https://redis.io/contact/). | +| Provider credentials | You provide embedding provider credentials (currently an OpenAI-compatible provider) | + +## Required software + +| Software | Minimum version | Purpose | +| -------- | --------------- | ------- | +| Kubernetes | 1.23+ | Orchestration; the chart renders an `autoscaling/v2` HorizontalPodAutoscaler | +| kubectl | 1.23+ | Kubernetes CLI | +| Helm | 3.x | Package manager | + +## Redis databases + +The Helm chart does not deploy Redis databases. Provision them outside the +chart and register them through the Control Plane's and Data Plane's config +overlays (see [Configuration]({{< relref "/operate/iris/langcache/self-managed/configuration" >}})). + +Cache Redis must support RediSearch with vector search, because LangCache +creates a RediSearch vector index per cache. Metadata Redis does not need +that capability. + +{{< table-scrollable >}} +| Redis database | Required | Registered in | Purpose | +| --- | --- | --- | --- | +| Metadata Redis | Always | Both the Data Plane's and Control Plane's config overlays (same URLs, same keyspace) | Cache records written by the Control Plane, read by the Data Plane. | +| Cache Redis (one or more) | Always | The Control Plane's config overlay only, as a `databases` registry entry keyed by a logical `databaseId` | Cache entry hashes and RediSearch vector indexes. The Data Plane has no database registry of its own — it resolves each cache's Redis URLs from the metadata the Control Plane already persisted at cache-creation time. | +| Identity Service metadata Redis (bundled mode only) | When `identityService.mode: bundled` | The bundled Identity Service's own config overlay | Agent-key and grant records. Can be the same Redis instance as Metadata Redis, in a separate namespace. | +{{< /table-scrollable >}} + +For a lab deployment, these Redis roles can point at the same Redis endpoint +if it has the required modules and capacity. For production, separate them +so cache data and control metadata can be scaled, backed up, and operated +independently. + +### Metadata Redis durability + +Metadata Redis is small compared with Cache Redis, but it is operationally +critical. Use persistent storage, Redis authentication, network isolation, +and TLS where required. Avoid eviction of metadata keys; losing metadata +removes Control Plane cache records. + +## Network access + +- **Connected install:** the cluster must be able to pull the LangCache and + Identity Service images from Docker Hub (or your mirrored registry) and + reach `https://helm.redis.io/ai`. +- **Air-gapped install:** mirror the images into an internal registry and + use a locally downloaded chart package. +- **Runtime access:** LangCache pods must reach the Redis databases and the + embedding provider endpoint used by the deployment. The Data Plane must + also reach the Identity Service (bundled or external); the Control Plane + must reach Metadata Redis and every registered Cache Redis database. +- **Data Plane exposure:** use NetworkPolicy, ingress, gateway, service mesh, + private load balancer, or equivalent controls to restrict API access. + +## Credentials and Secrets + +The chart never puts Redis URLs, the database registry, or the embedding +credential in `values.yaml` or a rendered ConfigMap. Each of the Data Plane, +Control Plane, and bundled Identity Service reads its own pre-created +overlay Secret, deep-merged over its rendered base config at runtime. See +[Configuration]({{< relref "/operate/iris/langcache/self-managed/configuration" >}}) +for the overlay content each component expects. + +| Secret | Required when | Default key | +| --- | --- | --- | +| LangCache license Secret | Always | `license` | +| Data Plane config overlay Secret | Always | `overlay.yaml` | +| Control Plane config overlay Secret | Always | `overlay.yaml` | +| Identity Service metadata Secret | `identityService.mode: bundled` | `metadata.yaml` | +| Control Plane admin token | Auto-generated by default, or bring your own | `token` | +| Control Plane internal (grant-validation) token | Auto-generated by default, or bring your own | `token` | +| Identity Service control token (bundled mode) | Auto-generated by default, or bring your own | `token` | +| Data Plane's Identity Service runtime credential (external mode) | `identityService.mode: external` | `token`, minted by the suite-level Identity Service owner | + +## Release artifacts and image tags + +LangCache self-managed image tags use the release SemVer value, for example: + +```yaml +dataplane: + image: + repository: redislabs/iris-langcache-data + tag: "" +controlplane: + image: + repository: redislabs/iris-langcache-control + tag: "" +identityService: + bundled: + image: + repository: redislabs/iris-identity-service + tag: "" +``` + +Use the image tags listed for the release on Docker Hub or provided by +Redis. Do not use floating image tags in production. + +## Air-gapped and private registry installs + +Mirror the published images into your internal registry: + +```bash +for image in iris-langcache-data iris-langcache-control iris-identity-service; do + docker pull redislabs/$image: + docker tag redislabs/$image: \ + registry.example.com/redislabs/$image: + docker push registry.example.com/redislabs/$image: +done +``` + +If the registry requires authentication, create an image pull Secret and +reference it from `imagePullSecrets` in your values file: + +```bash +kubectl -n create secret docker-registry langcache-registry \ + --docker-server=registry.example.com \ + --docker-username= \ + --docker-password= +``` + +```yaml +imagePullSecrets: + - name: langcache-registry +``` + +## System requirements + +Default chart values: + +| Component | Default | Purpose | +| --------- | ------- | ------- | +| LangCache Data Plane | 2 replicas with autoscaling enabled (2–10) | Data Plane API traffic | +| LangCache Control Plane | 1 replica, no autoscaling | Admin API for caches | +| Identity Service (bundled mode) | 1 replica | Agent-key issuance and introspection | + +During a rolling update, Kubernetes may temporarily run old and new pods at +the same time. A small test cluster can run out of CPU during install or +upgrade; size for the maximum rolling-update overlap, or reduce replicas +explicitly for a lab install. + +## Helm values to review + +The walkthroughs in this guide assume the chart's default +`fullnameOverride: langcache`, which fixes the rendered resource names to +`langcache` (Data Plane), `langcache-controlplane`, and +`langcache-identity-service` (bundled mode). If you change it, update the +release-derived names in the verification commands throughout this guide. + +{{< table-scrollable >}} +| Area | Values | Use when | +| --- | --- | --- | +| Images | `dataplane.image.*`, `controlplane.image.*`, `identityService.bundled.image.*`, `imagePullSecrets` | Selecting a release or private registry image. | +| Data Plane capacity | `dataplane.resources`, `dataplane.autoscaling.*` | Tuning request capacity or memory footprint. | +| Networking | `dataplane.service.*`, `dataplane.ingress.*` | Exposing LangCache outside the cluster. | +| Security posture | `security.profile` | Opting into the FIPS-oriented posture. | +| Identity Service mode | `identityService.mode` (`bundled` or `external`) | Choosing whether this release runs its own Identity Service or joins one the suite already runs. | +| Config overlays | `dataplane.secrets.*`, `controlplane.secrets.*`, `identityService.bundled.metadata.*` | Pointing the chart at your pre-created overlay Secrets. | +| Rotation | `*.existingSecretChecksum` fields throughout | Rolling pods after an externally managed Secret changes. | +{{< /table-scrollable >}} + +## Next steps + +Continue to [Configuration]({{< relref "/operate/iris/langcache/self-managed/configuration" >}}) +to prepare the Data Plane, Control Plane, and Identity Service overlay +Secrets, then [Deploy self-managed LangCache]({{< relref "/operate/iris/langcache/self-managed/deploy" >}}). diff --git a/content/operate/iris/langcache/self-managed/reference.md b/content/operate/iris/langcache/self-managed/reference.md new file mode 100644 index 0000000000..4f8f1218aa --- /dev/null +++ b/content/operate/iris/langcache/self-managed/reference.md @@ -0,0 +1,63 @@ +--- +Title: Configuration and troubleshooting +alwaysopen: false +categories: +- docs +- operate +- iris +description: Review self-managed LangCache configuration, troubleshooting guidance, and reference links. +linkTitle: Configuration and troubleshooting +weight: 100 +hideListLinks: true +--- + +## Configuration reference + +Use these files to configure a self-managed deployment: + +| File | Purpose | +| --- | --- | +| `langcache-values.yaml` | Helm values for images, replicas, services, security posture, Identity Service mode, and non-secret config structure. | +| `dp-overlay.yaml` | Data Plane's Metadata Redis URLs and (if static) embedding credential, deep-merged over the rendered config at startup. | +| `cp-overlay.yaml` | Control Plane's Metadata Redis URLs and Cache Redis database registry, deep-merged over the rendered config at startup. | +| `ids-metadata.yaml` | Bundled Identity Service's own Metadata Redis URLs. | +| `langcache.key` | LangCache license file provided by Redis. | + +### External secret managers + +If you use an external secret manager, expose the license, overlay, and +token material to the chart as Kubernetes Secrets and set the chart's +`existingSecret` values to those Secret names. + +## Troubleshooting + +{{< table-scrollable >}} +| Symptom | Likely cause | Fix | +| --- | --- | --- | +| Docker pull fails for the configured image tag | Image tag is wrong or not published yet | Use the image tag listed for the release on Docker Hub or provided by Redis. | +| Pod is stuck in `ImagePullBackOff` or `ErrImagePull` | Cluster cannot pull the configured image, image tag is wrong, registry requires credentials, or `imagePullSecrets` is missing/wrong | Verify `dataplane.image.*`/`controlplane.image.*`/`identityService.bundled.image.*`, registry reachability, and `imagePullSecrets`. | +| `helm install --atomic --wait` times out and rolls back | Cluster is small or image pull/startup takes longer than Helm's default timeout | Install without `--atomic --wait`, or set a longer `--timeout` and ensure enough cluster capacity. | +| Chart fails to render with `identityService.mode: bundled` and `security.profile: fips` | The FIPS posture forbids the bundled Identity Service's unencrypted in-cluster address | Use `identityService.mode: external` with a TLS-fronted Identity Service. | +| Data Plane health fails | Pod not ready, overlay Secret missing/invalid, or Redis unavailable | Check pod logs and call `/health`, `/health/liveness`, and `/health/readiness`. | +| Cache search or set requests fail with an index error | The RediSearch vector index for the cache was never provisioned, or Cache Redis does not support RediSearch with vector search | Check Control Plane cache status (`GET /v1/caches/{cacheId}`) and Cache Redis modules. | +| Control Plane `CreateCache` returns `424` | Cache Redis for the resolved `databaseId` is unreachable or does not satisfy LangCache's Redis module requirements | Check the `databases..urls` connectivity and Redis modules in `cp-overlay.yaml`. | +| Control Plane `CreateCache` returns `400` | A required field is missing, or a field fails validation — for example `databaseId` doesn't match `^[A-Za-z0-9-]+$`, `defaultSearchThreshold` is outside 0–1, or `attributes` has more than 5 entries | Check the request body against [Control Plane API reference]({{< relref "/operate/iris/langcache/self-managed/control-plane-api-reference" >}}). `CreateCache` has no embedding-related fields at all; the embedding provider, model, and dimensions always come from the deployment-wide contract, not the request. | +| Agent receives `401` | Missing, malformed, revoked, expired, or invalid agent key, or the Data Plane cannot reach the Identity Service | Check the `Authorization` header, key status through the Identity Service, and Data Plane connectivity to the Identity Service (bundled Service or `identityService.external.baseURL`). | +| Agent receives `403` | Key exists but lacks the required `lc-cache:` grant or action | Update grants through the Identity Service's `/v1/api-keys/{keyId}` endpoint. | +| Cache created by the Control Plane is not visible to the Data Plane | Data Plane and Control Plane overlays point at different Metadata Redis URLs | Make `dp-overlay.yaml` and `cp-overlay.yaml` use the same `metadata.urls`. | +| `helm upgrade` doesn't roll a pod after rotating an overlay Secret | The matching `existingSecretChecksum` value wasn't bumped | Recalculate the SHA-256 checksum of the overlay file and set the corresponding `*.existingSecretChecksum` value. | +| External Identity Service rejects LangCache's introspection calls | The suite-level Identity Service's `product_validation.langcache` isn't configured against this release's Control Plane internal Service and `internalToken` | Ask the Identity Service owner to configure that product entry; see [Authentication and authorization]({{< relref "/operate/iris/langcache/self-managed/authentication#external-identity-service" >}}). | +| NetworkPolicy blocks expected traffic | Placeholder namespace, release name, or caller selectors were not customized correctly | Check the Helm release label `app.kubernetes.io/instance`, caller namespace, and caller pod labels. | +{{< /table-scrollable >}} + +## References + +| Need | Reference | +| --- | --- | +| Helm chart repository | `https://helm.redis.io/ai`, chart `langcache` | +| Helm chart values and README | `langcache/helm/` in the LangCache source repository, or the synced copy in `RedisLabs/redis-enterprise-helm` at `ai/charts/langcache` | +| Container images | Docker Hub: [redislabs/iris-langcache-data](https://hub.docker.com/r/redislabs/iris-langcache-data/tags), [redislabs/iris-langcache-control](https://hub.docker.com/r/redislabs/iris-langcache-control/tags), [redislabs/iris-identity-service](https://hub.docker.com/r/redislabs/iris-identity-service/tags) | +| LangCache API reference (Data Plane) | [LangCache API]({{< relref "/develop/ai/context-engine/langcache/api-reference" >}}) | +| Control Plane API reference | [Control Plane API reference]({{< relref "/operate/iris/langcache/self-managed/control-plane-api-reference" >}}) | +| LangCache overview | [LangCache overview]({{< relref "/develop/ai/context-engine/langcache" >}}) | +| License key | Contact your Redis representative or [contact sales](https://redis.io/contact/) |