Running Instances
An instance is one MeshWeaver portal: its own domain, its own database, and its own sign-in,
served by a dedicated Kubernetes namespace. Instances typically share one cluster, one container
registry and one PostgreSQL server — only the namespace, domain and database differ, so a code change
merged to main reaches all of them via self-update. They differ in data, branding, sign-in
configuration, and who may log in.
Where an estate's instances are declared
Not in any doc. Every estate keeps its instances as DATA in a private configuration repository:
one Hosting/Deployment record per instance, the GitSynced Spaces it serves, and the
per-environment overlays and operations lanes that act on them. That repository is configuration —
the actual data the instances keep — and is normally administered through the estate's control
instance, not edited by hand. It is not a documentation source and not a module source: platform
documentation lives here (Doc/Architecture) and in the module docs; code lives in the platform and
plugin repositories. The live view is the control instance's Deployments board.
Running an instance of your own? Nothing on this page needs changing. Read it for the model (below): how versions are read, how self-update works, and how instances are created and deleted.
What each instance actually runs — platform build, commit, framework identity, update policy and every module's coordinate — is not written down anywhere: every instance reports it to the control instance, hourly. See DeploymentInventory.
The rest of this page is the mechanism, and applies to any installation.
Shared platform (all cloud instances)
| Piece | Value |
|---|---|
| AKS cluster | <aks-cluster> (RG <aks-resource-group>, swedencentral) — private cluster; kubectl only via az aks command invoke |
| Container registry | meshweaver.azurecr.io (ACR), multi-arch images (amd64 + arm64) |
| Database server | <pg-server> — private Azure PG Flexible Server 16 + pgvector, VNet-injected (one database per instance) |
| Workload identity | One shared UAMI <portal-identity>, one federated credential per namespace, AcrPull on the ACR |
| App stack | .NET 10 · Blazor Server · Orleans · Microsoft.Extensions.AI |
| Backups | Managed PITR (14 days) + geo-redundant — see DatabaseBackups.md |
Versioning — how to read the live version
Each instance runs the ACR image tag its in-pod self-updater last rolled to — the CI build number
ci.<N>. To see what a namespace is actually running, open the Fleet Console (/Hosting/Console
on the control instance): it shows the RUNNING version per instance next to the newest the
self-updater has seen. The cluster read is the break-glass form
(OperatingFromThePortal):
az aks command invoke -g <aks-resource-group> -n <aks-cluster> --command \
"kubectl -n <namespace> get deployment memex-portal-deployment \
-o jsonpath='{.spec.template.spec.containers[0].image}'"
# → meshweaver.azurecr.io/memex-portal-ai:ci.<N>
Self-update (the version channel)
Merge to main → CI builds a multi-arch image to ACR (ci.<N>) → each portal's in-pod
self-updater polls ACR and patches its own Deployment to the new tag → migration Job runs → portal
rolls. No manual step per instance. This is why a red main blocks the rollout for every
instance, and why the merge gate requires green CI. Full model:
ReleaseStrategy.md.
A manual code push to one instance (bypassing self-update) is a Roll Hosting/InstanceAction
with the tag on the control instance; the operator runs the kubectl set image + rollout sequence
of DeploymentAKS.md for you.
Instance lifecycle — creating and deleting instances
There is no "create instance" / "delete instance" button in the portal today. An instance is provisioned with the deploy tooling, not from the running app — the control instance is where you run that tooling (or drive it over MCP), not a control plane that spins up other instances.
Create a new instance — full runbook in OnboardingNewEnvironment.md:
- Add the namespace to
portalNamespacesindeploy/aks/infra/main.bicep(creates its federated credential + AcrPull) and redeploy the identity module. - Create the instance's database on the shared
<pg-server>server. - Author the env's
values.<env>.yaml(host,MEMEX_DATABASENAME, TLS secret, AI + auth config,selfUpdate.azureClientId). - Run the env's
deploy.sh— helm install + PVCs + KVSecretProviderClass+ ingress + TLS.
🚨 Env folders live in the estate's PRIVATE configuration repository, not under
deploy/aks/envs/<env>/— their directory names are tenant identities (see Where an estate's instances are declared).deploy/aks/envs/example/in this repository is the reference template only.
- Wire sign-in redirect URIs + invitation/email config for the new domain.
Delete an instance:
helm uninstallthe release in its namespace, then delete the namespace (removes pods, PVCs, ingress, secrets).- Drop (or archive-then-drop) the instance's database on
<pg-server>— this is the only place its data lives, so back it up first (DatabaseBackups.md). - Remove the namespace from
portalNamespaces(drops its federated credential) and delete its DNS record + TLS cert + git-ignoredenvs/<env>/config.
Turning the control instance into a real control plane (create / tear down instances from the UI, calling the Azure + Helm APIs behind an admin gate) is a possible future feature, not a current capability.
The admin Instances tab (control instance only)
Admin app (/Admin) ▸ Instances lists every portal on the cluster live from the k8s API —
domain, namespace, running version (image tag), replica health — with per-instance Grafana/Loki log
deep links and a guided create-instance plan generator (commands only; nothing deploys itself).
The tab exists only on the control instance, doubly gated:
Instances:Enabled(config, defaultfalse) — the Settings menu item is not even created on an install that doesn't set it. In the Helm chart,instancesAdmin.clusterReaddrives BOTH this flag and the RBAC below; the control instance's env overlay sets ittrue; every other instance inherits the default.- Cluster-read RBAC (
instancesAdmin.clusterRead) — reading deployments/ingresses across namespaces needs a cluster-scoped grant, given only to the control instance (a tenant pod must not enumerate the cluster). Without it the tab (where enabled) shows "Cluster query unavailable".
Log links need Instances:GrafanaBaseUrl (Helm: instancesAdmin.grafanaBaseUrl) — the Grafana
Explore (Loki) deep link is built per namespace. Empty until the in-cluster Grafana
(monitoring ns, loki-grafana service) is exposed on a host.