mirror of
https://github.com/rubenhensen/k8scd.git
synced 2026-11-15 14:29:09 +01:00
Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
506a3e33b3 | ||
|
|
b29616990c | ||
|
|
9f946d5e68 | ||
|
|
f08737c221 | ||
|
|
65858d3f0b | ||
|
|
b6be49b701 | ||
|
|
d6779a399f | ||
|
|
e042fdd8de | ||
|
|
e8145e12d7 | ||
|
|
3d1b7dd230 | ||
|
|
aaae182844 | ||
|
|
e0e64e1097 | ||
|
|
b4e992d092 | ||
|
|
6ee7fd6f5e | ||
|
|
7db73a100e | ||
|
|
40cd825602 | ||
|
|
bbb56e0e25 | ||
|
|
a4b09fc51e | ||
|
|
0589bb3e08 | ||
|
|
c298ad8746 | ||
|
|
fe105a4fa7 | ||
|
|
1afd4b6bbd | ||
|
|
b4663216db | ||
|
|
955c22c665 | ||
|
|
f7396b3cb7 |
No files matched your search
@@ -12,7 +12,7 @@ spec:
|
|||||||
project: default
|
project: default
|
||||||
source:
|
source:
|
||||||
repoURL: https://groundhog2k.github.io/helm-charts/
|
repoURL: https://groundhog2k.github.io/helm-charts/
|
||||||
targetRevision: 0.16.7
|
targetRevision: 0.16.8
|
||||||
chart: wordpress
|
chart: wordpress
|
||||||
helm:
|
helm:
|
||||||
values: |
|
values: |
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ spec:
|
|||||||
source:
|
source:
|
||||||
chart: plugin-barman-cloud
|
chart: plugin-barman-cloud
|
||||||
repoURL: https://cloudnative-pg.github.io/charts
|
repoURL: https://cloudnative-pg.github.io/charts
|
||||||
targetRevision: 0.8.1
|
targetRevision: 0.9.0
|
||||||
helm:
|
helm:
|
||||||
values: |
|
values: |
|
||||||
# CNPG's barman cloud plugin, which backs the PostgreSQL clusters
|
# CNPG's barman cloud plugin, which backs the PostgreSQL clusters
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ records:
|
|||||||
- name: "ldap"
|
- name: "ldap"
|
||||||
expire: 300
|
expire: 300
|
||||||
type: A
|
type: A
|
||||||
content: "62.41.86.27"
|
content: "62.41.86.53"
|
||||||
- name: "argocd"
|
- name: "argocd"
|
||||||
expire: 300
|
expire: 300
|
||||||
type: A
|
type: A
|
||||||
@@ -60,7 +60,7 @@ records:
|
|||||||
- name: "s2"
|
- name: "s2"
|
||||||
expire: 300
|
expire: 300
|
||||||
type: A
|
type: A
|
||||||
content: "62.41.86.27"
|
content: "62.41.86.53"
|
||||||
# ntfy for Gatus alerts, one next to each Gatus. Same reasoning as s2.
|
# ntfy for Gatus alerts, one next to each Gatus. Same reasoning as s2.
|
||||||
- name: "ntfy1"
|
- name: "ntfy1"
|
||||||
expire: 300
|
expire: 300
|
||||||
@@ -69,7 +69,7 @@ records:
|
|||||||
- name: "ntfy2"
|
- name: "ntfy2"
|
||||||
expire: 300
|
expire: 300
|
||||||
type: A
|
type: A
|
||||||
content: "62.41.86.27"
|
content: "62.41.86.53"
|
||||||
- name: "@"
|
- name: "@"
|
||||||
expire: 300
|
expire: 300
|
||||||
type: MX
|
type: MX
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ view, and everything is shared with everyone automatically.
|
|||||||
- **immich has no user groups**; albums are shared per user, as viewer or
|
- **immich has no user groups**; albums are shared per user, as viewer or
|
||||||
editor. The owner and editors of an album may add users and change
|
editor. The owner and editors of an album may add users and change
|
||||||
their roles. Search only covers your own photos and those of partners
|
their roles. Search only covers your own photos and those of partners
|
||||||
you show in your timeline.
|
you show in your timeline. People (face recognition) are per user too,
|
||||||
|
and a partner's library doesn't bring its people along; since 3.3 a
|
||||||
|
user can share people with the users in their cluster group.
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
@@ -46,7 +48,10 @@ view, and everything is shared with everyone automatically.
|
|||||||
every user into every album of the group account (`fotoupload@`), as
|
every user into every album of the group account (`fotoupload@`), as
|
||||||
editor or viewer by quota; the group account's library as a partner of
|
editor or viewer by quota; the group account's library as a partner of
|
||||||
everyone, shown in the timeline; album invitations for albums older than
|
everyone, shown in the timeline; album invitations for albums older than
|
||||||
a week hidden; sessions of OAuth users older than 30 days ended. Albums
|
a week hidden; sessions of OAuth users older than 30 days ended;
|
||||||
|
everyone in the group account's cluster group with its people shared
|
||||||
|
(names editable by those who may upload, added 2026-10-28, when nobody
|
||||||
|
but the group account could search by face). Albums
|
||||||
that kaderleden create get the group account as editor first (in the
|
that kaderleden create get the group account as editor first (in the
|
||||||
database, since the API only lets an album's owner or editors share
|
database, since the API only lets an album's owner or editors share
|
||||||
it), so they go to everyone too; names starting with "Privé"/"Prive"
|
it), so they go to everyone too; names starting with "Privé"/"Prive"
|
||||||
|
|||||||
+55
-27
@@ -1,22 +1,27 @@
|
|||||||
# Roadmap
|
# Roadmap
|
||||||
|
|
||||||
Where the cluster stands and what is left, as of 2026-10-25. Takes over
|
Where the cluster stands and what is left, as of 2026-10-28. Takes over
|
||||||
from wishlist.txt (January 2026, removed); its items are sorted in at the
|
from wishlist.txt (January 2026, removed); its items are sorted in at the
|
||||||
bottom.
|
bottom.
|
||||||
|
|
||||||
## State
|
## State
|
||||||
|
|
||||||
One node: opti1, an OptiPlex 5060 with an i5-8600T, 32 GB and one 1 TB
|
One node: opti1, an OptiPlex 5060 with an i5-8600T, 32 GB and one 1 TB
|
||||||
SATA SSD that is 72% full. microk8s v1.36.5 from 1.36/edge, snap held.
|
SATA SSD that is 54% full. microk8s v1.36.5 from 1.36/edge, snap held.
|
||||||
35 Argo CD apps (with metrics-server), all Synced/Healthy; every Longhorn
|
39 Argo CD apps (with metrics-server), all Synced/Healthy; every Longhorn
|
||||||
volume has one replica. authentik 2026.8.5, Vault 2.2.1. Backups go to the
|
volume has one replica. authentik 2026.8.5, Vault 2.2.1, immich 3.3.5 on
|
||||||
NAS (192.168.1.99): Longhorn to NFS at 00:00 (7 kept), Velero to Garage
|
PostgreSQL 17, MariaDB 11.4.13. Memory requests and limits on everything
|
||||||
(MinIO until 2026-10-26) at 01:00 (daily kept 30 days, weekly 90 days).
|
but Longhorn, the Vault servers, calico and the LDAP outpost. Backups go
|
||||||
|
to the NAS (192.168.1.99): Longhorn to NFS at 00:00 (7 kept), Velero to
|
||||||
|
Garage (MinIO until 2026-10-26) at 01:00 (daily kept 30 days, weekly 90
|
||||||
|
days), and CNPG to Garage (a base backup at 03:00, the WAL every 5
|
||||||
|
minutes, 30 days).
|
||||||
Gatus on s1 (node001, Hetzner) and s2 (home) watch each other and alert
|
Gatus on s1 (node001, Hetzner) and s2 (home) watch each other and alert
|
||||||
through ntfy; s2 also gets an hourly report from inside the cluster on the
|
through ntfy; s2 also gets an hourly report from inside the cluster on the
|
||||||
backups, Vault's seal, the Argo CD apps and the CNPG clusters.
|
backups, Vault's seal, the Argo CD apps and the CNPG clusters.
|
||||||
Every app namespace has NetworkPolicies, and CI renders and validates all
|
Every namespace with pods but kube-system has NetworkPolicies, and CI
|
||||||
apps on every PR. node001 runs mail and tunnels the public hosts home.
|
renders and validates all apps on every PR. node001 runs mail and tunnels
|
||||||
|
the public hosts home.
|
||||||
|
|
||||||
## Follow-ups from this week
|
## Follow-ups from this week
|
||||||
|
|
||||||
@@ -26,14 +31,22 @@ docs/longhorn-second-ssd.md:
|
|||||||
- [x] Read `~/iosample.log` on opti1: the worst stretch was not the
|
- [x] Read `~/iosample.log` on opti1: the worst stretch was not the
|
||||||
backups but 8.5 hours of Longhorn merging immich-claim's deleted
|
backups but 8.5 hours of Longhorn merging immich-claim's deleted
|
||||||
snapshots (2026-10-24 14:30-23:15), see docs/upgrade-k8s-1.33.md
|
snapshots (2026-10-24 14:30-23:15), see docs/upgrade-k8s-1.33.md
|
||||||
- [ ] From 2026-10-27, if immich runs without problems: delete
|
- [x] From 2026-10-27, if immich runs without problems: delete
|
||||||
`immich/postgresql-cluster.yaml` (the PG14 cluster still runs, 20 GiB),
|
`immich/postgresql-cluster.yaml` (the PG14 cluster, 20 GiB), the
|
||||||
the Longhorn snapshots and backups `immich-pg14-pre-vchord` and
|
Longhorn snapshots and backups `immich-pg14-pre-vchord` and
|
||||||
`immich-pg17-pre-v3`, and both dumps in `~` on opti1. PostgreSQL 14
|
`immich-pg17-pre-v3`, and both dumps in `~` on opti1. Done 2026-10-28
|
||||||
reaches end of life on 2026-11-12
|
(PR #61), with the PG14 volume's other Longhorn backups.
|
||||||
|
`immich-pg17-pre-v3` only ever was a snapshot
|
||||||
- [ ] The upgrade's dqlite and backend copies in `/root/` on opti1
|
- [ ] The upgrade's dqlite and backend copies in `/root/` on opti1
|
||||||
(`backend-*.tar`, `dqlite-pre-*`)
|
(`backend-*.tar`, `dqlite-pre-*`)
|
||||||
- [ ] Log in to immich as a jeugdlid (quota 0)
|
- [ ] Log in to immich as a jeugdlid (quota 0): no uploads, albums as
|
||||||
|
viewer, people searchable but not renamable
|
||||||
|
- [x] Searching by face: people are per user in immich, and a partner's
|
||||||
|
library doesn't bring its people along, so since the personal accounts
|
||||||
|
only the group account could. share-sync now puts everyone in the
|
||||||
|
group account's cluster group and shares its people (immich 3.3's
|
||||||
|
person sharing; PR #59, 2026-10-28): 4430 people, 169 named, for each
|
||||||
|
of the 6 accounts, with write access for those who may upload
|
||||||
- [ ] Back to 1.36/stable once it is at v1.36.5 or later (still v1.36.2 on
|
- [ ] Back to 1.36/stable once it is at v1.36.5 or later (still v1.36.2 on
|
||||||
2026-10-25). The snap is held, so microk8s gets no updates at all until
|
2026-10-25). The snap is held, so microk8s gets no updates at all until
|
||||||
someone refreshes it
|
someone refreshes it
|
||||||
@@ -215,7 +228,8 @@ Findings from 2026-10-25:
|
|||||||
22:48, since the old pod waited for its connections to close. The first
|
22:48, since the old pod waited for its connections to close. The first
|
||||||
base backups: 46 MB in 29 s and 776 MB in 3.5 minutes. immich's
|
base backups: 46 MB in 29 s and 776 MB in 3.5 minutes. immich's
|
||||||
`immediate` backup ran before the plugin was up and failed; a manual one
|
`immediate` backup ran before the plugin was up and failed; a manual one
|
||||||
(`immich-postgres-17-first`) went through
|
(`immich-postgres-17-first`) went through. The 03:00 base backups of
|
||||||
|
10-27 and 10-28 completed for both; the failed backup is deleted
|
||||||
- [ ] Restore one of them into a new Cluster (`bootstrap.recovery` from
|
- [ ] Restore one of them into a new Cluster (`bootstrap.recovery` from
|
||||||
the ObjectStore, to a point in time) to see that it works. After that,
|
the ObjectStore, to a point in time) to see that it works. After that,
|
||||||
decide whether Velero still needs to copy the CNPG data directories
|
decide whether Velero still needs to copy the CNPG data directories
|
||||||
@@ -241,11 +255,13 @@ Findings from 2026-10-25:
|
|||||||
MinIO still has the kopia repositories of namespaces that are gone
|
MinIO still has the kopia repositories of namespaces that are gone
|
||||||
(~156 GB: nextcloud, ttrss, whisper-priv, whisper-webui, blog, ghost,
|
(~156 GB: nextcloud, ttrss, whisper-priv, whisper-webui, blog, ghost,
|
||||||
mbg-wordpress, sogo, sogo-mail, outrun-game, owntracks); decide first
|
mbg-wordpress, sogo, sogo-mail, outrun-game, owntracks); decide first
|
||||||
whether any of them is worth keeping
|
whether any of them is worth keeping. The dailies of 10-27 and 10-28
|
||||||
|
on Garage completed without errors
|
||||||
- [ ] Garage's SQLite WAL (`meta/db.sqlite-wal`) was 1.7 GB on
|
- [ ] Garage's SQLite WAL (`meta/db.sqlite-wal`) was 1.7 GB on
|
||||||
2026-10-26 next to a 270 MB database, and going by the folders in
|
2026-10-26 next to a 270 MB database, and going by the folders in
|
||||||
`meta/snapshots`, each 6-hourly metadata snapshot takes about 70
|
`meta/snapshots`, each 6-hourly metadata snapshot takes about 70
|
||||||
minutes. Not growing; check again after a week of normal use
|
minutes. Not growing; check again after a week of normal use. 1.8 GB
|
||||||
|
on 2026-10-28
|
||||||
|
|
||||||
### 6. Monitoring
|
### 6. Monitoring
|
||||||
|
|
||||||
@@ -314,13 +330,14 @@ Counted 2026-10-25 over the 73 running containers:
|
|||||||
OIDC logins of Vault and FreshRSS reach authentik, all 24
|
OIDC logins of Vault and FreshRSS reach authentik, all 24
|
||||||
ExternalSecrets refresh, raft intact; Gitea no longer reaches the NAS
|
ExternalSecrets refresh, raft intact; Gitea no longer reaches the NAS
|
||||||
or Vault, and a pod in `default` no longer reaches Vault or Gitea
|
or Vault, and a pod in `default` no longer reaches Vault or Gitea
|
||||||
- [ ] Certificates couldn't renew in those 11 namespaces: Envoy may only
|
- [x] Certificates couldn't renew in those 11 namespaces: Envoy may only
|
||||||
reach each app's own port, and cert-manager's HTTP-01 solver listens on
|
reach each app's own port, and cert-manager's HTTP-01 solver listens on
|
||||||
8089. ynab's renewal hung from 2026-10-26 17:35 UTC; a policy for the
|
8089. ynab's renewal hung from 2026-10-26 17:35 UTC; a policy for the
|
||||||
solver pods, applied by hand in actual-budget that evening, let it
|
solver pods, applied by hand in actual-budget that evening, let it
|
||||||
through within 20 seconds (now valid until 2027-01-24). PR #51 adds it
|
through within 20 seconds (now valid until 2027-01-24). PR #51 adds it
|
||||||
to all 11. Without it the next renewals hang too: gitea on 11-15,
|
to all 11 (merged 2026-10-26 22:27 UTC). Without it the next renewals
|
||||||
bolletjestrui on 11-18, the rest from 12-03
|
would hang too; the first real test is gitea's on 11-15, then
|
||||||
|
bolletjestrui on 11-18 and the rest from 12-03
|
||||||
- [x] The infrastructure namespaces (cert-manager, cnpg-system,
|
- [x] The infrastructure namespaces (cert-manager, cnpg-system,
|
||||||
external-secrets, envoy-gateway-system, velero, mariadb-system, dns,
|
external-secrets, envoy-gateway-system, velero, mariadb-system, dns,
|
||||||
default), merged 2026-10-26: PR #54 for envoy-gateway-system (22:31
|
default), merged 2026-10-26: PR #54 for envoy-gateway-system (22:31
|
||||||
@@ -348,6 +365,12 @@ Counted 2026-10-25 over the 73 running containers:
|
|||||||
sat idle all day (240Mi), so on 2026-10-28 a test image went through
|
sat idle all day (240Mi), so on 2026-10-28 a test image went through
|
||||||
CLIP, face recognition and OCR inside the container: 884Mi with all
|
CLIP, face recognition and OCR inside the container: 884Mi with all
|
||||||
three loaded, limit 2Gi
|
three loaded, limit 2Gi
|
||||||
|
- [ ] authentik's server fails its liveness probe while its database is
|
||||||
|
away (`/-/health/live/` answers 500 when PostgreSQL is down), so each
|
||||||
|
database restart gets the server killed too, as on 2026-10-27 for
|
||||||
|
PostgreSQL 17.11. The login only comes back once the server has
|
||||||
|
started again. A liveness probe that doesn't touch the database would
|
||||||
|
leave it at not ready
|
||||||
- [x] WordPress (scoutingmbg.nl) was OOMKilled at 08:27:59 UTC on
|
- [x] WordPress (scoutingmbg.nl) was OOMKilled at 08:27:59 UTC on
|
||||||
2026-10-25, its third restart: a crawler asked for 88 pages and assets
|
2026-10-25, its third restart: a crawler asked for 88 pages and assets
|
||||||
within a few seconds (normally ~6 a minute), Apache started a PHP worker
|
within a few seconds (normally ~6 a minute), Apache started a PHP worker
|
||||||
@@ -413,10 +436,15 @@ every PR.
|
|||||||
fail the run; tested with a planted Secret and an untagged image), plus
|
fail the run; tested with a planted Secret and an untagged image), plus
|
||||||
PR annotations for containers without requests or probes. freshrss's
|
PR annotations for containers without requests or probes. freshrss's
|
||||||
`alpine/git` init container had no tag; now `v2.52.0`
|
`alpine/git` init container had no tag; now `v2.52.0`
|
||||||
- [ ] Automerge patch versions of low-risk apps now that CI runs: PR #52
|
- [x] Automerge patch versions of low-risk apps now that CI runs: PR #52,
|
||||||
(ntfy, gatus, freshrss, serpbear, actual-budget and CI's own tools;
|
merged 2026-10-26 (ntfy, gatus, freshrss, serpbear, actual-budget and
|
||||||
three days after the release, only on weekday evenings and at the
|
CI's own tools; three days after the release, only on weekday evenings
|
||||||
weekend, when the cluster can be reached)
|
and at the weekend, when the cluster can be reached). Nothing has
|
||||||
|
merged itself yet by 2026-10-28
|
||||||
|
- [x] MariaDB stays on 11.4 (PR #60, 2026-10-28): Renovate offered 11.8.9
|
||||||
|
as a minor update (#42, closed), but 11.8 can't be rolled back and has
|
||||||
|
community support until June 2028, against May 2029 for 11.4. Renovate
|
||||||
|
now only offers 11.4 patches; the next LTS step, 12.3, is by hand
|
||||||
- [x] Renovate listed external-snapshotter twice (#15 and #24): its
|
- [x] Renovate listed external-snapshotter twice (#15 and #24): its
|
||||||
`argocd` manager and a custom `github-tags` regex both matched. The
|
`argocd` manager and a custom `github-tags` regex both matched. The
|
||||||
regex is gone; Renovate should close #15 by itself
|
regex is gone; Renovate should close #15 by itself
|
||||||
@@ -508,8 +536,8 @@ critical / high:
|
|||||||
|
|
||||||
| Image | Crit | High | What to do |
|
| Image | Crit | High | What to do |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| tensorchord/cloudnative-pgvecto.rs:14-v0.2.1 | 38 | 342 | immich's old PG14 cluster; goes with the cleanup from 2026-10-27 |
|
| tensorchord/cloudnative-pgvecto.rs:14-v0.2.1 | 38 | 342 | immich's old PG14 cluster; deleted 2026-10-28 |
|
||||||
| cloudnative-pg/postgresql:17.4 | 27 | 260 | authentik's database, a Debian 11 image. Renovate now offers 17.7; a `17.x-standard-trixie` image is more current |
|
| cloudnative-pg/postgresql:17.4 | 27 | 260 | authentik's database, a Debian 11 image. 17.11 since PR #40 (2026-10-27); not scanned again, a `17.x-standard-trixie` image is more current |
|
||||||
| tensorchord/cloudnative-vectorchord:17.11-1.1.1 | 17 | 136 | immich's database; look for a newer tag |
|
| tensorchord/cloudnative-vectorchord:17.11-1.1.1 | 17 | 136 | immich's database; look for a newer tag |
|
||||||
| longhornio/longhorn-instance-manager:v1.7.3 | 11 | 159 | still serves 16 volumes, see below |
|
| longhornio/longhorn-instance-manager:v1.7.3 | 11 | 159 | still serves 16 volumes, see below |
|
||||||
| actualbudget/actual-server:26.6.0 | 8 | 83 | chart 1.8.9; Renovate now covers it |
|
| actualbudget/actual-server:26.6.0 | 8 | 83 | chart 1.8.9; Renovate now covers it |
|
||||||
@@ -519,7 +547,7 @@ critical / high:
|
|||||||
| rubenhensen/bolletjestrui:main-10268f1 | 5 | 76 | rebuild on a current base image |
|
| rubenhensen/bolletjestrui:main-10268f1 | 5 | 76 | rebuild on a current base image |
|
||||||
| coredns/coredns:1.10.1 | 5 | 70 | see below |
|
| coredns/coredns:1.10.1 | 5 | 70 | see below |
|
||||||
| dexidp/dex:v2.45.1, argocd v3.5.6, redis 8.2.3 | 4, 1, 2 | | come with Argo CD |
|
| dexidp/dex:v2.45.1, argocd v3.5.6, redis 8.2.3 | 4, 1, 2 | | come with Argo CD |
|
||||||
| mariadb:11.4.5 | 4 | 65 | the newest 11.4 patch; Renovate now covers it |
|
| mariadb:11.4.5 | 4 | 65 | 11.4.13 since PR #60; Renovate stays on 11.4 (it offered 11.8, PR #42) |
|
||||||
| calico v3.29.3 | 2-3 | ~50 | comes with microk8s |
|
| calico v3.29.3 | 2-3 | ~50 | comes with microk8s |
|
||||||
| goauthentik ldap / server 2026.8.5 | 3, 1 | 74, 65 | the next authentik patch |
|
| goauthentik ldap / server 2026.8.5 | 3, 1 | 74, 65 | the next authentik patch |
|
||||||
|
|
||||||
|
|||||||
@@ -169,8 +169,9 @@ pgvecto.rs. Done 2026-10-24, about an hour of immich downtime:
|
|||||||
v2.4.1 refused to start (it only accepts VectorChord <0.6); v2.5.0 and up
|
v2.4.1 refused to start (it only accepts VectorChord <0.6); v2.5.0 and up
|
||||||
accept <2, so immich went to v2.7.5, the last 2.x. It rebuilt both
|
accept <2, so immich went to v2.7.5, the last 2.x. It rebuilt both
|
||||||
indexes as `vchordrq` in about 1.5 minutes
|
indexes as `vchordrq` in about 1.5 minutes
|
||||||
- [ ] After a few days without problems: delete the old cluster
|
- [x] After a few days without problems: delete the old cluster
|
||||||
(`immich/postgresql-cluster.yaml`), the snapshot/backup and the dump.
|
(`immich/postgresql-cluster.yaml`), the snapshot/backup and the dump.
|
||||||
|
Done 2026-10-28 (PR #61), with the PG14 volume's Longhorn backups.
|
||||||
Rolling back means reverting the old volume to the snapshot, since its
|
Rolling back means reverting the old volume to the snapshot, since its
|
||||||
embeddings are now `real[]` without pgvecto.rs
|
embeddings are now `real[]` without pgvecto.rs
|
||||||
- [x] immich 3.x: v2.7.5 → v3.3.5 with chart 0.10.3 → 0.13.4 on
|
- [x] immich 3.x: v2.7.5 → v3.3.5 with chart 0.10.3 → 0.13.4 on
|
||||||
@@ -189,8 +190,8 @@ pgvecto.rs. Done 2026-10-24, about an hour of immich downtime:
|
|||||||
(v3.3.0), for faster ML with less memory; numerically the same models,
|
(v3.3.0), for faster ML with less memory; numerically the same models,
|
||||||
so no jobs to rerun. The model cache is an emptyDir, so the one-off
|
so no jobs to rerun. The model cache is an emptyDir, so the one-off
|
||||||
preparation repeats on every restart
|
preparation repeats on every restart
|
||||||
- [ ] After a few days without problems: delete the `immich-pg17-pre-v3`
|
- [x] After a few days without problems: delete the `immich-pg17-pre-v3`
|
||||||
snapshot and dump together with the PG14 leftovers above
|
snapshot and dump together with the PG14 leftovers above (2026-10-28)
|
||||||
|
|
||||||
## k8s-dqlite write stalls (found 2026-10-22)
|
## k8s-dqlite write stalls (found 2026-10-22)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -62,7 +62,7 @@ node, both PowerDNS Authoritative. PowerDNS LUA records health-check
|
|||||||
addresses and only return the healthy ones:
|
addresses and only return the healthy ones:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ 30 IN LUA A "ifurlup('https://status.rubenhensen.nl/health', {{'46.224.26.65'}, {'62.41.86.27'}})"
|
@ 30 IN LUA A "ifurlup('https://status.rubenhensen.nl/health', {{'46.224.26.65'}, {'62.41.86.53'}})"
|
||||||
```
|
```
|
||||||
|
|
||||||
The double braces make two groups. PowerDNS returns the first group that has
|
The double braces make two groups. PowerDNS returns the first group that has
|
||||||
@@ -85,7 +85,7 @@ Steps:
|
|||||||
|
|
||||||
1. Parent zone (`dns/domains/rubenhensen.nl.yaml`, synced to TransIP): add
|
1. Parent zone (`dns/domains/rubenhensen.nl.yaml`, synced to TransIP): add
|
||||||
`status NS ns-hetzner.rubenhensen.nl.` and `status NS ns-home.rubenhensen.nl.`,
|
`status NS ns-hetzner.rubenhensen.nl.` and `status NS ns-home.rubenhensen.nl.`,
|
||||||
plus A records for `ns-hetzner` (46.224.26.65) and `ns-home` (62.41.86.27).
|
plus A records for `ns-hetzner` (46.224.26.65) and `ns-home` (62.41.86.53).
|
||||||
First check that TransIP accepts NS records for a subdomain.
|
First check that TransIP accepts NS records for a subdomain.
|
||||||
2. Hetzner: run PowerDNS from node001.nix with `enable-lua-records=yes` and
|
2. Hetzner: run PowerDNS from node001.nix with `enable-lua-records=yes` and
|
||||||
the bind backend. Use the same zone file as home. Open 53/udp and 53/tcp.
|
the bind backend. Use the same zone file as home. Open 53/udp and 53/tcp.
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ spec:
|
|||||||
type: RuntimeDefault
|
type: RuntimeDefault
|
||||||
containers:
|
containers:
|
||||||
- name: check
|
- name: check
|
||||||
image: python:3.15.1-alpine3.24
|
image: python:3.15.2-alpine3.24
|
||||||
command: ["python", "/script/check.py"]
|
command: ["python", "/script/check.py"]
|
||||||
env:
|
env:
|
||||||
- name: PYTHONDONTWRITEBYTECODE
|
- name: PYTHONDONTWRITEBYTECODE
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: gatus
|
- name: gatus
|
||||||
image: twinproduction/gatus:v5.37.0
|
image: twinproduction/gatus:v5.38.0
|
||||||
env:
|
env:
|
||||||
- name: GATUS_CONFIG_PATH
|
- name: GATUS_CONFIG_PATH
|
||||||
value: /config/config.yaml
|
value: /config/config.yaml
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ spec:
|
|||||||
fsGroup: 1000
|
fsGroup: 1000
|
||||||
containers:
|
containers:
|
||||||
- name: gitea
|
- name: gitea
|
||||||
image: gitea/gitea:28.2.0
|
image: gitea/gitea:28.3.0
|
||||||
env:
|
env:
|
||||||
- name: USER_UID
|
- name: USER_UID
|
||||||
value: "1000"
|
value: "1000"
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ spec:
|
|||||||
|
|
||||||
# Filled once from the PostgreSQL 14 cluster (immich-postgres) after its
|
# Filled once from the PostgreSQL 14 cluster (immich-postgres) after its
|
||||||
# embedding columns were turned into real[] and pgvecto.rs was dropped,
|
# embedding columns were turned into real[] and pgvecto.rs was dropped,
|
||||||
# see docs/upgrade-k8s-1.33.md.
|
# see docs/upgrade-k8s-1.33.md. That cluster is gone since 2026-10-28, so
|
||||||
|
# creating this Cluster again fails here, on purpose: an empty database
|
||||||
|
# would start immich with an empty library. Restore from Garage instead
|
||||||
|
# (bootstrap.recovery, see postgresql-backup.yaml).
|
||||||
bootstrap:
|
bootstrap:
|
||||||
initdb:
|
initdb:
|
||||||
database: immich
|
database: immich
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
apiVersion: postgresql.cnpg.io/v1
|
|
||||||
kind: Cluster
|
|
||||||
metadata:
|
|
||||||
name: immich-postgres
|
|
||||||
namespace: immich
|
|
||||||
spec:
|
|
||||||
instances: 1
|
|
||||||
|
|
||||||
# Use TensorChord's CNPG-compatible image with pgvecto.rs v0.2.1
|
|
||||||
imageName: ghcr.io/tensorchord/cloudnative-pgvecto.rs:14-v0.2.1
|
|
||||||
|
|
||||||
postgresql:
|
|
||||||
shared_preload_libraries:
|
|
||||||
- "vectors.so"
|
|
||||||
|
|
||||||
bootstrap:
|
|
||||||
initdb:
|
|
||||||
database: immich
|
|
||||||
owner: immich
|
|
||||||
postInitSQL:
|
|
||||||
- CREATE EXTENSION IF NOT EXISTS vectors;
|
|
||||||
- CREATE EXTENSION IF NOT EXISTS cube;
|
|
||||||
- CREATE EXTENSION IF NOT EXISTS earthdistance CASCADE;
|
|
||||||
- ALTER USER immich WITH SUPERUSER;
|
|
||||||
|
|
||||||
storage:
|
|
||||||
size: 20Gi
|
|
||||||
storageClass: longhorn
|
|
||||||
+66
-2
@@ -8,6 +8,10 @@
|
|||||||
# - the group account's library is shared as a partner and shown in
|
# - the group account's library is shared as a partner and shown in
|
||||||
# everyone's timeline, so search covers it (immich only searches your own
|
# everyone's timeline, so search covers it (immich only searches your own
|
||||||
# and your timeline partners' photos);
|
# and your timeline partners' photos);
|
||||||
|
# - everyone is put in the group account's cluster group and gets its
|
||||||
|
# people (person sharing, immich 3.3): people are per user, and a partner
|
||||||
|
# library doesn't bring its people along. Those who may upload can name
|
||||||
|
# them, for everyone;
|
||||||
# - the invitation notifications for albums older than a week are hidden,
|
# - the invitation notifications for albums older than a week are hidden,
|
||||||
# or a new member would get one per album;
|
# or a new member would get one per album;
|
||||||
# - sessions of OAuth users older than SESSION_MAX_AGE_DAYS are ended, so
|
# - sessions of OAuth users older than SESSION_MAX_AGE_DAYS are ended, so
|
||||||
@@ -15,8 +19,11 @@
|
|||||||
# Online.
|
# Online.
|
||||||
# Albums and partners go through the API. Joining other people's albums
|
# Albums and partners go through the API. Joining other people's albums
|
||||||
# (the API only lets an album's owner or editors share it), the timeline
|
# (the API only lets an album's owner or editors share it), the timeline
|
||||||
# flag (which only the receiving user can set), the notifications and the
|
# flag and the cluster group (which only the receiving user can set or
|
||||||
# sessions go straight to the database.
|
# accept), sharing the people (the API wants person.update, which the
|
||||||
|
# group's key lacks, and with password login off nobody can log in as the
|
||||||
|
# group to add it), the notifications and the sessions go straight to the
|
||||||
|
# database.
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
@@ -24,6 +31,7 @@ metadata:
|
|||||||
namespace: immich
|
namespace: immich
|
||||||
data:
|
data:
|
||||||
sync.py: |
|
sync.py: |
|
||||||
|
import collections
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -129,6 +137,62 @@ data:
|
|||||||
'UPDATE partner SET "inTimeline" = true WHERE "sharedById" = :\'group\' AND NOT "inTimeline"',
|
'UPDATE partner SET "inTimeline" = true WHERE "sharedById" = :\'group\' AND NOT "inTimeline"',
|
||||||
group=group_id,
|
group=group_id,
|
||||||
)
|
)
|
||||||
|
# What accepting an invitation to the group account's cluster group does
|
||||||
|
# (ClusterGroupService.acceptRequest): the person groups only the member
|
||||||
|
# has people in move along. Members with people in groups that others
|
||||||
|
# also have people in are left alone; that only happens after sharing.
|
||||||
|
for (email,) in sql(
|
||||||
|
"""
|
||||||
|
BEGIN;
|
||||||
|
CREATE TEMP TABLE moving ON COMMIT DROP AS
|
||||||
|
SELECT u.id FROM "user" u, "user" g
|
||||||
|
WHERE g.id = :'group' AND u.id = ANY (:'members'::uuid[])
|
||||||
|
AND u."clusterGroupId" <> g."clusterGroupId"
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM person p
|
||||||
|
JOIN person o ON o."personGroupId" = p."personGroupId" AND o."ownerId" <> p."ownerId"
|
||||||
|
WHERE p."ownerId" = u.id
|
||||||
|
);
|
||||||
|
UPDATE person_group SET "clusterGroupId" = (SELECT "clusterGroupId" FROM "user" WHERE id = :'group')
|
||||||
|
WHERE id IN (SELECT p."personGroupId" FROM person p JOIN moving m ON m.id = p."ownerId");
|
||||||
|
DELETE FROM cluster_group_request
|
||||||
|
WHERE "userId" IN (SELECT id FROM moving)
|
||||||
|
AND "clusterGroupId" = (SELECT "clusterGroupId" FROM "user" WHERE id = :'group');
|
||||||
|
UPDATE "user" SET "clusterGroupId" = (SELECT "clusterGroupId" FROM "user" WHERE id = :'group')
|
||||||
|
WHERE id IN (SELECT id FROM moving)
|
||||||
|
RETURNING email;
|
||||||
|
COMMIT;
|
||||||
|
""",
|
||||||
|
group=group_id,
|
||||||
|
members="{" + ",".join(members) + "}",
|
||||||
|
):
|
||||||
|
print(f"put {email} in the group's cluster group", flush=True)
|
||||||
|
# What PUT /people/users does for the group account: its people, with
|
||||||
|
# their names, in every member's people list and search filters. Write
|
||||||
|
# access (naming people, for everyone) for those who may upload.
|
||||||
|
shared = sql(
|
||||||
|
"""
|
||||||
|
INSERT INTO person_user ("personGroupId", "sharedById", "sharedWithId", role)
|
||||||
|
SELECT p."personGroupId", p."ownerId", m.id, m.role::person_user_role_enum
|
||||||
|
FROM person p
|
||||||
|
JOIN "user" g ON g.id = p."ownerId"
|
||||||
|
CROSS JOIN unnest(:'ids'::uuid[], :'roles'::text[]) AS m(id, role)
|
||||||
|
JOIN "user" u ON u.id = m.id AND u."clusterGroupId" = g."clusterGroupId"
|
||||||
|
WHERE p."ownerId" = :'group' AND NOT p."isHidden"
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM person_user pu
|
||||||
|
WHERE pu."personGroupId" = p."personGroupId" AND pu."sharedById" = p."ownerId"
|
||||||
|
AND pu."sharedWithId" = m.id AND pu.role = m.role::person_user_role_enum
|
||||||
|
)
|
||||||
|
ON CONFLICT ("personGroupId", "sharedById", "sharedWithId") DO UPDATE SET role = EXCLUDED.role
|
||||||
|
RETURNING "sharedWithId", role
|
||||||
|
""",
|
||||||
|
group=group_id,
|
||||||
|
ids="{" + ",".join(wanted) + "}",
|
||||||
|
roles="{" + ",".join("read" if role == "viewer" else "write" for role in wanted.values()) + "}",
|
||||||
|
)
|
||||||
|
for (uid, role), count in sorted(collections.Counter(map(tuple, shared)).items()):
|
||||||
|
print(f"share {count} people with {members[uid]} ({role})", flush=True)
|
||||||
sql(
|
sql(
|
||||||
"""
|
"""
|
||||||
UPDATE notification SET "deletedAt" = now()
|
UPDATE notification SET "deletedAt" = now()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ spec:
|
|||||||
name: mbgwp-mariadb-credentials
|
name: mbgwp-mariadb-credentials
|
||||||
key: root-password
|
key: root-password
|
||||||
|
|
||||||
image: mariadb:11.4.5
|
image: mariadb:11.4.13
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
|
|
||||||
port: 3306
|
port: 3306
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
let
|
let
|
||||||
# Public IP of the home network where the k8s cluster ingress lives.
|
# Public IP of the home network where the k8s cluster ingress lives.
|
||||||
# Keep in sync with dns/domains/rubenhensen.nl.yaml.
|
# Keep in sync with dns/domains/rubenhensen.nl.yaml.
|
||||||
homeIP = "62.41.86.27";
|
homeIP = "62.41.86.53";
|
||||||
|
|
||||||
# Hosts tunneled to the home k8s cluster. Each entry gets:
|
# Hosts tunneled to the home k8s cluster. Each entry gets:
|
||||||
# * an SNI map entry for TCP passthrough on :443
|
# * an SNI map entry for TCP passthrough on :443
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: ntfy
|
- name: ntfy
|
||||||
image: binwiederhier/ntfy:v2.34.0
|
image: binwiederhier/ntfy:v2.37.2
|
||||||
args: ["serve"]
|
args: ["serve"]
|
||||||
env:
|
env:
|
||||||
- name: NTFY_BASE_URL
|
- name: NTFY_BASE_URL
|
||||||
|
|||||||
+8
-2
@@ -82,14 +82,20 @@
|
|||||||
"description": "A PostgreSQL major upgrade needs pg_upgrade or a dump, not a tag bump",
|
"description": "A PostgreSQL major upgrade needs pg_upgrade or a dump, not a tag bump",
|
||||||
"matchDepNames": [
|
"matchDepNames": [
|
||||||
"ghcr.io/cloudnative-pg/postgresql",
|
"ghcr.io/cloudnative-pg/postgresql",
|
||||||
"ghcr.io/tensorchord/cloudnative-vectorchord",
|
"ghcr.io/tensorchord/cloudnative-vectorchord"
|
||||||
"ghcr.io/tensorchord/cloudnative-pgvecto.rs"
|
|
||||||
],
|
],
|
||||||
"matchUpdateTypes": [
|
"matchUpdateTypes": [
|
||||||
"major"
|
"major"
|
||||||
],
|
],
|
||||||
"enabled": false
|
"enabled": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "MariaDB goes from one LTS to the next by hand, after a dump: there is no way back. 11.4 has community support until May 2029, longer than 11.8 (June 2028); the next step is 12.3 (June 2029). Within 11.4 the patches come through",
|
||||||
|
"matchDepNames": [
|
||||||
|
"mariadb"
|
||||||
|
],
|
||||||
|
"allowedVersions": "<11.5"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Patch updates of apps that hold little state and are easy to roll back, and of CI's tools, merge themselves once CI passes: three days after the release, in the evening or at the weekend, when the cluster can be reached. Not the databases, operators, Vault, authentik, Longhorn, Velero, immich, Gitea or WordPress. Renovate merges itself; the repo has no branch protection for GitHub's auto-merge to wait on",
|
"description": "Patch updates of apps that hold little state and are easy to roll back, and of CI's tools, merge themselves once CI passes: three days after the release, in the evening or at the weekend, when the cluster can be reached. Not the databases, operators, Vault, authentik, Longhorn, Velero, immich, Gitea or WordPress. Renovate merges itself; the repo has no branch protection for GitHub's auto-merge to wait on",
|
||||||
"matchFileNames": [
|
"matchFileNames": [
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ spec:
|
|||||||
value: --use-openssl-ca
|
value: --use-openssl-ca
|
||||||
- name: SSL_CERT_FILE
|
- name: SSL_CERT_FILE
|
||||||
value: /etc/ssl/certs/ca-certificates.crt
|
value: /etc/ssl/certs/ca-certificates.crt
|
||||||
image: towfiqi/serpbear:3.1.0
|
image: towfiqi/serpbear:3.1.2
|
||||||
name: serpbear
|
name: serpbear
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 3000
|
- containerPort: 3000
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ spec:
|
|||||||
source:
|
source:
|
||||||
chart: velero
|
chart: velero
|
||||||
repoURL: https://vmware-tanzu.github.io/helm-charts
|
repoURL: https://vmware-tanzu.github.io/helm-charts
|
||||||
targetRevision: 12.2.1
|
targetRevision: 12.2.3
|
||||||
helm:
|
helm:
|
||||||
values: |
|
values: |
|
||||||
# Velero builds its repository maintenance jobs from a Deployment
|
# Velero builds its repository maintenance jobs from a Deployment
|
||||||
|
|||||||
Reference in new issue
Block a user