The Scouting MBG photos (immich) will log in through this authentik,
which later passes on Scouts Online. The provider issues immich_role and
immich_quota: admins and the members of "MBG kader" may upload (-1),
everyone else gets a quota of 0, which makes immich refuse uploads.
"MBG leden" and "MBG kader" are filled by the Scouts Online source in a
next step; until then only authentik Admins can use the app.
The scouting blueprints and their secrets are mounted as directories
rather than with subPath, and the blueprint reads the client secret with
!File instead of !Env, so later changes reach authentik without a restart.
Actual Budget, Argo CD, FreshRSS, Stalwart and Vault had no policy
binding, so any authentik user could sign in to them. Scouts Online
members are about to get accounts in this authentik for immich; bind
each app to the authentik Admins group, as Longhorn already was.
immich 3 drops pgvecto.rs, which the database no longer uses since the
move to PostgreSQL 17 with VectorChord 1.1.1 (supported range >=0.3 <2)
and pgvector 0.8.6 (>=0.7 <0.9). None of the removed environment
variables are set here. The mobile app cannot pass sol-auth, so there are
no app clients to upgrade first.
Charts after 0.12.0 are only published to the OCI registry. Since 0.13.0
the chart validates its values, and emptyDir volumes no longer accept
size, accessMode or storageClass; they did nothing anyway. Valkey follows
the chart's new default, 9.1.2. Each component now gets its own
ServiceAccount without a mounted token.
Safety net: Longhorn snapshot immich-pg17-pre-v3 and a pg_dump in
~/immich-pg17-pre-v3.dump on opti1, since immich cannot be downgraded.
When a backend closes a kept-alive connection just as Envoy sends a
request over it, Envoy returns a 503 (response flag UC) and does not
retry by default. ingress-nginx retried these, so the race never showed.
The Apache in front of immich (sol-auth) recycles its processes after 30
connections, which made this happen during page loads: three chunks got
a 503 and immich failed with "error loading dynamically imported module".
authentik and ntfy saw it too, less often.
Retry up to twice on connection failures and resets, for every route on
the Gateway.
v2.4.1 only accepts VectorChord >=0.3 <0.6 and refused to start on the new PostgreSQL 17 cluster with VectorChord 1.1.1; from v2.5.0 the range is >=0.3 <2. v2.7.5 is the last 2.x release; the 3.x upgrade comes separately.
The import into immich-postgres-17 matched the old database table for table (assets, embeddings, faces, people, albums, migrations). On start immich builds its VectorChord indexes.
Imported once from the PostgreSQL 14 cluster, whose embeddings were converted to real[] and whose pgvecto.rs extension was dropped first (immich's manual migration). After the import the columns become vector(512) again under VectorChord 1.1.1 with pgvector 0.8.6. A logical import because CNPG can't upgrade in place from the bullseye-based pgvecto.rs image to the bookworm-based VectorChord one.
The database moves from PostgreSQL 14 with pgvecto.rs to a new PostgreSQL 17 cluster with VectorChord. Immich 3 no longer supports pgvecto.rs, and PostgreSQL 14 reaches end of life on 2026-11-12.
With them only Longhorn's own components can reach the longhorn-manager API, which any pod could otherwise call without authentication to manage volumes. 1.12 was kept off because its instance-manager policy left the host-side iSCSI initiator out; 1.13 opens port 3260 to any source while v1DataEngineInitiatorSourceCIDRs is empty.
Drops the label tracking pin kept through the 3.x upgrades, so Argo CD uses its default argocd.argoproj.io/tracking-id annotation. Labels can be copied by other tools (cert-manager's ingress-shim copied app.kubernetes.io/instance onto Certificates); the annotation names the exact resource. Every app gets synced once right after, so resources removed later are still recognised for pruning.
configMapGenerator gives every config change a new gatus-config-<hash> ConfigMap, and without prune the old one stayed behind and left the app OutOfSync.
Each poll updates the backupvolume objects, which made up about 8% of the k8s-dqlite writes at the 300s interval. The recurring backup runs once a night, so 30 minutes is plenty.
Nothing deploys disable/: the apps in it (ente-photos, minio, mist, owntracks, traccar, ttrss, whisper and others) are gone from the cluster apart from some old TLS secrets. git history keeps them. The argocd-cm patch copy was an old leftover that kustomize never used.
Nothing changes in microk8s between 1.35 and 1.36 for this setup. The stable channels lag upstream patches, including the CVE-2026-2270 fix, so the snap gets held and patch updates become a deliberate step.
1.13 needs Kubernetes 1.34 or later. It adds a longhorn-global-manager Deployment, set to one replica on this single node, and by default lets the CSI controller read every Secret for provisioner-secret StorageClass parameters; neither StorageClass uses those, so that grant stays off.
First step from 1.11.2 to 1.13 now that the cluster runs Kubernetes 1.35. The internal NetworkPolicies that 1.12 enables by default stay off: Calico would enforce them, and the instance-manager policy only admits Longhorn pods while the iSCSI initiator connects from the host.
Also lifts the Renovate hold below 1.11.3, which only existed for Kubernetes 1.33.
No breaking changes for this setup: the chart renders the same resources and server flags, and chart 12 only dropped the Bitnami kubectl image from the CRD hook, which stays off because Argo CD applies the CRDs. The AWS plugin goes to v1.14.4, the line for Velero 1.18.
1.17 drops restic, which nothing here uses (all 411 pod volume backups and 20 repositories are kopia), and moves the maintenance job settings from server flags into the velero-repo-maintenance ConfigMap, which the chart now renders with keepLatestMaintenanceJobs: 3. The AWS plugin goes to v1.13.2, the line for Velero 1.17.
3.5 is tested on Kubernetes 1.32 to 1.36; 3.4 stops at 1.35. It renders Helm charts with Helm 4.2.1 instead of 3.19; rendering all thirteen Helm apps with both gave the same manifests apart from whitespace, comments and document order.
dqlite supports VACUUM from v1.18.2, which microk8s 1.34 ships, but the dqlite shell wraps every statement in a transaction and SQLite refuses to VACUUM inside one. dqlite-vacuum sends it through the go-dqlite driver instead and otherwise just prints page statistics. dqlite-vacuum.sh makes the backups first.
Rehearsed on opti1 on a throwaway node in /dev/shm: 657 MB to 41 MB in 0.6s, with concurrent writes unaffected and the data intact after restarts.
v1.34.9 runs with the dqlite snapshot tuning intact. LIST latency is unchanged from 1.33, so the ConsistentListFromCache stalls of canonical/microk8s#5568 don't show here.
k8s-dqlite v1.8.1 in microk8s 1.34 already bundles dqlite 1.18.2, so the database can be vacuumed from 1.34 on. Also notes the containerd 2 jump at 1.35, the feature gates the 1.34 hook adds for kine, and the front-proxy certificate that expired in 2025.
Longhorn now sits behind an authentik login on the Gateway instead of nginx basic auth, so the check expects a 302 without following it. Same change for s1 on node001.
ingress-nginx is gone and every app is served by the Envoy Gateway. The certificates were created by cert-manager's ingress-shim and are owned by the Ingresses, so each app now declares its Certificate itself, with the same name, secret and usages, so nothing gets reissued. gateway-shim can't take over because the certificates live in the app namespaces.
immich drops mbg.hensen.io, which has no route, so that one certificate is reissued through the Gateway's HTTP-01 solver.
Also removes the Longhorn test-port redirect URI and updates comments that still described nginx.
Longhorn has no users of its own; nginx guarded it with basic auth using apr1 hashes, which Envoy Gateway does not support. An Envoy Gateway SecurityPolicy now sends visitors through an authentik OIDC application that only admins may use. The client secret lives in Vault at kv/longhorn-oidc and reaches both authentik and Envoy through External Secrets.
Envoy moves from the test ports to 80 and 443, and Let's Encrypt HTTP-01 challenges go through an HTTPRoute on the Gateway. Push only after sudo microk8s disable ingress, since both want the same host ports.
With server.insecure, TLS ends at nginx or Envoy and argocd-server serves plain HTTP, which is how Argo CD documents the Gateway API setup. The nginx Ingress now talks HTTP to the http port; the ssl-passthrough annotation did nothing without the controller flag. argocd-folder diffs server-side for the new HTTPRoute.
Each app gets an HTTPS listener on the Gateway with its existing certificate, an HTTPRoute, and a ReferenceGrant for that certificate. The routes drop Envoy's 15s request timeout, as nginx has no overall limit either. Argo CD and Longhorn follow separately; the Ingresses stay until the switch-over.
The API server fills in Gateway API defaults such as the parentRef group and kind and a PathPrefix / match, so Argo CD's client-side diff kept gateway-folder OutOfSync.
First app on the Gateway API: an HTTPS listener for s2.rubenhensen.nl using the existing certificate in the gatus namespace, an HTTPRoute, and a ReferenceGrant for the certificate. Plain HTTP on the Gateway now redirects to HTTPS. The Ingress stays until the switch-over.
Envoy runs as a DaemonSet on host ports 10080 and 10443 for now, so it can be tested next to ingress-nginx, which keeps 80 and 443. The Gateway has a plain HTTP listener and no routes yet.