diff --git a/enterprise/analytics.mdx b/enterprise/analytics.mdx index e1b84608..c2653147 100644 --- a/enterprise/analytics.mdx +++ b/enterprise/analytics.mdx @@ -11,6 +11,16 @@ You'll opt into Analytics and configure conversations to automatically send trac This guide is for users who want to explore analytics on their OpenHands Enterprise conversations. +It covers both supported install paths: + +- **Replicated (VM install)** -- if you followed the [Quick Start](/enterprise/quick-start) and + manage OpenHands through the Replicated Admin Console. +- **Helm (Kubernetes install)** -- if you deployed the `openhands` Helm chart into your own + Kubernetes cluster (see [Kubernetes Installation](/enterprise/k8s-install/index)). + +Most of the workflow (creating a Laminar project, creating an API key, viewing traces) is +the same on both paths. The two install-specific steps are tabbed below. + ### Why Laminar? [Laminar](https://laminar.sh/) is an open source observability platform for AI agents like OpenHands. @@ -29,31 +39,199 @@ For more information on evaluating skills, see [Evaluating Agent Skills](https:/ ### Prerequisites -Before you begin, make sure you completed the [Quick Start guide](/enterprise/quick-start). +Before you begin, make sure you have completed the install for your path: -## Enable Analytics +- **Replicated**: [Quick Start guide](/enterprise/quick-start) +- **Helm**: [Kubernetes Installation guide](/enterprise/k8s-install/index) -You should see an **Analytics Configuration** section on the application configuration page. +You will also need: -Check the **Enable Analytics** box to have the installer set up and configure Laminar for analytics. +- DNS records (and a TLS certificate covering the SAN) for `analytics.app.`. + On Replicated, this is included in the [Quick Start DNS table](/enterprise/quick-start#dns-and-tls-setup). + On Helm, you choose the hostname yourself in `site-values.yaml`. +- An ingress controller already running in the cluster (Replicated installs ship Traefik; Helm + installs typically use Traefik as well -- see the [chart README](https://github.com/OpenHands/OpenHands-Cloud/blob/main/charts/openhands/README.md)). -![Configure Analytics](./images/laminar-configure-analytics.png) +## Enable Analytics + + + + On the application configuration page in the Admin Console, find the + **Analytics Configuration** section. + + Check the **Enable Analytics** box. The installer will set up Laminar and template the + required hostnames and Keycloak wiring for you. + + ![Configure Analytics](./images/laminar-configure-analytics.png) + + + + Add the `laminar` block to your `site-values.yaml` and set the top-level `env.LMNR_*` + keys so the application sends traces to Laminar. + + This guide assumes a single-cluster install where OpenHands runtimes and Laminar run + in the same Kubernetes cluster. Traces are sent to the in-cluster Laminar Service, + so you only need **one** new DNS record and TLS SAN -- the user-facing Laminar UI + hostname (e.g. `analytics.app.`). + + Replace `example.com` with your base domain, and replace `traefik` with the name of + your ingress controller's IngressClass. + + ```yaml + # site-values.yaml + + env: + # The application sends traces to the in-cluster Laminar Service. No external + # hostname is required for ingestion. + LMNR_BASE_URL: "http://laminar-app-server-service" + LMNR_FORCE_HTTP: "true" + LMNR_HTTP_PORT: "8000" + # LMNR_PROJECT_API_KEY is set in a later step, after you create an ingest-only key + # in the Laminar UI. + + laminar: + enabled: true + global: + # Sets provider-specific defaults; not auto-detected. Use "gcp" or "aws". + cloudProvider: "gcp" + frontend: + ingress: + enabled: true + hostname: "analytics.app.example.com" # REQUIRED -- the Laminar UI hostname + className: "traefik" # your ingress controller's IngressClass + externalDns: + enabled: false # true if external-dns manages your DNS + tls: + enabled: true + clusterIssuer: "" # see TLS options below + secretName: "laminar-frontend-tls" + env: + # Must match laminar.frontend.ingress.hostname above. + nextauthUrl: "https://analytics.app.example.com" + nextPublicUrl: "https://analytics.app.example.com" + extraEnv: + # Wires the Laminar UI to your existing Keycloak realm so users can sign in + # with the same identity provider they use for OpenHands. + - name: AUTH_KEYCLOAK_ID + valueFrom: + secretKeyRef: + name: keycloak-realm + key: client-id + - name: AUTH_KEYCLOAK_SECRET + valueFrom: + secretKeyRef: + name: keycloak-realm + key: client-secret + - name: AUTH_KEYCLOAK_ISSUER + value: "https://auth.app.example.com/realms/allhands" + ``` + + ### TLS options for the frontend ingress + + The `laminar.frontend.ingress.tls` block above works with either pattern: + + - **Pre-existing TLS secret** (recommended if your DNS and certs are managed externally): + leave `clusterIssuer: ""` and create the secret yourself. Concatenate the certificate + and CA bundle into a full chain first: + + ```bash + cat cert.pem ca-bundle.pem > fullchain.pem + + kubectl create secret tls laminar-frontend-tls \ + -n openhands --cert=fullchain.pem --key=private-key.pem + ``` + + - **cert-manager with Let's Encrypt**: set `clusterIssuer: "letsencrypt"` (or the name + of any other `ClusterIssuer` in your cluster). The hostname must be publicly + DNS-resolvable so Let's Encrypt can complete the HTTP-01 challenge. + + ### Apply the change + + ```bash + helm upgrade --install openhands \ + --namespace openhands \ + oci://ghcr.io/all-hands-ai/helm-charts/openhands \ + -f site-values.yaml + ``` + + + Skip this section unless OpenHands runtimes will be sending traces from **outside** + the cluster where Laminar runs. Almost all installs are single-cluster and should + use the in-cluster ingest configuration above. + + For multi-cluster setups, expose the Laminar app-server through your ingress (or, on + AWS, an L4 Network Load Balancer) and point `LMNR_BASE_URL` at the external hostname. + This adds a second DNS record and TLS SAN (e.g. `laminar-api.app.`). + + ```yaml + # site-values.yaml + + env: + LMNR_BASE_URL: "https://laminar-api.app.example.com" + LMNR_FORCE_HTTP: "true" + # Omit LMNR_HTTP_PORT -- the port comes from the URL. + + laminar: + appServer: + ingress: + hostname: "laminar-api.app.example.com" + className: "traefik" + externalDns: + enabled: false + tls: + enabled: true + clusterIssuer: "" + secretName: "laminar-app-server-tls" + ``` + + **AWS clusters** can swap `laminar.appServer.ingress` for an L4 Network Load Balancer: + + ```yaml + laminar: + appServer: + loadBalancer: + enabled: true + hostname: "laminar-api.app.example.com" + ``` + + See the [lmnr-helm configuration guide](https://github.com/lmnr-ai/lmnr-helm/blob/main/CONFIGURATION.md) + for additional DNS and TLS variants, including manual DNS and pre-existing ACM certificates. + + + ## Deploy -OpenHands will begin deploying. You can expect the deployment status to transition from -**Missing** to **Unavailable** to **Ready**. This typically takes 10-15 minutes. + + + OpenHands will begin deploying. You can expect the deployment status to transition from + **Missing** to **Unavailable** to **Ready**. This typically takes 10-15 minutes. + + ![Deployment in progress](./images/laminar-deploy-in-progress.png) + + Click **Details** next to the deployment status to monitor individual resources. Resources + shown in orange are still deploying -- wait until all resources are ready. -![Deployment in progress](./images/laminar-deploy-in-progress.png) + ![Deployment status details](./images/laminar-deployment-status-details.png) + -Click **Details** next to the deployment status to monitor individual resources. Resources -shown in orange are still deploying -- wait until all resources are ready. + + Watch the Laminar pods come up in your cluster: -![Deployment status details](./images/laminar-deployment-status-details.png) + ```bash + kubectl get pods -n openhands -l app.kubernetes.io/instance=openhands -w + ``` + + You should see pods for `laminar-frontend`, `laminar-app-server`, `laminar-clickhouse`, + `laminar-postgres`, `laminar-rabbitmq`, `laminar-redis`, and the Quickwit components. + Wait until all pods are `Running` and ready before continuing. + + ## Access Laminar UI -Once the deployment status shows **Ready**, navigate to `https://analytics.app.`. +Once the deployment is **Ready**, navigate to `https://analytics.app.` +(or the `laminar.frontend.ingress.hostname` you configured for the Helm install). Click the **Continue with Keycloak** button: @@ -67,29 +245,69 @@ Once a project has been created, Laminar is ready to listen for traces. ![Laminar Listen Traces](./images/laminar-listen-traces.png) -## Create an ingest only API Key +## Create an ingest-only API Key -Important: Always use ingest API keys when deploying. + + Always use **ingest-only** API keys for the OpenHands integration. Ingest-only keys can + only write traces -- they cannot be used to read data, so they are safe to embed in + configuration. + -Create a key with the right permissions. Ingest only keys are recommended as they only have write access to write traces. They cannot be used to read data. +Create a key with ingest-only permissions: ![Configure Laminar Ingest Only Key](./images/laminar-ingest-only-key.png) -## Set Laminar Project API Key to enable automatic conversation traces +## Wire the API key into the install + + + + Paste the ingest-only key into the **Laminar Project API Key** field in the Admin Console + configuration: + + ![Configure Laminar Project API Key](./images/laminar-configure-key.png) + + Click **Save config**, then deploy the change: + + ![Laminar Deploy Again](./images/laminar-deploy-again.png) + + Wait for the deployment to complete. + + + + Set the ingest-only key in your `site-values.yaml` under the top-level `env` block: -Set the ingest only key as the Laminar Project API Key in the Admin Console configuration: + ```yaml + # site-values.yaml -![Configure Laminar Project API Key](./images/laminar-configure-key.png) + env: + LMNR_BASE_URL: "http://laminar-app-server-service" + LMNR_FORCE_HTTP: "true" + LMNR_HTTP_PORT: "8000" + LMNR_PROJECT_API_KEY: "" + ``` -Click **Save config**. + + For a production install, store the key in a Kubernetes Secret and reference it from + your values file or via `--set-string` at install time, rather than committing it to + source control. + -## Deploy Updated Configuration + Apply the change: -Deploy the config change after setting the Laminar Project API Key in the Admin Console. + ```bash + helm upgrade --install openhands \ + --namespace openhands \ + oci://ghcr.io/all-hands-ai/helm-charts/openhands \ + -f site-values.yaml + ``` -![Laminar Deploy Again](./images/laminar-deploy-again.png) + Wait for the rollout to complete: -Wait for the deployment to complete. + ```bash + kubectl rollout status deploy/openhands -n openhands + ``` + + ## Start a conversation diff --git a/enterprise/k8s-install/index.mdx b/enterprise/k8s-install/index.mdx index 50b7fdd3..1cc08ef2 100644 --- a/enterprise/k8s-install/index.mdx +++ b/enterprise/k8s-install/index.mdx @@ -58,6 +58,10 @@ OpenHands Enterprise consists of several components deployed as Kubernetes workl Configure memory, CPU, and storage for optimal performance. + + Enable Laminar for LLM observability and tracing. See the **Helm (Kubernetes Install)** tab on each step. + + ## Request Access Kubernetes-based installation is currently available to select customers on request. diff --git a/enterprise/quick-start.mdx b/enterprise/quick-start.mdx index cf686e4b..bf1bcf1b 100644 --- a/enterprise/quick-start.mdx +++ b/enterprise/quick-start.mdx @@ -235,6 +235,7 @@ If any check fails, stop and resolve before continuing: | `30000/TCP` inbound | Replicated/KOTS Admin Console for install and configuration | | `80/TCP` inbound | HTTP entrypoint used for ingress/redirect behavior | | `*.runtime.` DNS + cert SAN | Runtime sandboxes are addressed by dynamic runtime-specific hostnames | +| `analytics.app.` DNS + cert SAN | Hosts the Laminar UI when [Analytics](/enterprise/analytics) is enabled. Include the SAN at install time so you do not need to re-issue the certificate later. | | `replicated.app`, `proxy.replicated.com` | Replicated control-plane/license/install paths | | `images.r9...`, `charts.r9...`, `updates.r9...`, `install.r9...` | Vendor distribution image/chart/update/install endpoints | | `traefik.github.io` | Embedded cluster ingress chart repository |