monitoring namespace:
Loki without Alloy stores nothing; Alloy without Loki has nowhere to push. The wizard installs them as separate steps so each has its own release state.
Install them in this order, and finish with a third step
1
Loki first
Alloy’s default push target is the in-cluster Loki service. Install it with no Loki present and the DaemonSet runs happily, reporting healthy, while dropping every line on the floor.
2
Then Alloy
Once Loki is Ready.
3
Then re-apply Monitoring with Loki enabled
This is the step people miss. Grafana only gains Loki as a datasource when the kube-prometheus-stack release is re-applied with Loki enabled — that wiring lives in the monitoring stack’s values, not in Loki’s own. Skip it and logs are stored, queryable through Celum, and absent from Grafana.
Alloy collects pod container output only. There is no journald or host-log source, so a kernel or kubelet problem visible in
dmesg on a node will never appear in Loki. Those stay a node-level investigation.It is also not the guest-cluster path: a tenant’s logs come from the in-guest Alloy add-on, which reports its own status.Configuration that matters
The status reports the desired configuration each release runs with:- Loki — storage class and size (e.g.
ceph-block,50Gi). Loki keeps every project’s and cluster’s logs until that volume is full, so its size is the only dial. The status still carries a retention period, which reads0s(keep forever) once Loki has been applied. The Loki step’s Retention period field is not applied: an apply that sends any value other than0sadds aLoki retentionrow that says so. - Alloy — the Loki endpoint it pushes to (the in-cluster service,
http://loki.monitoring.svc.cluster.local:3100) and the excluded namespaces whose logs are not collected (e.g.flux-system,cilium-secrets,tetragon-system) — high-churn system namespaces that would otherwise dominate the store.
Tenants
Loki is multi-tenant. Every write and every read names its tenant in theX-Scope-OrgID header, and Loki refuses a request that names none. Where a stream lands depends on who wrote it:
Readers name every tenant the streams can be under. Celum’s read of a guest cluster’s logs names the projects that hold a cluster of that name, the cluster’s own name, the supervisor and
fake. Grafana’s Loki datasource names every tenant of the supervisor: the supervisor, every project, every Cluster API cluster and fake. The Loki apply, the kube-prometheus-stack apply, project create and delete, and cluster create and delete keep that list current. Both lists are built from what exists now, so the logs of a deleted cluster or project stay in Loki and are no longer read.
Loki refuses writers that name no tenant: the Alloy of a guest whose project’s add-on catalogue is older than capi-addons 0.6.7, and a supervisor Alloy whose configuration has no tenant_id. The Loki apply names them in its Loki writers row. Edit one cluster in each namespace it names to move that catalogue, and apply the Alloy step for the supervisor’s Alloy.
An Alloy you point at another supervisor’s Loki (Loki push URL (override)) writes under tenants that supervisor’s Celum and Grafana do not read.
Logs from before tenancy
These apply Loki:
Re-apply chart on the kube-prometheus-stack panel does not apply Loki. It still closes the Loki port
8080 in project policies (see below) wherever the Loki route no longer goes to Loki’s retired NGINX gateway.
hr-status vs status
Both components expose two reads, and the distinction is the useful part:
The split mirrors the three-layer triage:
hr-status answers “did the chart land”, status answers “what is it configured to do” — and neither proves logs are actually arriving. For that, query a pod’s logs and check the source (below).
The tenant log read layer
Pod logs of a guest cluster, on the cluster’s Resources tab, are served Loki-first with live fallback:1
Loki first
The backend queries the supervisor’s Loki through the Kubernetes API server’s service proxy, never through the Gateway route, with a selector on cluster, namespace and pod (and container, when one is picked). The query names every tenant the cluster’s streams can be under (see Tenants) and returns up to 72 hours of history, including logs from pods that have since restarted or been rescheduled.
2
Live fallback
When Loki has nothing for the pod (shipping is off, or ingestion has not caught up), or the Loki read fails, the request falls back to the live kubelet log read. You never get less than the plain Kubernetes path would give you.
3
Source badge
The logs view labels each transcript with its source (
Loki · history or live), so a silent fallback is visible. A pod that should have history but shows live is your cue to check the shipping path.GET /api/clusters/<cluster>/workload-pod-logs takes source=auto (the default), loki or live. With loki it does not fall back: it returns an empty transcript and a note. Over MCP, get_cluster_pod_logs takes the same source. The supervisor’s own pod logs are not read from Loki: GET /api/supervisors/<supervisor>/pod-logs reads them live, and no page or MCP tool calls that route.
Guest clusters ship their logs with their own Alloy collectors pushing to the supervisor’s Loki. That path requires Loki to be published on the shared Gateway — guests are separate clusters and can only reach it via a routable hostname. Celum exposes the route automatically when Loki is installed; see Gateways & Routes. The route forwards /loki/api/v1/push only, to the loki Service on port 3100. It answers no query: Celum and Grafana read Loki inside the supervisor.
On a supervisor whose shared Gateway is Envoy Gateway and which has a usable secret store, the route also requires the guest’s project push credential, as basic auth, once every guest that runs the Logs add-on sends it. The Gateway then sets the Loki tenant to the guest’s project and removes the Authorization header before the request reaches Loki. The push credential describes the credential and when the requirement turns on; the Prometheus route follows the same rules.
Why a project’s network isolation does not already allow that push
This is the least intuitive thing on the page, and it costs an afternoon every time it is met fresh. A project namespace with network isolation gets an egress rule allowing traffic toworld — the public internet. A guest’s collector pushes to the Loki hostname on the shared Gateway, which is an address outside the cluster, so that rule looks like it covers the push. It does not.
The Gateway terminates TLS and hairpins the request back into the cluster, and the proxy policy-checks that upstream hop with the original client’s egress policy against the real backend pod identity — the Loki pod in the monitoring namespace, not world. A rule written for world never matches, the push is dropped at L7, and the shape of the failure is distinctive: the proxy answers 403 while the flow record reads verdict=DROPPED with the destination logged as the Gateway’s address. A collector then retries forever, producing a steady stream of denials and no logs.
On an Envoy Gateway supervisor, the guest’s first hop is the Gateway’s own Envoy proxy, a pod in envoy-gateway-system. A world rule does not match that pod either, and the isolation policy holds a hole for it as well.
The platform maintains that egress hole itself, so on a current release there is nothing to do. Two details matter if you are reading an older namespace or writing policy by hand:
- The hole opens one port,
3100. That is the port thelokiroute targets. Port8080on the Loki pod belongs to its rules sidecar, not to a Loki API, so the hole leaves it shut. Policies written by older releases still open8080: the next Loki or Monitoring apply removes it from every project isolation policy andallow-tenant-loki-pushhole, and reports it in the*/Loki egressrow (narrowed in N policies). While the Loki route still goes to Loki’s retired NGINX gateway, which listens on8080, the row readskept in N policiesuntil a Loki apply moves the route. - Do not hand-write the hole into a namespace that has no isolation policy. A CiliumNetworkPolicy with an empty
endpointSelectorflips every endpoint in that namespace to egress default-deny — so a “fix” applied to an open namespace creates the very lockout it was meant to relieve. The platform ties the two together for this reason: the hole is applied only where isolation exists, and removed with it.
What commonly breaks
Other recurring failure modes, in triage order:- Alloy not installed — logs views quietly serve
liveonly. The status panel shows the release absent. - Collector pods down — the Pod Security case above, or a node-level issue; either way the release is green and the DaemonSet is not.
- Guest push path broken — the guest’s collectors are healthy but the Loki route is missing or unreachable from the guest network; supervisor logs work, guest history does not.
- Guest push denied by policy — route present, collector healthy, and every push dropped. The flow record reads
DROPPEDagainst the Gateway’s address while the proxy answers403. See the section above: aworldegress rule does not cover a hairpinned push. - Guest push refused with
401: the Loki route requires the project’s push credential, and the guest sends none or a wrong one. Theloki-push-authrow of the next Monitoring or Loki apply readskept; failing for N guests that do not send the credentialand names each guest with the reason, such as a guest outside a project, an add-on rendered without the credential, or a credential Secret not delivered yet. See The push credential. - Pushes refused because they name no tenant: a guest whose add-on catalogue is older than capi-addons
0.6.7, or a supervisor Alloy without atenant_id. The Loki apply’sLoki writersrow names them; see Tenants. - History shorter than expected: Loki deletes no tenant’s logs except
fake’s, and the Retention period field plays no part. Missing history is either from before tenancy, which a Loki apply deletes once it is a day old, or from a cluster or project that no longer exists, whose logs Loki keeps and Celum and Grafana no longer read. - Logs exist in Celum but not in Grafana — the monitoring stack was never re-applied with Loki enabled, so Grafana has no Loki datasource. Nothing about Loki itself is wrong. If the datasource exists and one cluster or project is missing from it, its tenant is not in the datasource’s tenant list yet. Re-apply chart on the kube-prometheus-stack panel rewrites that list, and so does a Loki apply.
- A reader or writer of your own stops working: Loki refuses a request without
X-Scope-OrgID. On an Envoy Gateway supervisor, the Monitoring apply also admits only themonitoringnamespace, the nodes, the API server and the Gateway’s proxies to the Loki pod; see Direct access to Prometheus, Loki and Alertmanager. That includes Alloy inside a VM (the alpha Send system logs to Grafana), which writes to Loki’s in-cluster address. - Looking for kernel or kubelet messages — they are not collected. Alloy reads pod output only.
Permissions
Related
Platform health overview
Release state vs runtime state — the model this page applies.
Monitoring
The metrics half of the observability stack, same namespace.
Flow telemetry
Network flow data — a separate pipeline with its own freshness signal.
Gateways & Routes
The shared Gateway that guest log shipping depends on.