# Deploy Lens

```json metadata
{
  "schema_version": 2,
  "title": "Deploy Lens",
  "description": "Install the Identity Service and Lens, check the deployment, create API keys, and give developers their Lens settings.",
  "categories": ["docs","operate","iris"],
  "tableOfContents": {"sections":[{"id":"1-create-the-namespace","title":"1. Create the namespace"},{"id":"2-create-secrets","title":"2. Create Secrets"},{"id":"3-install-the-identity-service","title":"3. Install the Identity Service"},{"id":"4-install-lens","title":"4. Install Lens"},{"id":"5-check-the-deployment","title":"5. Check the deployment"},{"id":"6-make-an-authenticated-read","title":"6. Make an authenticated read"},{"id":"expose-the-data-plane","title":"Expose the data plane"},{"id":"hand-off-to-developers","title":"Hand off to developers"},{"id":"install-with-the-redis-iris-suite-chart","title":"Install with the Redis Iris suite chart"},{"id":"next-steps","title":"Next steps"}]}

,
  "codeExamples": []
}
```


> [!NOTE]
> For a supported install, see [Install with the Redis Iris suite chart](#install-with-the-redis-iris-suite-chart). The standalone steps on this page show what each value does.

Follow these steps to install an Identity Service release and the `redis-lens` chart, check the deployment with a read key, and give developers the settings their agents need.

The examples use a Lens release named `lens` and an Identity Service release named `ids`, in the same namespace. With these names, the Lens Services are `lens-redis-lens-dataplane` and `lens-redis-lens-controlplane`, and the Identity Service is `ids-iris-identity-service`. If you choose other names, change them everywhere they appear, in both releases.

Before you begin, review the [prerequisites](https://redis.io/docs/latest/operate/iris/lens/self-managed/prerequisites). If you already run an Identity Service release for another Iris service, add the Lens entries from [step 3](#3-install-the-identity-service) to its values, and skip installing it.

## 1. Create the namespace

```bash
kubectl create namespace <namespace-name>
```

## 2. Create Secrets

Save the storage files from [Storage Secret](https://redis.io/docs/latest/operate/iris/lens/self-managed/configuration#storage-secret), and the license you received as `lens-license.key`. Save the Identity Service's metadata Redis as `ids-metadata.yaml`:

```yaml
metadata:
  urls: ["rediss://<ids-metadata-user>:<ids-metadata-password>@<ids-metadata-host>:<ids-metadata-port>"]
```

Then create the Secrets:

```bash
kubectl -n <namespace-name> create secret generic lens-storage \
  --from-file=lens-dataplane-storage.yaml \
  --from-file=lens-controlplane-storage.yaml
kubectl -n <namespace-name> create secret generic lens-license \
  --from-file=license=./lens-license.key
kubectl -n <namespace-name> create secret generic lens-dp-credential \
  --from-literal=token="$(openssl rand -hex 32)"
kubectl -n <namespace-name> create secret generic lens-internal-token \
  --from-literal=token="$(openssl rand -hex 32)"
kubectl -n <namespace-name> create secret generic ids-metadata \
  --from-file=metadata.yaml=./ids-metadata.yaml
kubectl -n <namespace-name> create secret generic ids-control-token \
  --from-literal=token="$(openssl rand -hex 32)"
```

Both releases mount `lens-dp-credential` and `lens-internal-token`. You own these two Secrets, and neither chart generates them. Neither chart checks the other's values, so keep them consistent yourself.

## 3. Install the Identity Service

For every Identity Service setting, and for running one release that serves several products, see the [Identity Service guide](https://redis.io/docs/latest/operate/iris/identity-service).

Save this as `values-ids.yaml`. It registers the data plane's runtime credential, and points grant validation at the Lens control plane:

```yaml
metadata:
  existingSecret: ids-metadata
control:
  existingSecret: ids-control-token
  autoGenerate: false
runtime:
  apiKeyTenant:
    singleTenantID: default
  serviceCredentials:
    - name: lens-dataplane
      subject: lens-dataplane
      allowedOperations: [api-key-introspect]
      allowedProducts: [lens]
      existingSecret: lens-dp-credential
      secretKey: token
productValidation:
  products:
    lens:
      baseURL: http://lens-redis-lens-controlplane:9300
      credential:
        existingSecret: lens-internal-token
        secretKey: token
```

`singleTenantID` must equal the Lens `tenantId`. Lens needs no `subjectGrants.allowed` entry and no unscoped-grants product.

```bash
helm repo add redis-ai https://helm.redis.io/ai
helm repo update redis-ai
helm install ids redis-ai/iris-identity-service \
  --version 1.0.0 \
  --namespace <namespace-name> \
  -f values-ids.yaml
```

Use the same version as the Lens chart, `1.0.0`. The Lens control plane doesn't exist yet. Wait until Lens is running before you create keys, because the Identity Service calls the control plane to validate each grant.

## 4. Install Lens

Write `lens-values.yaml` from [Helm values](https://redis.io/docs/latest/operate/iris/lens/self-managed/configuration#helm-values), then install the chart:

```bash
helm install lens redis-ai/redis-lens \
  --version 1.0.0 \
  --namespace <namespace-name> \
  -f lens-values.yaml \
  --wait --timeout 5m
```

The control plane creates the instance named by `instance.id` at startup, and generates the admin token Secret `lens-redis-lens-controlplane-admin-token`.

## 5. Check the deployment

Wait for the three Deployments:

```bash
kubectl -n <namespace-name> rollout status deployment/lens-redis-lens-dataplane
kubectl -n <namespace-name> rollout status deployment/lens-redis-lens-worker
kubectl -n <namespace-name> rollout status deployment/lens-redis-lens-controlplane
```

With `tests.enabled=true`, run the readiness checks:

```bash
helm test lens --namespace <namespace-name>
```

Readiness stays false while the license is in its grace period. A release image without a valid license doesn't start.

## 6. Make an authenticated read

Run each port-forward in its own terminal and leave it running:

```bash
kubectl -n <namespace-name> port-forward svc/ids-iris-identity-service 9200:9200
```

```bash
kubectl -n <namespace-name> port-forward svc/lens-redis-lens-dataplane 9000:9000
```

Create a read key, as described in [Create API keys](https://redis.io/docs/latest/operate/iris/lens/self-managed/authentication#create-api-keys), and save it in `LENS_API_KEY`. Then list the instance's agents:

```bash
curl -sS http://localhost:9000/iris/data/v1beta1/lens/instances/default/agents \
  -H "Authorization: Bearer $LENS_API_KEY"
```

A new instance returns an empty list. A `401` means the key is wrong or the data plane can't reach the Identity Service. A `403` means the key has no `read` grant on this instance.

## Expose the data plane

Agents and read clients reach Lens at an Iris host, such as `https://iris.example.com`. The SDK refuses a plain `http://` endpoint outside loopback addresses by default, and the data plane serves plain HTTP. Publish it through a TLS-terminating ingress or gateway:

- Route the path prefix `/iris/data/v1beta1/lens` on the Iris host to the `lens-redis-lens-dataplane` Service on port `9000`, without rewriting the path.
- Allow request bodies up to the ingest request size in [Request limits](https://redis.io/docs/latest/develop/ai/context-engine/lens/limits#request-limits), 8 mebibytes (MiB) by default.
- Don't publish the control plane. Operators reach it inside the cluster.

For example, with a Kubernetes Ingress:

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: lens
spec:
  ingressClassName: <ingress-class>
  tls:
    - hosts: [<iris-host>]
      secretName: <iris-host-tls-secret>
  rules:
    - host: <iris-host>
      http:
        paths:
          - path: /iris/data/v1beta1/lens
            pathType: Prefix
            backend:
              service:
                name: lens-redis-lens-dataplane
                port:
                  number: 9000
```

To let developers open Lens in the Iris console, also add a `lens` entry to the console's gateway. See [Connect the console](https://redis.io/docs/latest/operate/iris/lens/self-managed/operations#connect-the-console).

## Hand off to developers

Give each application team these values. They match the variables in [Configure Lens](https://redis.io/docs/latest/develop/ai/context-engine/lens/configure) and the [read API](https://redis.io/docs/latest/develop/ai/context-engine/lens/read-api):

| Variable | Value |
| --- | --- |
| `IRIS_LENS_ENDPOINT` | The Iris host, such as `https://<iris-host>`. The SDK sends turns to `/iris/data/v1beta1/lens/v1/traces` on it. |
| `IRIS_LENS_API_KEY` | An ingest key for each agent. |
| `LENS_URL` | The same Iris host, for the read client. |
| `LENS_INSTANCE_ID` | Your `instance.id`, `default` unless you changed it. |
| `LENS_API_KEY` | A read key for each person or tool that reads turns. |

Give each agent its own ingest key. If one agent's key leaks, you can [revoke or rotate that key](https://redis.io/docs/latest/operate/iris/lens/self-managed/authentication) without interrupting your other agents. Send keys through your secret store, not in chat or tickets.

Developers can then [trace their first turn](https://redis.io/docs/latest/develop/ai/context-engine/lens/quickstart).

## Install with the Redis Iris suite chart

The `redis-iris` Helm chart installs Lens with the Identity Service and the Iris console in one release. Lens is on by default (`global.iris.products.lens.enabled`), and its values go under the `lens:` key. The chart also installs the other Iris products by default, so set `global.iris.products.<product>.enabled: false` for each one you don't deploy: `memory`, `playbook`, `contextGateway`, or `intent`.

The suite derives these values from `global.iris`. Don't set them under `lens:`: a value that differs fails the render and names the field.

- `tenantId`, from `global.iris.tenantId`.
- `license.existingSecret` and `license.secretKey`, from `global.iris.license`.
- `dataplane.identityServiceBaseURL` and `identityService.allowInsecureTransport`, for the suite's Identity Service.
- `identityService.credential` and `controlplane.internalToken`, the runtime credential and internal token.
- `auth.oidc.audience`, `dataplane.oidc`, and `controlplane.oidc.enabled`, from `global.iris.auth.oidc` and `global.iris.auth.roleBindings`.

The suite also fixes `fullnameOverride` (`redis-lens`), the Service ports, `instance.id` (`default`), the data-plane rollout strategy, and `podDisruptionBudget.enabled` (`true`), and runs two data-plane replicas by default. The Services are `redis-lens-dataplane` and `redis-lens-controlplane`, the admin token is in the Secret `iris-lens-admin-token`, and the suite adds the console's Lens route. Save the Lens values in `iris-values.yaml`:

```yaml
lens:
  storage:
    existingSecret: lens-storage
```

```bash
helm install iris redis-ai/redis-iris \
  --version 1.0.0 \
  --namespace <namespace-name> \
  -f iris-values.yaml
```

The rest of this guide applies to the values under `lens:`.

## Next steps

- [Create, rotate, and revoke API keys](https://redis.io/docs/latest/operate/iris/lens/self-managed/authentication).
- [Operate the deployment](https://redis.io/docs/latest/operate/iris/lens/self-managed/operations).

