docs: add Helm install path to enterprise Analytics guide#524
docs: add Helm install path to enterprise Analytics guide#524jpshackelford wants to merge 2 commits into
Conversation
Restructures enterprise/analytics.mdx into a single page with tabbed 'Replicated (VM Install)' vs 'Helm (Kubernetes Install)' sections for the two steps where the install paths actually diverge: - 'Enable Analytics' (KOTS checkbox vs site-values.yaml laminar: block plus env.LMNR_BASE_URL/LMNR_FORCE_HTTP keys, with options for pre-existing TLS secrets and cert-manager) - 'Deploy' (Admin Console redeploy vs helm upgrade + kubectl rollout) - 'Wire the API key into the install' (KOTS field + Save config vs env.LMNR_PROJECT_API_KEY + helm upgrade) The Laminar-side workflow (Keycloak login, create project, create ingest-only key, view traces) is shared between paths and stays outside the tabs. Helm-tab content is distilled from the OpenHands-Cloud chart values, the All-Hands-AI/deploy production reference, and the upstream lmnr-helm CONFIGURATION.md, with a Tip pointing AWS users at appServer.loadBalancer. Also: - enterprise/k8s-install/index.mdx: add Analytics card to Guides - enterprise/quick-start.mdx: add analytics.app.<domain> row to the 'Reasons for Requirements' table so the SAN is included at install time and customers don't have to re-issue certs later (complements PR #523 which added the row to the DNS table and preflight script) Co-authored-by: openhands <openhands@all-hands.dev>
Background detail (moved from PR description)Helm tab content — provenanceThe
Includes a ScreenshotsAll existing screenshots are reused as-is. The Replicated-only screenshots ( What this PR does not do
IA precedentThis is a small IA precedent that doesn't match the existing |
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
all-hands-bot
left a comment
There was a problem hiding this comment.
Well-structured documentation that successfully adds Helm install coverage for analytics. The tabs pattern works well, and the YAML configuration is comprehensive. Two suggestions for security best practices and clarity.
Was this automated review useful? React with 👍 or 👎 to this review to help us measure review quality.
Workflow run: https://github.com/OpenHands/docs/actions/runs/26460674595
| env: | ||
| LMNR_BASE_URL: "https://laminar-api.app.example.com" | ||
| LMNR_FORCE_HTTP: "true" | ||
| LMNR_PROJECT_API_KEY: "<paste-your-ingest-only-key-here>" |
There was a problem hiding this comment.
🟡 Suggestion: The main example shows the API key in plaintext YAML, which could lead users to commit secrets to version control. Consider showing the Secret-based approach as the primary example:
env:
LMNR_BASE_URL: "https://laminar-api.app.example.com"
LMNR_FORCE_HTTP: "true"
LMNR_PROJECT_API_KEY:
valueFrom:
secretKeyRef:
name: laminar-api-key
key: api-keyThen show how to create the secret:
kubectl create secret generic laminar-api-key \
-n openhands --from-literal=api-key='<your-ingest-only-key>'| - 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" |
There was a problem hiding this comment.
🟡 Suggestion: The config references a keycloak-realm secret that's created by the Replicated installer but may not exist in Helm installs. Add a note explaining where this comes from:
<Note>
The `keycloak-realm` secret is created automatically by the OpenHands Helm chart during initial install. If you need to update Keycloak configuration, see the [chart documentation](https://github.com/OpenHands/OpenHands-Cloud/blob/main/charts/openhands/README.md).
</Note>
all-hands-bot
left a comment
There was a problem hiding this comment.
Solid, well-structured addition. The tabbed layout cleanly separates the two install paths without duplicating the non-path-specific steps, the YAML examples are thorough and well-commented, and the cross-linking to prerequisites is accurate. Three inline suggestions below — none are blockers.
This review was generated by an AI agent (OpenHands) on behalf of the user through OpenHands Automation.
| enabled: true | ||
| global: | ||
| # Sets provider-specific defaults; not auto-detected. Use "gcp" or "aws". | ||
| cloudProvider: "gcp" |
There was a problem hiding this comment.
🟡 Suggestion: cloudProvider: "gcp" is a concrete value in a copy-paste snippet, but the comment only lists "gcp" or "aws" as valid options. Users on Azure or bare-metal may set this to an unsupported value silently and get unexpected defaults from the upstream lmnr-helm chart.
Consider either expanding the comment to list all valid values (or link directly to the relevant section of the lmnr-helm config guide), or use a placeholder like <gcp|aws> to make it clear this must be substituted:
| cloudProvider: "gcp" | |
| # Sets provider-specific defaults; not auto-detected. Valid values: "gcp", "aws". | |
| # See https://github.com/lmnr-ai/lmnr-helm/blob/main/CONFIGURATION.md for other environments. | |
| cloudProvider: "gcp" |
There was a problem hiding this comment.
Some customers will be in AWS? We may want to specify to the user with a comment specify your cloud provider AWS or GCP.
The cloud provider also impacts laminar storage. Customers might be using a different storage type than the default. Defaults are listed here in the laminar chart values https://github.com/lmnr-ai/lmnr-helm/blob/main/charts/laminar/values.yaml#L837. The GCP default pd-balanced was not available for us in the SaaS GKE cluster. For SaaS in GCP GKE, there's hyperdisk-balanced https://github.com/OpenHands/deploy/blob/main/openhands/envs/production/values.yaml#L183. I checked in the cluster and that was the storage class type available.
| name: keycloak-realm | ||
| key: client-secret | ||
| - name: AUTH_KEYCLOAK_ISSUER | ||
| value: "https://auth.app.example.com/realms/allhands" |
There was a problem hiding this comment.
🟡 Suggestion: The instructions above say "Replace example.com with your base domain" but don't address the allhands realm name in the issuer URL. If allhands is always the fixed Keycloak realm in OpenHands Enterprise, that should be stated explicitly so users don't wonder whether it's a placeholder. If it can vary, it should be listed as a substitution alongside example.com.
A brief inline comment would resolve the ambiguity:
| value: "https://auth.app.example.com/realms/allhands" | |
| - name: AUTH_KEYCLOAK_ISSUER | |
| value: "https://auth.app.example.com/realms/allhands" # realm name is fixed as "allhands" in OpenHands Enterprise |
| helm upgrade --install openhands \ | ||
| --namespace openhands \ | ||
| oci://ghcr.io/all-hands-ai/helm-charts/openhands \ | ||
| -f site-values.yaml |
There was a problem hiding this comment.
🟡 Suggestion: The helm upgrade --install command here (and again at line 283) doesn't pin a chart version. Without --version, running this command at a later date will silently upgrade to whatever the latest OCI tag is at that time, which could introduce breaking changes in a production cluster.
Consider adding a note that users should pin the version to match what they originally installed, e.g.:
| -f site-values.yaml | |
| oci://ghcr.io/all-hands-ai/helm-charts/openhands \ | |
| --version <chart-version> \ # use the same version as your existing install; omit to upgrade to latest | |
| -f site-values.yaml |
Alternatively, a brief prose note like "If you want to stay on your current chart version, add --version <X.Y.Z>." would be sufficient.
The previous draft mirrored the All-Hands SaaS production values, which expose an external Laminar app-server ingress at laminar-api.app... . That's necessary for SaaS because the runtime fleet can span clusters, but it's over-specified for typical single-cluster Helm customers, who have no current multi-cluster installs. Update the Helm tab so the primary path uses the in-cluster Laminar Service for trace ingestion -- LMNR_BASE_URL=http://laminar-app-server-service, LMNR_FORCE_HTTP=true, LMNR_HTTP_PORT=8000 -- matching what the Replicated install does. This means customers only need ONE new DNS record and TLS SAN (the user-facing analytics.app.<base-domain> hostname) instead of two. Move the laminar.appServer.ingress / loadBalancer configuration into an <Accordion> labelled 'Advanced: expose the app-server externally (multi-cluster only)' so it's discoverable but doesn't pollute the default path. Also update the 'Wire the API key' Helm code block to reflect the new LMNR_BASE_URL value. Co-authored-by: openhands <openhands@all-hands.dev>
Revision: in-cluster ingest is now the default Helm pathJM pushed back on the previous draft: since we have zero multi-cluster customers, two new DNS records and two TLS SANs is over-specified. The Helm tab now mirrors what Replicated actually does — `LMNR_BASE_URL: "http://laminar-app-server-service\"\`, `LMNR_FORCE_HTTP: "true"`, `LMNR_HTTP_PORT: "8000"`, no `laminar.appServer` block. One new DNS record + TLS SAN for the user-facing Laminar UI (`analytics.app.`), matching the Quick Start row added in #523. The external app-server ingress / NLB pattern is preserved inside an `` labeled "Advanced: expose the app-server externally (multi-cluster only)" so it's discoverable but doesn't pollute the default path. Pushed in 05e582b. |
| 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" |
There was a problem hiding this comment.
If it is a one cluster setup then I think this is fine
| tls: | ||
| enabled: true | ||
| clusterIssuer: "" # see TLS options below | ||
| secretName: "laminar-frontend-tls" |
There was a problem hiding this comment.
The customer can reuse the openhands cert secret here instead
Problem Statement
enterprise/analyticsis 100% Replicated/KOTS — every step ("Enable Analytics" checkbox, "Save config", "Deploy") is a click in the Admin Console. Customers doing a Helm install into their own Kubernetes cluster (e.g. C3.ai on GKE — see slack thread) have no documented path; they edit a `site-values.yaml` and run `helm upgrade`.With more Helm-based installs coming, the analytics doc needs proper coverage for both paths.
Proposed Solution
Single page, single URL, with `` only on the install-specific steps. The Laminar-side workflow (Keycloak login → create project → create ingest-only key → view traces) is identical across paths and stays outside the tabs.
Three places get a tab block:
Also adds a cross-link card from `enterprise/k8s-install/index.mdx`, and an `analytics.app.` row to the Quick Start "Reasons for Requirements" table so the SAN is included at install time (complements #523).
See follow-up comment for content provenance, screenshot handling, and out-of-scope notes.
Checklist
This PR was created by an AI agent (OpenHands) on John-Mason's behalf.