Gå til innhold

Idriftsettelse: Kai Platform prod på ekte data⚓︎

Denne runbooken tar Kai Platform (v2) i prod fra hardkodet testdata til ekte data: API-et leser fra PostgreSQL og workeren kjører daglig synk + pipeline (seleksjon → dokumenter → ekstraksjon → regelkjøring). Den speiler oppsettet som allerede kjører i test (infrastructure/environments/test/main.tf).

Alt kode-/config-arbeidet ligger i PR-en som lukker AB#21247. Prod er config + bootstrap — ingen ny kode. Fordi promote-pipelinene for prod er trigger: none, skjer ingenting automatisk ved merge; hvert steg under kjøres manuelt av deg.

Rekkefølge er viktig

Kjør stegene i rekkefølge. Promoterer du image-ene (steg 5–6) før infra er applied (steg 3) og DB-en er bootstrappet (steg 4), krasjer app-ene ved oppstart (ValidateOnStart på Mimir/Websak, eller Postgres-tilkobling som timer ut).

Go-live-gate (AB#21247 AC#3)⚓︎

Saksbehandlere skal ikke se prod-resultater før noen har besluttet at de er til å stole på.

  • Godkjenner: Bjørn Kristian Punsvik (BK). (TODO: flytt til PO/fagansvarlig når det er avklart med teamet.)
  • Beslutning dokumenteres her når den er tatt: dato, hvem, og hva som ble verifisert (minst én ekte sak gjennom hele pipelinen med korrekt regelutfall).
  • Gate: ikke slipp saksbehandlere til prod-flaten før denne beslutningen er ført.
Dato Godkjent av Verifisert
2026-07-16 BK (Noone is using prod v2 atm so its safe to deploy) 2026-07-17: sak 26/23624 gikk hele pipelinen (CU-ekstraksjon → 3 tilbud med tilbudsdato+konfidens → regelutfall «Ikke godkjent: 3 tilbud, men nøyaktig 2 kreves»). Ekte data, korrekt regelutfall.

Prod-fakta⚓︎

Ting Verdi
Subscription b6eeed57-7d07-45d6-ac3d-147c5cf872f6 (pv-kai-prod)
Ressursgruppe rg-kai-platform-prod
Deploy-SP 5d4dc673-10b6-4f9d-81b6-d1543a81e646 (kai-azure-prod)
NAT-egress-IP (pip-ng-kai-prod) 51.107.216.52
PG-server / FQDN psql-kai-platform-prod / psql-kai-platform-prod.postgres.database.azure.com
Entra-admin-gruppe (= psql-login-bruker) kai-platform-db-admins-prod
App-principaler app-kai-platform-api-prod, app-kai-platform-worker-prod
Foundry (CU + chat) aif-kai-prod · https://aif-kai-prod.services.ai.azure.com
Websak (prod) base https://api.data.enova.no/websak · scope api://websak-api-authentication-prod.enovasf.onmicrosoft.com/.default
Mimir / Databricks (delt prod-instans) url https://adb-3890932255281591.11.azuredatabricks.net · warehouse abbe6bba5318fc3c

Manuelle forutsetninger (AB#21247 AC#4)⚓︎

Disse krever prod-privilegier og gjøres av en prod-admin. Kryss av før go-live.

  • [ ] pg-bootstrap — kjør pg-onetime-bootstrap.sql (steg 4 under). Oppretter api/worker-principalene, grants (inkl. CREATE ON DATABASE kai for worker → TickerQ ticker-schema), og forhåndsoppretter vector-extensionen.
  • [ ] Databricks-grantworker-managed-identity må ha lesetilgang til å spørre Mimir/Databricks-warehouset (SELECT/USE på production.gold + CAN_USE på warehouset). Ellers er workeren «healthy» men ReplikaSync/SakSeleksjon feiler (403). Api-en kaller IKKE Mimir (den leser kun ferdig-ekstraherte fakta fra Postgres) — kun worker-MI-en trenger denne granten.
  • [ ] Tenant-consent — admin-consent på prod-app-registreringene (Websak-scope m.m.), slik at Entra-token-flyten fungerer.
  • [ ] Websak-gruppemedlemskap — worker-MI-en må være medlem av (ha app-rollen på) websak-api-authentication-prod («user assignment required»). enable_worker_compute wirer app-rolle-tildelingen i modulen; bekreft at den faktisk ble opprettet.
  • [x] KV-secretwebsak-subscription-key (APIM-nøkkel; ikke [Required], men Websak-kall 401-er uten den) legges i prod-Key-Vault når Websak faktisk kalles.
  • [x] Foundry-deployment — prod bruker gpt-4.1, som allerede er Terraform-styrt på aif-kai-prod (infrastructure/prod/main.tffoundry_models_to_deploy). Ingen manuell handling. NB: test kjører på gpt-5.2-257303 (portal-opprettet, ikke i Terraform), så prod/test har modell-gap; å gjøre gpt-5.2 Terraform-styrt i begge miljøer spores i AB#21273 (Kai får egen AIF-konto eid av kai-platform).
  • [x] CU-analyzere deployet til prod — pipelinene deployer dem nå automatisk: kai-worker-promote kjører et deploy-cu-preDeployStep (som kai-azure-prod-SP-en) FØR ACR-retag, så analyzerne finnes i aif-kai-prod før worker-imaget som forventer dem rulles ut. En fersk CU-ressurs har ingen modelDeployments-defaults; verktøyet setter dem nå idempotent selv (før het det manuelt/portal). Forutsetning: kai-azure-prod-SP-en må ha direkte Cognitive Services Content Understanding Contributoraif-kai-prod — CU sin (preview) data-plane-RBAC honorerer KUN direkte bruker/SP-tildelinger, ikke gruppe-baserte (nested eller ei). Terraform-styrt (infrastructure/{prod,test}/main.tf, v1-rot). Uten den: ExtractDocument404 ModelNotFound.

Rulleut-steg⚓︎

Steg 1 — Merge PR-en (AB#21247)⚓︎

Endrer, alt i én PR:

  • src/Enova.Kai.Api/appsettings.Production.json — AIF-endepunkt (gpt-4.1).
  • src/Enova.Kai.Worker/appsettings.Production.json (ny) — AIF, Websak, CU (prod).
  • infrastructure/environments/prod/main.tfenable_worker_compute=true, api/worker ConnectionStrings__kai + blob-URI, db_admin_upns, backend_app_role_group_member_upns, NAT-IP i prod_trusted_ips.

Merge er trygt — ingenting deployes til prod automatisk. appsettings.Production.json lastes kun når ASPNETCORE_ENVIRONMENT=Production (kun prod), så test er urørt.

Steg 2 — (ingen)⚓︎

Steg 3 — La kai-infra apply prod⚓︎

Kjør/godkjenn kai-infra-promote. Oppretter/oppdaterer app-settings for api+worker, firewall-regelen for NAT-IP-en, kai-platform-db-admins-prod-gruppen + AD-admin, og worker-compute. Prod krever godkjenning; kjører som kai-terraform-prod-SP-en.

  • Se opp for azuread_group_member «already exists» hvis prod-gruppene har manuelle medlemmer (traff oss i test) — fjern/importer dem og kjør på nytt.

Steg 4 — Én-gangs DB-bootstrap (kjøres én gang, som prod-team-admin)⚓︎

Bruk kai-postgres-connect-skillen. Koble som gruppenavnet mot postgres-DB-en:

PowerShell
$env:PGPASSWORD = az account get-access-token --resource https://ossrdbms-aad.database.windows.net --query accessToken -o tsv
psql "host=psql-kai-platform-prod.postgres.database.azure.com port=5432 dbname=postgres user=kai-platform-db-admins-prod sslmode=require" -v ON_ERROR_STOP=1 -v api_principal=app-kai-platform-api-prod -v worker_principal=app-kai-platform-worker-prod -f infrastructure/modules/kai-platform/scripts/pg-onetime-bootstrap.sql
  • Din egen laptop-IP må ligge i prod_trusted_ips for å koble (BK sin hjemme-IP er der).
  • Gruppe-sync mynter individuelle UPN-roller ~30 min etter enable; frem til da bruk gruppenavnet som psql-bruker (funker alltid). Idempotent.

Steg 5 — Deploy worker⚓︎

Kjør/godkjenn kai-worker-promote til prod → workeren migrerer DB-en på oppstart → /health 200. Se etter Applying N pending EF migrationsEF migrations appliedNow listening on :8080 i loggen. Bruk appservice-container-logs hvis den ikke kommer opp. (Worker først så schemaet finnes før api-en kobler.)

Promote deployer også CU-analyzerne (preDeployStep)

kai-worker-promote kjører deploy-cu mot prod FØR ACR-retag. Feiler det steget (manglende SP-rolle, brannmur), stopper promoten før imaget flippes — så en worker aldri peker på en analyzer som ikke er i CU. Se CU-forutsetningen i AC#4. En feilende promote her betyr som regel at kai-terraform-prod ikke har applyet CU-Contributor-rollen ennå (kjør den først), eller at agent-poolens egress-IP mangler i Foundry-brannmuren.

Steg 6 — Deploy api⚓︎

Kjør/godkjenn kai-api-promote til prod → /health 200.

Steg 7 — Verifiser⚓︎

Bash
curl -s -o /dev/null -w "%{http_code}\n" https://app-kai-platform-worker-prod.azurewebsites.net/health   # 200
curl -s -o /dev/null -w "%{http_code}\n" https://app-kai-platform-api-prod.azurewebsites.net/health      # 200

Deretter, mot ekte data:

  • API returnerer ekte saker (ikke FakeData-fixturene) på /cases.
  • Worker-loggen viser ReplikaSync og SakSeleksjon som kjører (Success: True).
  • Minst én ekte sak går hele pipelinen igjennom med korrekt regelutfall → før dette i go-live-gate-tabellen over.

Feller (alle truffet under test-idriftsettelsen)⚓︎

  • NAT-egress-IP i trusted_ips ellers timer tilkoblinger ut (brannmuren dropper, avviser ikke).
  • Mimir/Websak ValidateOnStart — manglende config krasjer app-en ved oppstart, før noen hosted service starter.
  • vector: CREATE EXTENSION krever azure_pg_admin; bootstrap forhåndsoppretter den.
  • Worker trenger CREATE ON DATABASE (TickerQ ticker-schema) — ligger i bootstrap.
  • Image/port: worker bruker aspnet-base-imaget med EXPOSE 8080 — ellers prober App Service :80 og evicter containeren i loop.
  • TickerQ-dashboard basic auth — sett Kai:TickerQ:Dashboard:Username/Password i prod for å unngå et uautentisert dashboard (logges som warning).
  • Foundry-brannmur = NAT-IP OG v2-subnett-VNet-regel. aif-kai-prod har default_action=Deny. Workeren når CU via NAT-egress-IP-en (ip_rules), MEN et subnett med Microsoft.CognitiveServices-service-endpoint treffer kontoen som en VNet-regel, ikke via den offentlige IP-en — så snet-kai-platform-prod-app må ligge i Foundry-kontoens virtual_network_rules. Bare NAT-IP-en → ExtractDocument 403 «Virtual Network/Firewall».
  • MI-token-cache ved redeploy. Managed-identity-token cacher roles-claimet. Etter en ny app-rolle-tildeling (Websak) eller RBAC-endring får MI-en først det nye claimet i et ferskt token — en redeploy/restart av app-en tvinger et nytt token. Symptom: 401 mot Websak som «magisk» forsvinner etter neste deploy.
  • Regelmotor-seed kjører ved worker-oppstart. RegelmotorSeedHostedService seeder regler+workflow i alle Postgres-miljøer ved boot (idempotent). Kjører Evaluation FØR seeden har landet (fersk DB, worker ikke startet ennå) → Ingen gyldig workflow for virkemiddel …. Ikke en bug i gyldig_fra (seeden bruker åpent vindu 2000-01-01); det er timing — reanalyser saken etter at workeren har seedet.

Avgrensning⚓︎

  • Prod kjører mot Postgres. Fjerningen av den tidligere InMemory-modusen fra koden er dekket av AB#21248 og er ikke en del av denne runbooken.
  • Migrering av aif-kai-prod + Websak-app-registreringen til kai-platform-Terraform er AB#21273 / AB#21275 (v1-avvikling). Runbooken peker på de v1-eide ressursene som de er i dag.