Appearance
30 minutter til første innsikt
Denne tutorialen tar en teknisk evaluator fra en ren installasjon av publiserte artefakter til den første survey-responsen synlig i dashboardet — uten å gå veien om produksjonsherdning. Målet er å bevise at hele kjeden fungerer på din egen infrastruktur før du investerer i en full utrulling.
Lokal-eval, ikke produksjonsoppskrift
Denne tutorialen bruker en lokal Keycloak som OIDC-provider for å gjøre evalueringen selvbetjent. Det betyr ikke at Keycloak er den anbefalte eller forventede enterprise-provideren. Når din virksomhet kjøper Lumi, kobler du typisk mot Entra ID eller en annen sentral IdP — se Entra ID-sporet nederst og OIDC-oppsett for provider-detaljer.
Bruk dette løpet til å validere produktet, ikke som mal for prod-arkitektur.
Verifisert ende-til-ende
Løpet under er kjørt mot et disposable kind-cluster fra de publiserte artefaktene: OIDC-login, setup-wizard, innsendingskontrakten med origin-validering (samme V2-payload som widgeten sender via transport.submit, verifisert direkte mot API-et), og responsen synlig i dashboardet. Selve widget-rendringen i nettleser er ikke del av det beviset. Stegene beskriver observert oppførsel — der lokal-oppsettet krever en snarvei et produksjonscluster ikke trenger, er det merket kind-only.
Hva du trenger
| Krav | Detalj |
|---|---|
| Kubernetes-cluster | Et engangs-/disposable cluster holder (kind, minikube, k3s). 4 GB RAM ledig. Både linux/amd64 og linux/arm64 støttes — verifiser multi-arch-manifestene i Fase 0. |
kubectl + helm | Helm 3.14+. |
| GHCR-tilgang | Et Personal Access Token (PAT) til ghcr.io — se Fase 0. |
| Docker med buildx | For multi-arch-preflight-sjekken i Fase 0 (docker buildx imagetools). |
| Realm-fixture | lumi-realm.json — følger med evalueringstilgangen, brukes i Fase 1. |
| Node 20+ | For å bygge widget-vert-appen i Fase 4. |
openssl | For å generere sessionSecret. |
Tidsbudsjettet under forutsetter at clusteret allerede kjører. Selve clusteret (kind create cluster) er ikke regnet inn i de 30 minuttene.
OIDC-provideren må være på plass før Lumi installeres — chartet validerer at issuer-verdiene er ikke-tomme når authProvider=oidc, og rendringen feiler ellers. Derfor settes Keycloak opp i Fase 1, før Helm-installasjonen i Fase 2.
| Fase | Hva | Tid |
|---|---|---|
| 0 | Tilgang til artefakter | 5 min |
| 1 | Sett opp lokal Keycloak | 8 min |
| 2 | Installer Lumi med Helm | 8 min |
| 3 | Kjør setup-wizarden | 3 min |
| 4 | Koble widgeten mot API-et | 4 min |
| 5 | Se den første responsen | 2 min |
Fase 0: Tilgang til artefakter (5 min)
Alle Lumi-imager og Helm-chartet er private GHCR-pakker. Før noe kan installeres må du logge inn mot ghcr.io med et token du har fått utlevert.
Credential-utlevering
For en pilot-evaluering utleverer vi GHCR-tilgangen (PAT med read:packages) og realm-fixturen lumi-realm.json direkte til deg — self-serve-evaluering uten manuell utlevering er ikke på plass. Hold tokenet utenfor shell-historikk og committede filer.
Logg inn mot OCI-registeret for å hente chartet (read:packages er nok):
sh
echo "$GHCR_TOKEN" | helm registry login ghcr.io -u <din-bruker> --password-stdinForventet utskrift: Login Succeeded.
Opprett namespace og en image-pull-secret slik at podene kan hente de private imagene:
sh
kubectl create namespace lumi
kubectl create secret docker-registry ghcr-pull \
--namespace lumi \
--docker-server=ghcr.io \
--docker-username=<din-bruker> \
--docker-password="$GHCR_TOKEN"Pre-flight: verifiser at runtime-imagene dekker din plattform. Spesielt viktig på arm64-noder — et image som mangler plattformen din gir ImagePullBackOff med no match for platform in manifest først ved install:
sh
echo "$GHCR_TOKEN" | docker login ghcr.io -u <din-bruker> --password-stdin
docker buildx imagetools inspect ghcr.io/asorheim/lumi-analytics/lumi-api:1.0.0
docker buildx imagetools inspect ghcr.io/asorheim/lumi-analytics/lumi-dashboard:1.0.0Forventet: begge manifestene lister både linux/amd64 og linux/arm64. Mangler en plattform: stopp og ta kontakt før du installerer.
Hvis det feiler:
denied/403påhelm registry login→ PAT-en manglerread:packages, eller du er ikke gitt tilgang til pakkene. Ta kontakt for ny utlevering.unauthorizedsenere påhelm pull→ du logget inn mot feil bruker, eller tokenet er utløpt.
Fase 1: Sett opp lokal Keycloak (8 min)
For en selvbetjent evaluering kjører vi en lokal Keycloak i clusteret og bruker den som IdP. Lumi-API-et trenger issuer-URL-en herfra allerede i Fase 2, så Keycloak settes opp først.
Prinsippet som styrer hele OIDC-oppsettet: den robuste konfigurasjonen er én issuer-URL som når Keycloak likt fra både podene og nettleseren, slik at iss-claimet er identisk i nettleserens login-redirect og i den server-side kodevekslingen. Lokalt løses det med verts-navnet keycloak.127.0.0.1.nip.io — nip.io slår opp til 127.0.0.1, så nettleseren treffer en port-forward, mens podene rutes til Keycloak-Service-en via en hostAliases-snarvei (kind-only, Fase 2). I produksjon er dette automatisk: én offentlig IdP-URL som både cluster og brukere når.
Realm, client, mappere, grupper og test-brukere importeres fra fixturen lumi-realm.json — ingen manuelle admin-konsoll-klikk. Opprett en ConfigMap fra fixturen, og deploy en utviklings-Keycloak som importerer den ved oppstart:
sh
kubectl -n lumi create configmap lumi-realm --from-file=lumi-realm.json
kubectl -n lumi apply -f keycloak.yamlder keycloak.yaml er:
yaml
# Disposable Keycloak for lokal evaluering. IKKE for produksjon.
apiVersion: apps/v1
kind: Deployment
metadata:
name: keycloak
namespace: lumi
labels: { app: keycloak }
spec:
replicas: 1
selector:
matchLabels: { app: keycloak }
template:
metadata:
labels: { app: keycloak }
spec:
containers:
- name: keycloak
image: quay.io/keycloak/keycloak:26.2
args: ["start-dev", "--import-realm"]
env:
- { name: KC_BOOTSTRAP_ADMIN_USERNAME, value: "admin" }
- { name: KC_BOOTSTRAP_ADMIN_PASSWORD, value: "admin" }
- { name: KC_HEALTH_ENABLED, value: "true" }
ports:
- { name: http, containerPort: 8080 }
- { name: mgmt, containerPort: 9000 }
readinessProbe:
httpGet: { path: /health/ready, port: 9000 }
initialDelaySeconds: 20
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 48
volumeMounts:
- { name: realm-import, mountPath: /opt/keycloak/data/import, readOnly: true }
volumes:
- name: realm-import
configMap:
name: lumi-realm
---
apiVersion: v1
kind: Service
metadata:
name: keycloak
namespace: lumi
labels: { app: keycloak }
spec:
selector: { app: keycloak }
ports:
- { name: http, port: 8080, targetPort: 8080 }Vent til Keycloak er klar (boot + realm-import tar et par minutter), og start port-forwarden som nettleseren skal bruke. La den stå i en egen terminal gjennom hele evalueringen — issuer-URL-en avhenger av den:
sh
kubectl -n lumi rollout status deploy/keycloak
kubectl -n lumi port-forward svc/keycloak 8080:8080Issuer-URL-en for resten av tutorialen er dermed http://keycloak.127.0.0.1.nip.io:8080/realms/lumi.
Fixturen definerer alt resten av tutorialen trenger:
- realm
lumimed public clientlumi-dashboard(standard flow + PKCE S256) - Audience-mapperen (
aud: lumi-dashboard) og Group Membership-mapperen (claimgroups, full path av) — de to claimene API-et validerer, og som en default OIDC-client ikke sender - gruppene
lumi-admins(matcheradminGroupi Fase 2) ogteam-alpha - tre disposable test-brukere, inkludert
[email protected](medlem avlumi-admins) som du logger inn med i Fase 3
Fixturen er insecure-by-design — kun for lokal evaluering
lumi-realm.json er selv-merket «LUMI INSTALL PROOF — NOT FOR PRODUCTION», og skal aldri importeres i en tenant som møter ekte brukere:
- Test-brukerne (
[email protected],[email protected],[email protected]) har hardkodet passordtest. - Den konfidensielle
lumi-service-clienten har hardkodet secret. Den finnes kun for API-ets integrasjonstester; dashboard-login trenger den ikke. - Realmet bruker
sslRequired: "external"slik at localhost-HTTP fungerer.
Clienten lumi-dashboard er dessuten pinnet til redirect-URI http://localhost:3000/* — det passer denne tutorialen (dashboardet port-forwardes på 3000 i Fase 3), men en produksjons-IdP må settes opp med ditt reelle dashboard-host. For produksjon: opprett et tomt realm i din egen IdP og repliser de to mapperne — se OIDC-oppsett → Keycloak-oppsett.
Trenger du å inspisere realmet, er admin-konsollet tilgjengelig på http://localhost:8080 (admin / admin) mens port-forwarden kjører.
Fase 2: Installer Lumi med Helm (8 min)
Chartet publiseres som OCI-artefakt. Versjon 1.0.1 er den verifiserte chart-versjonen for launch; API- og dashboard-imagene peker fortsatt på 1.0.0 via chartets appVersion.
Lag en eval-values.yaml med samme issuer-URL for API og dashboard — single-issuer er den verifiserte konfigurasjonen:
yaml
# eval-values.yaml
global:
imagePullSecrets:
- name: ghcr-pull
api:
image:
tag: "1.0.0"
# Sett digest fra release-audit for produksjonspinning:
# digest: sha256:API_IMAGE_DIGEST_FROM_RELEASE_AUDIT
env:
lumiEnv: production
authProvider: oidc
oidcIssuerUrl: http://keycloak.127.0.0.1.nip.io:8080/realms/lumi
oidcAudience: lumi-dashboard
dashboardClientId: lumi-dashboard
adminGroup: lumi-admins
dashboard:
image:
tag: "1.0.0"
# Sett digest fra release-audit for produksjonspinning:
# digest: sha256:DASHBOARD_IMAGE_DIGEST_FROM_RELEASE_AUDIT
env:
authProvider: oidc
oidcIssuerUrl: http://keycloak.127.0.0.1.nip.io:8080/realms/lumi # SAMME url som API-et
# oidcBrowserIssuerUrl: bevisst usatt — single-issuer
oidcClientId: lumi-dashboard
oidcRedirectUri: http://localhost:3000/auth/callback
secret:
sessionSecret: SESSION_SECRET_PLACEHOLDER
postgresql:
auth:
password: POSTGRES_PASSWORD_PLACEHOLDER
valkey:
auth:
password: VALKEY_PASSWORD_PLACEHOLDER
ingress:
enabled: falseSplit-issuer er ikke wet-run-verifisert — bruk single-issuer
Chartet eksponerer dashboard.env.oidcBrowserIssuerUrl for split-horizon-oppsett (én issuer-URL for nettleseren, en annen for podene). Konfigurasjonen er støttet i koden (discovery hentes fra server-issueren; browser-issueren brukes kun i login-redirecten), men den er ikke verifisert ende-til-ende slik single-issuer-løpet i denne tutorialen er. Hold deg til single-issuer for evalueringen; split-horizon er kun aktuelt når IdP-en genuint har to adresser. Merk at API-ets oidcIssuerUrl uansett må matche iss-claimet IdP-en stempler — se OIDC-oppsett → split-networking for detaljene.
Generer hemmelighetene og installer:
sh
sed -i.bak \
-e "s|SESSION_SECRET_PLACEHOLDER|$(openssl rand -base64 32)|" \
-e "s|POSTGRES_PASSWORD_PLACEHOLDER|$(openssl rand -hex 24)|" \
-e "s|VALKEY_PASSWORD_PLACEHOLDER|$(openssl rand -hex 24)|" \
eval-values.yaml && rm eval-values.yaml.bak
helm install lumi oci://ghcr.io/asorheim/lumi-analytics/charts/lumi \
--version 1.0.1 \
--namespace lumi \
-f eval-values.yamlForventet utskrift: STATUS: deployed.
Kind-only: pek podene på Keycloak-hostnavnet
keycloak.127.0.0.1.nip.io slår opp til 127.0.0.1 — riktig for nettleseren (port-forwarden fra Fase 1), men feil inne i podene. Legg inn en hostAliases-oppføring som ruter hostnavnet til Keycloak-Service-en, rett etter helm install:
sh
KC_IP=$(kubectl -n lumi get svc keycloak -o jsonpath='{.spec.clusterIP}')
kubectl -n lumi patch deploy lumi-api --type=strategic -p "{\"spec\":{\"template\":{\"spec\":{\"hostAliases\":[{\"ip\":\"$KC_IP\",\"hostnames\":[\"keycloak.127.0.0.1.nip.io\"]}]}}}}"
kubectl -n lumi patch deploy lumi-dashboard --type=strategic -p "{\"spec\":{\"template\":{\"spec\":{\"hostAliases\":[{\"ip\":\"$KC_IP\",\"hostnames\":[\"keycloak.127.0.0.1.nip.io\"]}]}}}}"Et produksjonscluster trenger ikke dette — en reell, offentlig IdP-URL løses likt av DNS overalt.
Etter ~1–2 minutter skal podene være oppe:
sh
kubectl -n lumi get podsForvent Running på lumi-api, lumi-dashboard, lumi-postgresql-0 og lumi-valkey-*. API-et kjører Flyway-migrasjonene automatisk ved oppstart.
Verifiser at API-et er friskt via det interne Prometheus-endepunktet (merk: stien er /internal/prometheus, ikke /metrics). Service-en eksponerer port 80, så port-forwarden mapper dit:
sh
kubectl -n lumi port-forward svc/lumi-api 8081:80 &
curl -s http://localhost:8081/internal/prometheus | head -5
kill %1 # stopp forwarden; Fase 4 starter den på nyttProduksjon: ikke inline secrets i values
Denne tutorialen skriver genererte hemmeligheter rett inn i values-filen — greit for et disposable eval-cluster, ikke for produksjon. Chartet støtter existingSecret-referanser for API, dashboard, PostgreSQL og Valkey (api.existingSecret, dashboard.existingSecret, postgresql.auth.existingSecret, valkey.auth.existingSecret), slik at SOPS, sealed-secrets eller plattformens secret-manager eier runtime-Secretene. Se charts/lumi/values.yaml for nøkkel-navnene og oppgraderingsguiden for rotasjonsregelen.
Hvis det feiler:
helm installaborterer med f.eks.api.env.oidcIssuerUrl (required when authProvider=oidc) must be set to a non-empty value(template-feil ved render) → en påkrevd OIDC-verdi ieval-values.yamler tom. Dette skjer før noen pod startes. Sjekk at alle de OIDC-påkrevde verdiene (oidcIssuerUrl,oidcAudience,oidcClientId,oidcRedirectUri,adminGroup,sessionSecret) har ikke-tomme verdier.ImagePullBackOff→ pull-secreten fra Fase 0 mangler eller er i feil namespace. Sjekkkubectl -n lumi get secret ghcr-pull.CrashLoopBackOffellerPending-readiness på API/dashboard etter oppstart → podene når ikke Keycloak på issuer-URL-en. Sjekk athostAliases-patchen over er lagt inn (kind-only), at Keycloak kjører (kubectl -n lumi get pods), ogkubectl -n lumi logs deploy/lumi-api.- Postgres-poden henger på
Pending→ clusteret mangler en default StorageClass.kindogminikubehar en; bare-metal kan trenge én.
Fase 3: Kjør setup-wizarden (3 min)
Port-forward dashboardet på port 3000 — det er porten både oidcRedirectUri i values og fixturens redirect-URI er pinnet til:
sh
kubectl -n lumi port-forward svc/lumi-dashboard 3000:80Åpne http://localhost:3000 og logg inn med test-brukeren fra fixturen: [email protected] / test (medlem av lumi-admins). Første gang havner du i /setup-wizarden, som tar deg gjennom fire steg:
- Organisasjon — oppretter organisasjonen og det første teamet; team-slugen blir
default— den brukes i Fase 5. - API-nøkler — opprett en Publishable (pk)-nøkkel her. Nye pk-nøkler krever en tillatt origin: sett Applikasjonens origin til
http://localhost:5173(det er der widget-vert-appen kjører i Fase 4). Kopierlumi_pk_live_...-verdien som vises; den vises bare én gang. - Embed widget — viser et kodesnutt-utgangspunkt. Fase 4 under bruker en herdet variant av samme snutt, så du kan gå videre.
- Ferdig — du lander i dashboardet.
En bruker i lumi-admins-gruppen (matcher adminGroup fra Fase 2) får org-admin-UI-et, og dashboardet er tomt til den første innsendingen kommer — det er Fase 4–5. Nøkler kan administreres senere under Innstillinger → API-nøkler.
For å koble Keycloak-grupper til Lumi-team (f.eks. team-alpha fra fixturen), følg OIDC-oppsett → Mappe Keycloak-grupper til Lumi-team.
Fase 4: Koble widgeten mot API-et (4 min)
Widgeten er publisert på npm som @lumianalytics/survey. Lag en minimal React-app som vert (f.eks. med Vite, som kjører dev-serveren på http://localhost:5173), og installer pakken pinnet til den verifiserte launch-versjonen:
sh
npm install @lumianalytics/[email protected]Widget-verten poster til API-et på et eget localhost-opphav. Port-forward API-tjenesten (service-port 80) i en egen terminal:
sh
kubectl -n lumi port-forward svc/lumi-api 8081:80Rendre LumiSurveyDock med publishable-nøkkelen fra Fase 3:
tsx
import {
LumiSurveyDock,
DEFAULT_SURVEY_RATING,
type LumiSurveyTransport,
} from "@lumianalytics/survey";
import "@lumianalytics/survey/styles.css";
const transport: LumiSurveyTransport = {
async submit(submission) {
const res = await fetch("http://localhost:8081/api/v1/submission", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": "lumi_pk_live_...",
},
body: JSON.stringify(submission.transportPayload),
});
// fetch resolverer også på 403/500 — kast slik at widgeten viser
// feiltilstand i stedet for falsk suksess.
if (!res.ok) {
throw new Error(`Innsending avvist: ${res.status}`);
}
},
};
export function App() {
return (
<LumiSurveyDock
surveyId="eval-rating"
survey={DEFAULT_SURVEY_RATING}
transport={transport}
/>
);
}Origin-en http://localhost:5173 må være registrert som tillatt opprinnelse på pk-nøkkelen (det gjorde du i Fase 3) — API-et validerer Origin-headeren og avviser ukjente opphav med 403 Forbidden. Se Produksjonsherdning for hvordan origin-validering fungerer.
Produksjon: samme host, ingen egen port-forward
Port-forwarden over er eval-stien. I produksjon ruter chartets ingress både dashboard og API på samme host — / til dashboardet og /api til API-tjenesten — så widgeten poster til https://dashboard.example.com/api/v1/submission uten et eget opphav å sette opp. Dashboardet proxyer ikke innsendinger.
Start vert-appen (npm run dev), åpne http://localhost:5173, og fyll ut surveyen som dukker opp nederst.
Hvis det feiler:
403 ForbiddenmedOrigin not allowed for this key→http://localhost:5173er ikke registrert som tillatt opprinnelse på pk-nøkkelen. Legg den til under Innstillinger → API-nøkler og prøv igjen.
Fase 5: Se den første responsen (2 min)
Gå tilbake til dashboardet på http://localhost:3000, åpne Tilbakemeldinger for teamet ditt (slug default fra Fase 3), og bekreft at responsen du nettopp sendte vises.
Suksesskriterium — du er ferdig når: svaret fra Fase 4 er synlig i dashboardet, med riktig spørsmål og tidsstempel, filtrerbart på tidsperiode.
Entra ID og andre providere
Denne tutorialen brukte lokal Keycloak for å gjøre evalueringen selvbetjent. For en faktisk enterprise-utrulling kobler du mot din sentrale IdP:
- Entra ID — det vanligste enterprise-sporet. Et live-verifisert Entra-avsnitt (audience,
groups-claim, admin-gruppe, team-mapping mot en ekte tenant) legges til her som et eget spor når det er verifisert. Behandl ikke Keycloak-løpet over som Entra-oppskrift. - Auth0 / Okta — kildeverifiserte konfigurasjonsnotater finnes i OIDC-oppsett, men er ennå ikke E2E-verifisert.
Neste steg
- Produksjonsherdning — origin-validering, nøkkelrotasjon og sikkerhetskontekster før du går videre fra eval.
- Distribuer Lumi — full referanse for Helm- og Compose-oppsett, miljøvariabler og image-mirroring.
- OIDC-oppsett — provider-spesifikk client- og mapper-konfigurasjon.
- Releaseverifisering — hvordan artefaktene du installerte er bygget og signert.
