Restore test fixes: site facts, self-restore, CNPG archive generations, dependency graph #1296

Closed
claude-bot wants to merge 43 commits from worktree-restore-test-real into main
151 changed files with 2596 additions and 574 deletions
+18 -12
View File
@@ -6,18 +6,24 @@ below (like `wp-pg`) keeps `bootstrap.recovery` in git: a cold rebuild restores
each from its backup with no manual step. This document covers the
precondition, watching and verifying that restore, and the reasoning behind it.
| Cluster | Namespace | ObjectStore | barman path (`destinationPath`) | app DB / owner |
|-----------|----------------|-----------------|--------------------------------------|---------------------------------|
| `ak-pg` | authentik | `ak-pg-store` | `s3://renner-uno-k8s-cnpg/ak-pg` | `authentik`/`authentik` |
| `im-pg` | immich | `im-pg-store` | `s3://renner-uno-k8s-cnpg/im-pg` | `immich`/`immich` |
| `pprl-pg` | paperless | `pprl-pg-store` | `s3://renner-uno-k8s-cnpg/pprl-pg` | `paperless`/`paperless` |
| `ha-pg` | home-assistant | `ha-pg-store` | `s3://renner-uno-k8s-cnpg/ha-pg` | `homeassistant`/`homeassistant` |
| `mx-pg` | matrix | `mx-pg-store` | `s3://renner-uno-k8s-cnpg/mx-pg` | `synapse`/`synapse` |
| `tr-pg` | trmnl | `tr-pg-store` | `s3://renner-uno-k8s-cnpg/tr-pg` | `terminus`/`terminus` |
| Cluster | Namespace | app DB / owner |
|-----------|----------------|---------------------------------|
| `ak-pg` | authentik | `authentik`/`authentik` |
| `im-pg` | immich | `immich`/`immich` |
| `pprl-pg` | paperless | `paperless`/`paperless` |
| `ha-pg` | home-assistant | `homeassistant`/`homeassistant` |
| `mx-pg` | matrix | `synapse`/`synapse` |
| `tr-pg` | trmnl | `terminus`/`terminus` |
| `wp-pg` | woodpecker | `woodpecker`/`woodpecker` |
The barman **`serverName`** is the last path segment of `destinationPath`, i.e.
it equals the cluster name. `gf-pg` (monitoring) has no ObjectStore and stays
on `initdb`.
Each cluster `<x>` has two ObjectStores in `kubernetes/cnpg-object-stores/`:
`<x>-store`, where it archives WAL and takes base backups, and
`<x>-store-source`, which `bootstrap.recovery` reads. Their paths come from the
`flux-system/cnpg-paths` ConfigMap, which `bootstrap.sh` writes once per
cluster incarnation: the source is the prefix in `s3://renner-uno-k8s-cnpg`
whose `<x>/base/` holds the newest base backup, the archive a new prefix
`<x>-g<timestamp>`. The barman **`serverName`** is the cluster name in both.
`gf-pg` (monitoring) has no ObjectStore and stays on `initdb`.
---
@@ -129,7 +135,7 @@ cluster in the *same* namespace (so it can reference the existing namespaced
restore, but never archiving, so it only ever *reads* the backup path.
```sh
NS=authentik ; SRC=ak-pg ; STORE=ak-pg-store ; DB=authentik
NS=authentik ; SRC=ak-pg ; STORE=ak-pg-store-source ; DB=authentik
kubectl apply -f - <<EOF
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
@@ -131,7 +131,7 @@ data:
state: absent
# shelly-manager.home.renner.uno is gated by authentik-gate-sync
# (kubernetes/apps/home-assistant/shelly-manager-ingress.yaml), which
# (kubernetes/apps/home-assistant-iot/shelly-manager-ingress.yaml), which
# admits this group. Members are managed in Authentik.
- model: authentik_core.group
identifiers:
+1 -1
View File
@@ -47,7 +47,7 @@ spec:
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: ak-pg-store
barmanObjectName: ak-pg-store-source
serverName: ak-pg
postgresql:
parameters:
+4 -3
View File
@@ -152,10 +152,11 @@ spec:
targetCPUUtilizationPercentage: 70
metrics:
enabled: true
# The chart renders it without checking for monitoring.coreos.com, so
# the install would wait on monitoring. Declared in
# monitoring-rules/authentik-servicemonitor.yaml instead.
serviceMonitor:
enabled: true
labels:
release: kube-prometheus-stack
enabled: false
ingress:
enabled: true
ingressClassName: traefik
@@ -15,6 +15,5 @@ resources:
# infrastructure-cnpg-barman dep + CNPG Cluster healthCheckExprs (see
# clusters/homelab/authentik.yaml).
- cluster.yaml
- objectstore.yaml
- scheduled-backup.yaml
- hetzner-creds-externalsecret.yaml
@@ -1,33 +0,0 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: ak-pg-store
namespace: authentik
annotations:
# Prune-disabled — a standing guard kept from the seed->authentik-KS handoff (backup target).
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
# Offsite Hetzner Object Storage (fsn1) — replaces Garage on nas-1.
# No SSE: Hetzner supports only SSE-C, unusable by barman-cloud
# (plugin #646), so at-rest encryption is unavailable; transit is TLS.
destinationPath: s3://renner-uno-k8s-cnpg/ak-pg
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
# Region is required (REGION=fsn1) — without it boto3's HeadBucket
# (barman-cloud-check-wal-archive during bootstrap.recovery) 400s.
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
+2 -5
View File
@@ -10,10 +10,8 @@
# - Name, namespace, accessModes, storageClassName and volumeMode must match
# the live claim exactly: they are immutable, a mismatch fails the whole
# gitea Kustomization (no change to the live claim).
# - volumeName must stay: kustomize-controller has owned spec.volumeName
# since the namespace move pre-created this claim (eb23d3ac, #878).
# Without it, server-side apply tries to clear the field and the API server
# rejects the whole claim as an immutable-spec change.
# - No volumeName: the gitea Kustomization ignores /spec/volumeName on this
# claim, so the bound volume is kept and a fresh cluster binds a new one.
# - Grow only. A smaller value is rejected by the API server.
# - prune: disabled, so removing this file from git never deletes the claim
# and its data. To hand ownership back, delete the file; the claim stays.
@@ -33,7 +31,6 @@ spec:
accessModes: ["ReadWriteOnce"]
storageClassName: ceph-block
volumeMode: Filesystem
volumeName: pvc-e7c56db2-481d-40cb-b94a-b264b7b4b5be
resources:
requests:
storage: 60Gi
@@ -0,0 +1,35 @@
# The home-assistant workloads attached to the IoT VLAN (v30iot). Separate from
# ../home-assistant so that HA and what depends on it do not wait on a VLAN
# the node may not have; the pods run only where it does
# (net.renner.uno/iot-vlan).
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- shelly-manager-pvc.yaml
- shelly-manager-network-attachment.yaml
- shelly-manager-firmware-rbac.yaml
- shelly-ble-proxy-key-externalsecret.yaml
# shelly-manager-auth comes from ../home-assistant: mqtt-account-controller
# mounts it too, and that Kustomization comes first.
- shelly-manager-llat-externalsecret.yaml
- shelly-manager-deployment.yaml
- shelly-manager-service.yaml
- shelly-manager-ingress.yaml
# mDNS relay — carries IoT-VLAN announcements into HA's zeroconf listener as
# unicast, which is the only direction the CNI will move them. Without it HA
# never learns that a device's DHCP lease moved. See the header comment in
# mdns-relay-deployment.yaml.
- mdns-relay-network-attachment.yaml
- mdns-relay-service.yaml
- mdns-relay-deployment.yaml
configMapGenerator:
# shelly-manager api-proxy sidecar config (REN-935). Hash suffix disabled
# (name stays stable), so editing shelly-manager-api-proxy.conf does not
# auto-roll the pod — restart manually with
# `kubectl rollout restart deploy/shelly-manager -n home-assistant`.
- name: shelly-manager-api-proxy
namespace: home-assistant
files:
- api.conf.template=shelly-manager-api-proxy.conf
generatorOptions:
disableNameSuffixHash: true
@@ -47,6 +47,9 @@ spec:
homelab.renner.uno/restarted-for: "2026-10-06 cni-plugins v1.9.1 attach check"
k8s.v1.cni.cncf.io/networks: mdns-relay-iot
spec:
# Runs where the node patch declares the IoT VLAN (ens19).
nodeSelector:
net.renner.uno/iot-vlan: "true"
enableServiceLinks: false
securityContext:
runAsNonRoot: true
@@ -47,10 +47,10 @@ spec:
spec:
# eth0 (Cilium-managed pod network) is still the primary — it
# carries the ingress, mosquitto LB return path, etc. The macvlan
# above is additive. No explicit edge exclusion is needed: the
# `workload-class=pinned:NoSchedule` taint on k8s-edge already
# keeps this pod off there (we never tolerate it), and the NAD's
# `master: ens19` (stable predictable name for the v30iot NIC) is present on every k8s-{1,2,3} worker.
# above is additive.
# Runs where the node patch declares the IoT VLAN (ens19).
nodeSelector:
net.renner.uno/iot-vlan: "true"
enableServiceLinks: false
# Grants shelly-manager the in-cluster identity used by the firmware
# pipeline to create esphome flash Jobs and stream their logs. RBAC is
@@ -116,7 +116,7 @@ spec:
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: ha-pg-store
barmanObjectName: ha-pg-store-source
serverName: ha-pg
postgresql:
parameters:
@@ -1,35 +0,0 @@
---
# Barman object store for ha-pg: base backups + continuous WAL archiving to
# Hetzner Object Storage, same target bucket as the other CNPG clusters.
#
# Its own prefix. Two clusters archiving WAL to one destinationPath interleave
# their streams and corrupt both — see the note in
# kubernetes/apps/woodpecker/objectstore.yaml, which learned that the hard way.
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: ha-pg-store
namespace: home-assistant
spec:
configuration:
destinationPath: s3://renner-uno-k8s-cnpg/ha-pg
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
# Matches the 30d retention the other CNPG clusters use and the
# renner-uno-k8s-cnpg bucket's noncurrent-version expiry in
# opentofu/object_storage.tf, so old S3 versions don't outlive the backups
# that superseded them.
retentionPolicy: "30d"
@@ -21,26 +21,11 @@ resources:
- mosquitto-iot-service.yaml
- mosquitto-deployment.yaml
- mosquitto-evcc-credentials-externalsecret.yaml
- shelly-manager-pvc.yaml
- shelly-manager-network-attachment.yaml
- shelly-manager-firmware-rbac.yaml
- shelly-ble-proxy-key-externalsecret.yaml
- shelly-manager-auth-externalsecret.yaml
- shelly-manager-llat-externalsecret.yaml
- shelly-manager-deployment.yaml
- shelly-manager-service.yaml
- shelly-manager-ingress.yaml
# shelly-manager and the mDNS relay sit on the IoT VLAN: ../home-assistant-iot.
- esphome-pvc.yaml
- esphome-deployment.yaml
- esphome-service.yaml
- esphome-ingress.yaml
# mDNS relay — carries IoT-VLAN announcements into HA's zeroconf listener as
# unicast, which is the only direction the CNI will move them. Without it HA
# never learns that a device's DHCP lease moved. See the header comment in
# mdns-relay-deployment.yaml.
- mdns-relay-network-attachment.yaml
- mdns-relay-service.yaml
- mdns-relay-deployment.yaml
# Zigbee2MQTT — ZHA replacement bridge. Ships scaled to 0; the cutover
# runbook (zigbee2mqtt-migration-runbook.md) scales it up. The MQTT
# `zigbee2mqtt` broker user is provisioned by mosquitto-bootstrap.yaml
@@ -57,7 +42,6 @@ resources:
# Live: recorder.db_url in the homeassistant repo points here, and the
# long-term statistics carry their full history from 2024.
- ha-pg-hetzner-creds-externalsecret.yaml
- ha-pg-objectstore.yaml
- ha-pg-cluster.yaml
- ha-pg-scheduled-backup.yaml
# MQTT credential management (REN-802): the account controller manages the
@@ -66,6 +50,8 @@ resources:
# Register: mqtt-accounts.yaml (configMapGenerator).
- mosquitto-dynsec-test.yaml
- mqtt-account-controller.yaml
# Also mounted by shelly-manager (../home-assistant-iot), which runs after this.
- shelly-manager-auth-externalsecret.yaml
configMapGenerator:
# nginx config for the reverse-proxy sidecar. Hash suffix disabled so
# the cm name stays stable; editing proxy.conf does not auto-roll the
@@ -116,13 +102,5 @@ configMapGenerator:
namespace: home-assistant
files:
- mqtt-accounts.yaml
# shelly-manager api-proxy sidecar config (REN-935). Hash suffix disabled
# (name stays stable), so editing shelly-manager-api-proxy.conf does not
# auto-roll the pod — restart manually with
# `kubectl rollout restart deploy/shelly-manager -n home-assistant`.
- name: shelly-manager-api-proxy
namespace: home-assistant
files:
- api.conf.template=shelly-manager-api-proxy.conf
generatorOptions:
disableNameSuffixHash: true
@@ -305,10 +305,13 @@ spec:
- key: api-key
path: api-key
# Client certificate HA gets (cert-manager renews it in place; not a
# subPath mount, so the next loop sees the new file).
# subPath mount, so the next loop sees the new file). Optional: this
# controller creates its Certificate, so on a new cluster the Secret
# appears only after the controller has started.
- name: ha-mqtt-tls
secret:
secretName: mqtt-home-assistant-tls
optional: true
# HA long-lived token of the service user `MQTT Cert Sync`
# (system-admin; config flows need admin). REN-1268.
- name: ha-token
+1 -1
View File
@@ -43,7 +43,7 @@ spec:
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: im-pg-store
barmanObjectName: im-pg-store-source
serverName: im-pg
postgresql:
# vchord only. The image also ships pgvecto.rs (vectors.so), but its
@@ -11,7 +11,6 @@ resources:
# a teardown). This KS gains the infrastructure-cnpg-barman dep + CNPG Cluster
# healthCheckExprs (see clusters/homelab/immich.yaml).
- cluster.yaml
- objectstore.yaml
- scheduled-backup.yaml
- hetzner-creds-externalsecret.yaml
- pvcs.yaml
-33
View File
@@ -1,33 +0,0 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: im-pg-store
namespace: immich
annotations:
# Prune-disabled — a standing guard kept from the seed->immich-KS handoff (backup target).
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
# Offsite Hetzner Object Storage (fsn1) — replaces Garage on nas-1.
# No SSE: Hetzner supports only SSE-C, unusable by barman-cloud
# (plugin #646), so at-rest encryption is unavailable; transit is TLS.
destinationPath: s3://renner-uno-k8s-cnpg/im-pg
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
# Region is required (REGION=fsn1) — without it boto3's HeadBucket
# (barman-cloud-check-wal-archive during bootstrap.recovery) 400s.
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
@@ -44,6 +44,9 @@ spec:
labels:
app.kubernetes.io/name: llama-server
spec:
# Runs only where the node patch declares the Intel iGPU.
nodeSelector:
hardware.renner.uno/intel-gpu: "true"
securityContext:
runAsNonRoot: true
runAsUser: 1000
+3
View File
@@ -34,6 +34,9 @@ spec:
labels:
app.kubernetes.io/name: llama-embed
spec:
# Runs only where the node patch declares the Intel iGPU.
nodeSelector:
hardware.renner.uno/intel-gpu: "true"
securityContext:
runAsNonRoot: true
runAsUser: 1000
@@ -23,6 +23,9 @@ spec:
labels:
app.kubernetes.io/name: wiki-embed
spec:
# Runs only where the node patch declares the Intel iGPU.
nodeSelector:
hardware.renner.uno/intel-gpu: "true"
securityContext:
runAsNonRoot: true
runAsUser: 1000
+1 -1
View File
@@ -31,7 +31,7 @@ spec:
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: mx-pg-store
barmanObjectName: mx-pg-store-source
serverName: mx-pg
postgresql:
parameters:
@@ -9,6 +9,5 @@ resources:
# mx-pg CNPG Postgres + offsite Barman backup. The media store and signing
# key are on synapse-data, backed up by Velero (matrix-daily).
- cluster.yaml
- objectstore.yaml
- scheduled-backup.yaml
- hetzner-creds-externalsecret.yaml
-30
View File
@@ -1,30 +0,0 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: mx-pg-store
namespace: matrix
spec:
configuration:
# Offsite Hetzner Object Storage (fsn1), same bucket as the other CNPG
# clusters. No SSE: Hetzner supports only SSE-C, unusable by barman-cloud
# (plugin #646), so at-rest encryption is unavailable; transit is TLS.
destinationPath: s3://renner-uno-k8s-cnpg/mx-pg
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
# Region is required (REGION=fsn1) — without it boto3's HeadBucket
# (barman-cloud-check-wal-archive during bootstrap.recovery) 400s.
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
@@ -32,11 +32,9 @@ spec:
# OTBR via OTBR's ClusterIP Service). The macvlan attachment
# above is additive, not a replacement.
#
# No nodeSelector/toleration: this pod only needs v30iot (present
# on all nodes), not the edge USB devices. Dropping the
# workload-class=pinned toleration lets the edge taint keep it off
# the (tiny) edge box, reserving that node for the USB-bound
# home-assistant + zwave-js pods.
# Runs where the node patch declares the IoT VLAN (ens19).
nodeSelector:
net.renner.uno/iot-vlan: "true"
containers:
- name: matter-server
# Use the HAOS-published image from `ghcr.io/matter-js/...`,
@@ -1,63 +0,0 @@
---
# Only radius needs a hand-written ServiceMonitor. The goauthentik.io operator
# creates one per outpost and Prometheus discovers those directly, because
# serviceMonitorSelector here is empty (see monitoring/helmrelease-prometheus.yaml).
# Standalone copies for ldap and paperless-gate used to live here as well; they
# duplicated the operator's and were removed.
#
# Radius requires extra plumbing. The radius binary listens on :9300 just
# like ldap/proxy (hardcoded in authentik/lib/default.yml), but authentik's
# Python operator (`providers/radius/controllers/kubernetes.py`) omits the
# `DeploymentPort(9300, "http-metrics", "tcp", 9300)` entry from its
# `deployment_ports` list — that's an upstream bug; the ldap controller has
# it, radius does not. Result: the operator-managed `ak-outpost-local-radius`
# Service exposes only UDP 1812. Add a sibling Service here that selects the
# same pod labels and exposes 9300/TCP, then a ServiceMonitor for it.
#
# The operator's own `ak-outpost-local-radius` ServiceMonitor cannot cover
# this: it selects on `app.kubernetes.io/managed-by: goauthentik.io` together
# with `goauthentik.io/service-type: metrics`, and no Service carries both —
# the operator's has the first, the one below has the second.
apiVersion: v1
kind: Service
metadata:
name: ak-outpost-local-radius-metrics
namespace: authentik
labels:
app.kubernetes.io/managed-by: homelab
goauthentik.io/outpost-name: local-radius
goauthentik.io/outpost-type: radius
spec:
type: ClusterIP
clusterIP: None
selector:
goauthentik.io/outpost-name: local-radius
goauthentik.io/outpost-type: radius
ports:
- name: http-metrics
port: 9300
targetPort: 9300
protocol: TCP
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: authentik-outpost-radius
namespace: authentik
labels:
release: kube-prometheus-stack
spec:
namespaceSelector:
matchNames:
- authentik
selector:
# Pinned to the Service above. Without managed-by this would also match the
# operator's Service and scrape the same endpoint twice.
matchLabels:
app.kubernetes.io/managed-by: homelab
goauthentik.io/outpost-name: local-radius
goauthentik.io/outpost-type: radius
endpoints:
- port: http-metrics
path: /metrics
interval: 30s
@@ -0,0 +1,24 @@
---
# authentik server metrics. The chart's metrics Service stays; only its
# ServiceMonitor is declared here (see apps/authentik/helmrelease.yaml).
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: authentik-server-metrics
namespace: authentik
labels:
release: kube-prometheus-stack
spec:
namespaceSelector:
matchNames:
- authentik
selector:
matchLabels:
app.kubernetes.io/name: authentik
app.kubernetes.io/instance: authentik
app.kubernetes.io/component: server-metrics
endpoints:
- port: metrics
path: /metrics
interval: 30s
scrapeTimeout: 3s
@@ -49,7 +49,7 @@ resources:
# cannot live beside the Velero HelmRelease.
- velero-podmonitor.yaml
- velero-servicemonitor.yaml
- authentik-outpost-servicemonitors.yaml
- authentik-servicemonitor.yaml
# Rook's exporter/mgr monitors: the operator aborts its node-daemon reconcile
# when it cannot create these, which held the CephCluster in Progressing and
# deadlocked the whole apps layer. See the file for the cycle.
@@ -269,9 +269,9 @@ spec:
# per the app's own test (shelly-manager repo,
# AuthenticationTests.Health_IsUnauthenticated); it is also the pod's
# kubelet liveness/readiness path
# (../home-assistant/shelly-manager-deployment.yaml). AllowedHosts is
# (../home-assistant-iot/shelly-manager-deployment.yaml). AllowedHosts is
# "*", so the cluster-local Host header is accepted. Service :80 ->
# container :8080 (../home-assistant/shelly-manager-service.yaml).
# container :8080 (../home-assistant-iot/shelly-manager-service.yaml).
#
# NO CiliumNetworkPolicy change: the home-assistant default-deny
# admits the whole monitoring namespace on every port
@@ -25,6 +25,8 @@ spec:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
nodeSelector:
hardware.renner.uno/intel-gpu: "true"
securityContext:
seccompProfile:
type: RuntimeDefault
@@ -33,12 +33,9 @@ spec:
k8s.v1.cni.cncf.io/networks: music-assistant-iot
spec:
enableServiceLinks: false
# No nodeSelector/toleration: MA only needs a node on v30iot (all
# of them) for audio-sync L2, not the edge USB devices. It's the
# heaviest of the formerly edge-pinned pods (2Gi limit), so
# dropping the workload-class=pinned toleration — which lets the
# edge taint keep it off the tiny edge box — is the main capacity
# win for this step.
# Runs where the node patch declares the IoT VLAN (ens19).
nodeSelector:
net.renner.uno/iot-vlan: "true"
initContainers:
# MA advertises a stored publish_ip to players (Sendspin / Snapcast /
# SlimProto) and binds its stream + Sendspin servers to a stored
+4 -5
View File
@@ -30,11 +30,10 @@ spec:
# the IoT VLAN for mDNS/SRP advertisements and RA listening.
k8s.v1.cni.cncf.io/networks: otbr-iot
spec:
# No nodeSelector/toleration: OTBR only needs v30iot L2 presence
# (macvlan master: ens19, present on every node), not the edge USB
# devices, and its Thread RCP is reached over the network
# (slzb-thread.renner.uno). Dropping the workload-class=pinned
# toleration lets the edge taint keep it off the tiny edge box.
# Runs where the node patch declares the IoT VLAN (ens19). Its Thread
# RCP is reached over the network (slzb-thread.renner.uno).
nodeSelector:
net.renner.uno/iot-vlan: "true"
containers:
# The Thread RCP is a network-attached radio (Serial-over-IP), so the
# spinel transport needs a TCP-to-PTY bridge. Two obvious approaches
+1 -1
View File
@@ -39,7 +39,7 @@ spec:
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: pprl-pg-store
barmanObjectName: pprl-pg-store-source
serverName: pprl-pg
postgresql:
parameters:
@@ -17,7 +17,6 @@ resources:
# transferred without a teardown). This KS gains the infrastructure-cnpg-barman
# dep + CNPG Cluster healthCheckExprs (see clusters/homelab/paperless.yaml).
- cluster.yaml
- objectstore.yaml
- scheduled-backup.yaml
- hetzner-creds-externalsecret.yaml
- pvcs.yaml
@@ -1,35 +0,0 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: pprl-pg-store
namespace: paperless
annotations:
# Prune-disabled — a standing guard kept from the seed->paperless-KS handoff (backup target).
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
# Offsite Hetzner Object Storage (fsn1) — replaces local Garage on
# nas-1 so paperless backups survive nas-1 being powered off. barman
# uses boto3 default (auto) addressing; Hetzner (Ceph RGW) accepts it.
destinationPath: s3://renner-uno-k8s-cnpg/pprl-pg
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
# No `encryption: AES256` (SSE-S3): Hetzner Object Storage supports
# only SSE-C, which the barman-cloud plugin can't use (cnpg
# plugin-barman-cloud #646). At-rest encryption is therefore not
# available here; transit is TLS and the bucket is private.
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
+1 -1
View File
@@ -36,7 +36,7 @@ spec:
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: tr-pg-store
barmanObjectName: tr-pg-store-source
serverName: tr-pg
postgresql:
parameters:
-1
View File
@@ -18,6 +18,5 @@ resources:
# tr-pg CNPG Postgres + offsite Barman backup. Note this cluster runs
# PostgreSQL 18, not the repo-standard 16 — see the comment in cluster.yaml.
- cluster.yaml
- objectstore.yaml
- scheduled-backup.yaml
- hetzner-creds-externalsecret.yaml
-30
View File
@@ -1,30 +0,0 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: tr-pg-store
namespace: trmnl
spec:
configuration:
# Offsite Hetzner Object Storage (fsn1), same bucket as the other CNPG
# clusters. No SSE: Hetzner supports only SSE-C, unusable by barman-cloud
# (plugin #646), so at-rest encryption is unavailable; transit is TLS.
destinationPath: s3://renner-uno-k8s-cnpg/tr-pg
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
# Region is required (REGION=fsn1) — without it boto3's HeadBucket
# (barman-cloud-check-wal-archive during bootstrap.recovery) 400s.
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
+4
View File
@@ -39,6 +39,10 @@ spec:
labels:
app.kubernetes.io/name: wiki
spec:
# Its embedding backend (wiki-embed) needs the Intel iGPU; without it
# the wiki has nothing to serve, so it runs where the iGPU is declared.
nodeSelector:
hardware.renner.uno/intel-gpu: "true"
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
@@ -34,6 +34,5 @@ resources:
# This KS depends on infrastructure-cnpg-barman for the barman plugin behind
# the ObjectStore and ScheduledBackup.
- hetzner-creds-externalsecret.yaml
- objectstore.yaml
- cluster.yaml
- scheduled-backup.yaml
+703 -94
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -17,6 +17,7 @@ spec:
# woodpecker migrated) — secrets come from OpenBao via ESO
# (MIGRATION-sops-openbao.md).
dependsOn:
- name: restore-apps
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-ceph-cluster
@@ -22,6 +22,7 @@ spec:
secretRef:
name: sops-age
dependsOn:
- name: restore-audiobookshelf
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
+3 -1
View File
@@ -20,10 +20,12 @@ spec:
# from OpenBao via ESO (MIGRATION-sops-openbao.md). This was the LAST
# sops consumer; phase 4 (age-key retirement) may proceed after soak.
dependsOn:
- name: restore-authentik
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
- name: cnpg-object-stores # the ObjectStores its Cluster names
- name: gitea # server, LDAP outpost and gate-sync images are in Gitea's registry
healthCheckExprs:
- apiVersion: postgresql.cnpg.io/v1
kind: Cluster
@@ -0,0 +1,27 @@
# The CNPG ObjectStores. Their paths come from the cnpg-paths ConfigMap, which
# bootstrap.sh writes once per cluster incarnation and never replaces:
# CNPG_<X>_SOURCE the bucket prefix holding <x>'s newest base backup
# CNPG_<X>_ARCHIVE a new, empty prefix <x>-g<timestamp>
# Not optional: without it every path renders empty.
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: cnpg-object-stores
namespace: flux-system
spec:
interval: 10m
retryInterval: 1m
timeout: 5m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/cnpg-object-stores
prune: true
wait: true
dependsOn:
- name: infrastructure
- name: infrastructure-cnpg-barman
postBuild:
substituteFrom:
- kind: ConfigMap
name: cnpg-paths
+2
View File
@@ -19,3 +19,5 @@ spec:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
# mqtt-account-controller there delivers mqtt-evcc-client-tls; mosquitto is the broker.
- name: home-assistant
@@ -16,3 +16,4 @@ spec:
dependsOn:
- name: infrastructure
- name: infrastructure-crds
- name: gitea # serves Gitea's API
+7
View File
@@ -14,7 +14,14 @@ spec:
path: ./kubernetes/apps/gitea
prune: true
wait: true
# The claim's bound volume differs per cluster (apps/gitea/pvc.yaml).
ignore:
- paths: ["/spec/volumeName"]
target:
kind: PersistentVolumeClaim
name: data-gitea-0
dependsOn:
- name: restore-gitea
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
+39 -25
View File
@@ -4,43 +4,28 @@ metadata:
name: home-assistant
namespace: flux-system
spec:
# Seed Job collapsed into the HA pod's `seed` initContainer so the
# backup tarball + .HA_RESTORE manifest staging happens in the same
# pod as HA Core (no Multi-Attach race against the RWO Ceph-RBD
# PVC if production grows to multiple edge nodes). HA Core still
# does the actual restore from the staged manifest on its boot.
# Timeout has to absorb the worst-case 3h wait for the HAOS backup
# to appear in Garage plus the in-pod download + HA's native restore.
# The slowest part on a cold start is ha-pg recovering from barman (base
# backup ~1.7 GiB compressed, then WAL replay); the config PVC is restored
# beforehand by restore-home-assistant.
interval: 10m
retryInterval: 1m
timeout: 4h
timeout: 30m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/apps/home-assistant
prune: true
# Same TBD-USB caveat for the stromzaehler hostPath. Manifests apply;
# HA pod may CrashLoop until the USB is present — acceptable during canary.
wait: false
wait: true
# decryption block dropped 2026-07-13: path is sops-free — secrets come
# from OpenBao via ESO (MIGRATION-sops-openbao.md).
dependsOn:
- name: restore-home-assistant
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
# ha-pg-objectstore.yaml declares an ObjectStore, whose CRD comes from the
# CNPG Barman plugin in infrastructure-cnpg-barman. Without this edge the
# kind is unknown when this path is first applied, and a server-side
# dry-run rejects the ENTIRE set over the one object it cannot recognise:
#
# ObjectStore/home-assistant/ha-pg-store dry-run failed:
# no matches for kind "ObjectStore" in version ...
#
# Every other ObjectStore user — authentik, immich, paperless, trmnl,
# woodpecker — already declares it. This was the only one that did not, and
# it took speech-to-phrase, zone-configurator and matter-server down with
# it, since all three wait on home-assistant.
- name: infrastructure-cnpg-barman
- name: cnpg-object-stores # the ObjectStores its Cluster names
- name: gitea # mqtt-account-controller's image is in Gitea's registry
- name: influxdb # HA's InfluxDB integration writes there
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
@@ -58,10 +43,35 @@ spec:
prune: true
wait: true
dependsOn:
- name: restore-home-assistant
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
---
# shelly-manager and the mDNS relay: home-assistant's IoT-VLAN workloads.
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: home-assistant-iot
namespace: flux-system
spec:
interval: 10m
retryInterval: 1m
timeout: 10m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/apps/home-assistant-iot
prune: true
wait: true
dependsOn:
- name: restore-home-assistant # shelly-manager's PVC
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: gitea # shelly-manager's image is in Gitea's registry
- name: home-assistant # both serve HA: its API, its zeroconf listener
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
@@ -76,10 +86,13 @@ spec:
name: flux-system
path: ./kubernetes/apps/otbr
prune: true
wait: false
# Not in use.
suspend: true
wait: true
# decryption block dropped 2026-07-13: path is sops-free — secrets come
# from OpenBao via ESO (MIGRATION-sops-openbao.md).
dependsOn:
- name: restore-home-assistant
- name: infrastructure
- name: infrastructure-crds
---
@@ -120,6 +133,7 @@ spec:
# First boot downloads the Whisper model (a few hundred MB) — give it room.
wait: true
dependsOn:
- name: restore-home-assistant
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
+2 -1
View File
@@ -20,10 +20,11 @@ spec:
# decryption block dropped 2026-07-13: path is sops-free — secrets come
# from OpenBao via ESO (MIGRATION-sops-openbao.md).
dependsOn:
- name: restore-immich
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
- name: cnpg-object-stores # the ObjectStores its Cluster names
healthCheckExprs:
- apiVersion: postgresql.cnpg.io/v1
kind: Cluster
@@ -25,6 +25,7 @@ spec:
# boilerplate from the monolithic seed KS — InfluxDB has no CNPG cluster, only
# a chart-provisioned ceph-block PVC, so ceph is the only storage dep needed.
dependsOn:
- name: restore-influxdb
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
@@ -0,0 +1,19 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: infrastructure-inhouse
namespace: flux-system
spec:
interval: 10m
retryInterval: 2m
timeout: 10m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/infrastructure-inhouse
prune: true
wait: true
dependsOn:
- name: infrastructure
- name: infrastructure-crds
- name: gitea # its images are in Gitea's registry
@@ -0,0 +1,98 @@
# Infrastructure services that consume Secrets from OpenBao. Each carries its
# ExternalSecrets and depends on infrastructure-crds, where the openbao
# ClusterSecretStore turns Ready only once OpenBao is unsealed, so the
# HelmRelease never installs before its Secret exists. One Kustomization each:
# a broken service holds back nothing but itself (velero: the restore chain).
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: crowdsec
namespace: flux-system
spec:
interval: 10m
retryInterval: 1m
timeout: 10m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/infrastructure/crowdsec
prune: true
wait: true
dependsOn:
- name: infrastructure
- name: infrastructure-crds
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: external-dns-unifi
namespace: flux-system
spec:
interval: 10m
retryInterval: 1m
timeout: 5m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/infrastructure/external-dns-unifi
prune: true
wait: true
dependsOn:
- name: infrastructure
- name: infrastructure-crds
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: netbird-ingress
namespace: flux-system
spec:
interval: 10m
retryInterval: 1m
timeout: 5m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/infrastructure/netbird-ingress
prune: true
wait: true
dependsOn:
- name: infrastructure
- name: infrastructure-crds
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: velero
namespace: flux-system
spec:
interval: 10m
retryInterval: 1m
timeout: 15m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/infrastructure/velero
prune: true
wait: true
dependsOn:
- name: infrastructure
- name: infrastructure-crds
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: velero-schedules
namespace: flux-system
spec:
interval: 10m
retryInterval: 1m
timeout: 5m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/infrastructure/velero-schedules
prune: true
wait: true
dependsOn:
- name: velero # the velero.io CRDs
@@ -40,6 +40,13 @@ spec:
kind: HelmRelease
name: openbao # the ESO backend ExternalSecrets resolve against
namespace: openbao
# Ready only when every replica is unsealed (readiness probe: bao status).
# The HelmRelease is Ready as soon as the chart is installed; the
# ClusterSecretStore in infrastructure-crds must not come up before.
- apiVersion: apps/v1
kind: StatefulSet
name: openbao
namespace: openbao
- apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
name: rook-ceph-operator # storage — apps mount PVCs
+2 -1
View File
@@ -17,10 +17,11 @@ spec:
prune: true
wait: true
dependsOn:
- name: restore-matrix
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
- name: cnpg-object-stores # the ObjectStores its Cluster names
healthCheckExprs:
- apiVersion: postgresql.cnpg.io/v1
kind: Cluster
@@ -46,6 +46,7 @@ spec:
# from OpenBao via ESO (MIGRATION-sops-openbao.md).
dependsOn:
- name: grafana-db
- name: influxdb # its Job writes the grafana-influxdb-token Secret Grafana mounts
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
@@ -22,6 +22,7 @@ spec:
secretRef:
name: sops-age
dependsOn:
- name: restore-music-assistant
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
@@ -14,6 +14,7 @@ spec:
prune: true
wait: true
dependsOn:
- name: restore-navidrome
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
+3 -1
View File
@@ -20,10 +20,12 @@ spec:
# decryption block dropped 2026-07-13: path is sops-free — secrets come
# from OpenBao via ESO (MIGRATION-sops-openbao.md).
dependsOn:
- name: restore-paperless
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
- name: cnpg-object-stores # the ObjectStores its Cluster names
- name: gitea # ftp-scanner (vsftpd) image is in Gitea's registry
healthCheckExprs:
- apiVersion: postgresql.cnpg.io/v1
kind: Cluster
@@ -35,3 +35,4 @@ spec:
# The `openbao` ClusterSecretStore, including the `renovate` entry in its
# conditions.namespaces allowlist.
- name: infrastructure-crds
- name: gitea # the platform it runs against (git.renner.uno)
+396
View File
@@ -0,0 +1,396 @@
# Ready once Velero has completed a sync of the backups in the bucket. A
# Restore created before that finds no backup and fails for good.
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: velero-backups-synced
namespace: flux-system
spec:
interval: 10m
timeout: 30m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/gate
prune: true
dependsOn:
- name: velero # the BackupStorageLocation and its credentials
healthChecks:
- apiVersion: velero.io/v1
kind: BackupStorageLocation
name: default
namespace: velero
healthCheckExprs:
- apiVersion: velero.io/v1
kind: BackupStorageLocation
current: has(status.lastSyncedTime)
---
# One Kustomization per Velero Schedule (infrastructure/velero-schedules/schedules.yaml),
# each restoring that schedule's newest backup. An app depends on its own, so
# it waits for its data and for nothing else. Gitea's data goes first: it is
# the registry for the in-house images; the others depend on restore-gitea.
# openbao-daily has none: bootstrap.sh restores OpenBao from its raft snapshot.
# Every one carries the same health check: a schedule without any backup has
# nothing to restore (FailedValidation "No backups found for schedule").
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-gitea
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/gitea
prune: true
wait: true
dependsOn:
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-apps
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/apps
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-audiobookshelf
namespace: flux-system
spec:
interval: 10m
timeout: 3h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/audiobookshelf
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-authentik
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/authentik
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-home-assistant
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/home-assistant
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-immich
namespace: flux-system
spec:
interval: 10m
timeout: 6h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/immich
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-influxdb
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/influxdb
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-matrix
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/matrix
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-music-assistant
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/music-assistant
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-navidrome
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/navidrome
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-paperless
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/paperless
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-trmnl
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/trmnl
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-wordpress
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/wordpress
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
@@ -16,3 +16,4 @@ spec:
dependsOn:
- name: infrastructure
- name: infrastructure-crds
- name: gitea # its image is in Gitea's registry
+3 -1
View File
@@ -17,10 +17,12 @@ spec:
prune: true
wait: true
dependsOn:
- name: restore-trmnl
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
- name: cnpg-object-stores # the ObjectStores its Cluster names
- name: home-assistant # the renderer reads HA's API
healthCheckExprs:
- apiVersion: postgresql.cnpg.io/v1
kind: Cluster
+1
View File
@@ -20,3 +20,4 @@ spec:
- name: infrastructure-ceph-cluster
# wiki-embed (the embedding backend) lives in the llama-server app.
- name: llama-server
- name: gitea # its image is in Gitea's registry
+2 -1
View File
@@ -24,7 +24,8 @@ spec:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
- name: cnpg-object-stores # the ObjectStores its Cluster names
- name: gitea # its forge and login provider
healthCheckExprs:
- apiVersion: postgresql.cnpg.io/v1
kind: Cluster
@@ -12,7 +12,9 @@ spec:
name: flux-system
path: ./kubernetes/apps/wordpress
prune: true
wait: true
dependsOn:
- name: restore-wordpress
# infrastructure gates on the mariadb-operator HelmRelease being Ready,
# so the MariaDB CRD exists and has a controller before this applies.
- name: infrastructure
+54
View File
@@ -0,0 +1,54 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: ak-pg-store
namespace: authentik
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
destinationPath: ${CNPG_AK_PG_ARCHIVE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: ak-pg-store-source
namespace: authentik
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
cnpg.renner.uno/server-name: ak-pg
spec:
configuration:
destinationPath: ${CNPG_AK_PG_SOURCE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
+54
View File
@@ -0,0 +1,54 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: ha-pg-store
namespace: home-assistant
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
destinationPath: ${CNPG_HA_PG_ARCHIVE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: ha-pg-store-source
namespace: home-assistant
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
cnpg.renner.uno/server-name: ha-pg
spec:
configuration:
destinationPath: ${CNPG_HA_PG_SOURCE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
+54
View File
@@ -0,0 +1,54 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: im-pg-store
namespace: immich
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
destinationPath: ${CNPG_IM_PG_ARCHIVE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: im-pg-store-source
namespace: immich
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
cnpg.renner.uno/server-name: im-pg
spec:
configuration:
destinationPath: ${CNPG_IM_PG_SOURCE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
@@ -0,0 +1,24 @@
# Every CNPG cluster's two ObjectStores: <x>-store, where it archives WAL and
# takes base backups, and <x>-store-source, which its bootstrap.recovery reads.
#
# Their destinationPaths are Flux variables from the cnpg-paths ConfigMap
# (clusters/homelab/cnpg-object-stores.yaml). Nothing else may live in this
# directory: postBuild substitution blanks every ${...} it renders.
#
# The source store carries cnpg.renner.uno/server-name, the cluster whose
# backups bootstrap.sh looks for, and optionally
# cnpg.renner.uno/source-prefixes, bucket prefixes outside the <name> and
# <name>-g<timestamp> pattern that may still hold them.
#
# No SSE: Hetzner supports only SSE-C, unusable by barman-cloud (plugin #646),
# so at-rest encryption is unavailable; transit is TLS.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ak-pg.yaml
- ha-pg.yaml
- im-pg.yaml
- mx-pg.yaml
- pprl-pg.yaml
- tr-pg.yaml
- wp-pg.yaml
+54
View File
@@ -0,0 +1,54 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: mx-pg-store
namespace: matrix
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
destinationPath: ${CNPG_MX_PG_ARCHIVE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: mx-pg-store-source
namespace: matrix
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
cnpg.renner.uno/server-name: mx-pg
spec:
configuration:
destinationPath: ${CNPG_MX_PG_SOURCE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
@@ -0,0 +1,54 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: pprl-pg-store
namespace: paperless
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
destinationPath: ${CNPG_PPRL_PG_ARCHIVE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: pprl-pg-store-source
namespace: paperless
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
cnpg.renner.uno/server-name: pprl-pg
spec:
configuration:
destinationPath: ${CNPG_PPRL_PG_SOURCE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
+54
View File
@@ -0,0 +1,54 @@
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: tr-pg-store
namespace: trmnl
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
destinationPath: ${CNPG_TR_PG_ARCHIVE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
retentionPolicy: "30d"
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: tr-pg-store-source
namespace: trmnl
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
cnpg.renner.uno/server-name: tr-pg
spec:
configuration:
destinationPath: ${CNPG_TR_PG_SOURCE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
@@ -1,46 +1,14 @@
---
# RECOVERY SOURCE — read-only. The prefix wp-pg archives to (wp-pg-store below).
#
# serverName on the consuming externalCluster must be `wp-pg`, the name of the
# cluster that produced these backups.
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: wp-pg-store-source
namespace: woodpecker
spec:
configuration:
destinationPath: s3://renner-uno-k8s-cnpg/wp-pg-woodpecker
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
# No retentionPolicy: wp-pg-store owns the lifecycle of this prefix.
---
# ARCHIVING TARGET.
#
# Not s3://renner-uno-k8s-cnpg/wp-pg: the retired `apps/wp-pg` archived there,
# and two clusters archiving WAL to one destinationPath interleave their streams
# and corrupt both.
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: wp-pg-store
namespace: woodpecker
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
configuration:
destinationPath: s3://renner-uno-k8s-cnpg/wp-pg-woodpecker
destinationPath: ${CNPG_WP_PG_ARCHIVE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
@@ -57,3 +25,32 @@ spec:
data:
compression: gzip
retentionPolicy: "30d"
---
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: wp-pg-store-source
namespace: woodpecker
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
cnpg.renner.uno/server-name: wp-pg
# wp-pg's archive since its move out of `apps`.
cnpg.renner.uno/source-prefixes: wp-pg-woodpecker
spec:
configuration:
destinationPath: ${CNPG_WP_PG_SOURCE}
endpointURL: https://fsn1.your-objectstorage.com
s3Credentials:
accessKeyId:
name: hetzner-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: hetzner-s3-creds
key: ACCESS_SECRET_KEY
region:
name: hetzner-s3-creds
key: REGION
wal:
compression: gzip
data:
compression: gzip
@@ -51,6 +51,10 @@ spec:
# Owns table 47, where all pod traffic is routed. Without it the table
# stays empty and the rules fall through to main, unseparated.
priorityClassName: system-node-critical
# Table 47 exists only where the site patch routes pod traffic into it
# (RoutingRuleConfig); the same patch labels those nodes.
nodeSelector:
net.renner.uno/pod-table: "47"
# Writes host routes and peers on host addresses.
hostNetwork: true
serviceAccountName: bird
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Infrastructure that runs images from Gitea's registry with no copy on
# ghcr.io, so it cannot start before Gitea serves them.
resources:
- bird/
- netbird-service-sync/
@@ -0,0 +1,79 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: ceph-csi-operator
namespace: rook-ceph
spec:
interval: 24h
url: https://ceph.github.io/ceph-csi-operator
---
# The CSI Driver and OperatorConfig resources Rook requires
# (rook/Documentation/Helm-Charts/csi-drivers-chart.md). Values are Rook's
# recommended ones (rook/deploy/charts/ceph-csi-drivers/values.yaml) plus the
# shape this cluster runs with.
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: ceph-csi-drivers
namespace: rook-ceph
spec:
interval: 30m
dependsOn:
- name: rook-ceph-operator
chart:
spec:
chart: ceph-csi-drivers
sourceRef:
kind: HelmRepository
name: ceph-csi-operator
namespace: rook-ceph
install:
remediation:
retries: 3
upgrade:
remediation:
retries: 3
values:
operatorConfig:
namespace: rook-ceph
driverSpecDefaults:
imageSet:
name: rook-csi-operator-image-set-configmap
nodePlugin:
priorityClassName: system-node-critical
controllerPlugin:
priorityClassName: system-cluster-critical
drivers:
rbd:
enabled: true
name: rook-ceph.rbd.csi.ceph.com
# Velero snapshots ceph-block claims through CSI.
snapshotPolicy: volumeSnapshot
nodePlugin:
tolerations:
- key: workload-class
operator: Equal
value: pinned
effect: NoSchedule
controllerPlugin:
replicas: 2
deploymentStrategy:
type: Recreate
cephfs:
enabled: true
name: rook-ceph.cephfs.csi.ceph.com
snapshotPolicy: volumeGroupSnapshot
nodePlugin:
tolerations:
- key: workload-class
operator: Equal
value: pinned
effect: NoSchedule
controllerPlugin:
replicas: 2
deploymentStrategy:
type: Recreate
nfs:
enabled: false
nvmeof:
enabled: false
@@ -1,5 +1,6 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- helmrelease.yaml
- serviceaccounts.yaml
- rbac.yaml
@@ -184,26 +184,13 @@ spec:
# Cilium's, the sessions re-establish.
bgpControlPlane:
enabled: true
# Masquerading exception, not a routing statement: pod traffic to these
# ranges leaves unmasqueraded, so LAN services see real pod IPs. That only
# works because BGP advertises the pod CIDRs, which is what gives the UDM a
# route back. The two settings are one decision and have to move together.
#
# Pod CIDRs are 10.244.0.0/16 and fd10:244::/48 (talos/patches/cluster.yaml);
# the supernets here cover the LAN as well, which is the point.
ipv4NativeRoutingCIDR: 10.0.0.0/8
ipv6NativeRoutingCIDR: fd00::/8
# Pod east-west leaves the node on pod0 (VLAN 48) rather than the
# management VLAN. Native routing hands forwarding to the kernel;
# autoDirectNodeRoutes installs the remote PodCIDR routes, which is
# allowed because all three nodes share pod0's L2 segment.
#
# directRoutingDevice is explicit on purpose: with several addressed
# devices Cilium falls back to the one carrying the Kubernetes InternalIP,
# which is mgmt0.
#
# Encapsulation is gone, so the datapath MTU goes 1450 -> 1500.
routingMode: native
autoDirectNodeRoutes: true
nodePort:
directRoutingDevice: pod0
# What the site's network can carry decides how pod traffic crosses between
# nodes and which destinations see real pod IPs: routingMode,
# autoDirectNodeRoutes, the direct-routing device and the native-routing
# (masquerade-exempt) CIDRs come from the cilium-site ConfigMap that each
# Talos site patch carries (talos/patches/site-*.yaml). They must not be set
# in values above, which would override it.
valuesFrom:
- kind: ConfigMap
name: cilium-site
valuesKey: values.yaml
@@ -3,3 +3,5 @@ kind: Kustomization
resources:
- lapi-ingress.yaml
- helmrelease.yaml
- crowdsec-bouncer-key-externalsecret.yaml
- crowdsec-edge-bouncer-key-externalsecret.yaml
@@ -2,3 +2,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- helmrelease.yaml
- externalsecret.yaml
@@ -119,3 +119,4 @@ spec:
type: DirectoryOrCreate
nodeSelector:
kubernetes.io/arch: amd64
hardware.renner.uno/intel-gpu: "true"

Some files were not shown because too many files have changed in this diff Show More