Wave 1 indri→ringtail migration: paperless, teslamate, mealie #363

Merged
eblume merged 12 commits from migrate-wave1-ringtail into main 2026-06-03 10:34:01 -07:00
6 changed files with 221 additions and 0 deletions
Showing only changes of commit 1d4cbbfb84 - Show all commits

databases-ringtail: add blumeops-pg cluster for wave-1 (paperless, teslamate)

CNPG Cluster on ringtail to receive the paperless + teslamate databases
migrated off the minikube blumeops-pg via cold pg_dump/pg_restore. Mirrors
the minikube cluster (managed roles eblume/borgmatic/paperless/teslamate,
scram pg_hba) on ringtail's local-path storage, scoped to wave-1 roles
(miniflux + authentik stay put for later waves). Apps reach it in-cluster
at blumeops-pg-rw.databases.svc.cluster.local — same name as on minikube.

Database creation is deferred to cutover: paperless restores into the
bootstrap database; teslamate's DB is created by the eblume superuser at
its cutover (the dump's earthdistance extension is untrusted). The four
ExternalSecrets reuse the same 1Password items as the minikube cluster.
Not yet synced; deploy waits for review. kustomize build verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Erich Blume 2026-06-03 09:26:39 -07:00

View file

@ -0,0 +1,97 @@
# PostgreSQL Cluster for blumeops services on ringtail k3s.
#
# Wave-1 indri-k8s decommission target (see [[migrate-wave1-ringtail]]).
# Holds the paperless and teslamate databases migrated off the minikube
# blumeops-pg via cold pg_dump/pg_restore at cutover. miniflux + authentik
# stay where they are for now (later waves), so this cluster only carries
# the wave-1 roles.
#
# Apps reach this in-cluster at blumeops-pg-rw.databases.svc.cluster.local
# — the same name they used on minikube, so teslamate's DATABASE_HOST is
# unchanged.
#
# Database creation is deferred to cutover, mirroring the minikube cluster
# (where only the bootstrap database is declared and the rest were created
# out-of-band):
# - paperless: the bootstrap database below (restored into at cutover).
# - teslamate: created at its cutover by the eblume superuser, because the
# dump's `earthdistance` extension is untrusted and CREATE EXTENSION
# needs superuser. (cube + earthdistance ownership then transferred to
# the teslamate role so it can ALTER EXTENSION UPDATE.)
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: blumeops-pg
namespace: databases
spec:
instances: 1
imageName: ghcr.io/cloudnative-pg/postgresql:18.3
storage:
size: 10Gi
storageClass: local-path
bootstrap:
initdb:
database: paperless
owner: paperless
managed:
roles:
# eblume superuser for admin + privileged restore steps (extensions)
- name: eblume
login: true
superuser: true
createdb: true
createrole: true
connectionLimit: -1
ensure: present
inherit: true
passwordSecret:
name: blumeops-pg-eblume
# borgmatic read-only user for backups
- name: borgmatic
login: true
connectionLimit: -1
ensure: present
inherit: true
inRoles:
- pg_read_all_data
passwordSecret:
name: blumeops-pg-borgmatic
# paperless user (also the bootstrap database owner above; the
# managed role sets its password from the 1Password-backed secret)
- name: paperless
login: true
connectionLimit: -1
ensure: present
inherit: true
passwordSecret:
name: blumeops-pg-paperless
# teslamate user. Extension ownership (cube, earthdistance) is
# transferred to this role at cutover so it can ALTER EXTENSION UPDATE.
- name: teslamate
login: true
connectionLimit: -1
ensure: present
inherit: true
passwordSecret:
name: blumeops-pg-teslamate
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "1Gi"
cpu: "500m"
postgresql:
parameters:
max_connections: "50"
shared_buffers: "128MB"
password_encryption: "scram-sha-256"
pg_hba:
# Password auth from anywhere; network security is via Tailscale.
- host all all 0.0.0.0/0 scram-sha-256
- host all all ::/0 scram-sha-256

View file

@ -0,0 +1,30 @@
# ExternalSecret for borgmatic backup user password
#
# Replaces the manual op inject workflow from secret-borgmatic.yaml.tpl
#
# 1Password item: "borgmatic" in blumeops vault
# Field: "db-password"
#
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: blumeops-pg-borgmatic
namespace: databases
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword-blumeops
target:
name: blumeops-pg-borgmatic
creationPolicy: Owner
template:
type: kubernetes.io/basic-auth
data:
username: borgmatic
password: "{{ .password }}"
data:
- secretKey: password
remoteRef:
key: borgmatic
property: db-password

View file

@ -0,0 +1,30 @@
# ExternalSecret for eblume superuser password
#
# Replaces the manual op inject workflow from secret-eblume.yaml.tpl
#
# 1Password item: "postgres" in blumeops vault
# Field: "password"
#
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: blumeops-pg-eblume
namespace: databases
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword-blumeops
target:
name: blumeops-pg-eblume
creationPolicy: Owner
template:
type: kubernetes.io/basic-auth
data:
username: eblume
password: "{{ .password }}"
data:
- secretKey: password
remoteRef:
key: postgres
property: password

View file

@ -0,0 +1,28 @@
# ExternalSecret for Paperless database user password
#
# 1Password item: "Paperless (blumeops)" in blumeops vault
# Field: "postgresql-password"
#
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: blumeops-pg-paperless
namespace: databases
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword-blumeops
target:
name: blumeops-pg-paperless
creationPolicy: Owner
template:
type: kubernetes.io/basic-auth
data:
username: paperless
password: "{{ .password }}"
data:
- secretKey: password
remoteRef:
key: Paperless (blumeops)
property: postgresql-password

View file

@ -0,0 +1,30 @@
# ExternalSecret for TeslaMate database user password
#
# Replaces the manual op inject workflow from secret-teslamate.yaml.tpl
#
# 1Password item: "TeslaMate" in blumeops vault
# Field: "db_password"
#
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: blumeops-pg-teslamate
namespace: databases
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: onepassword-blumeops
target:
name: blumeops-pg-teslamate
creationPolicy: Owner
template:
type: kubernetes.io/basic-auth
data:
username: teslamate
password: "{{ .password }}"
data:
- secretKey: password
remoteRef:
key: TeslaMate
property: db_password

View file

@ -7,3 +7,9 @@ resources:
- immich-pg.yaml - immich-pg.yaml
- external-secret-immich-borgmatic.yaml - external-secret-immich-borgmatic.yaml
- service-immich-pg-tailscale.yaml - service-immich-pg-tailscale.yaml
# wave-1 indri-k8s decommission: blumeops-pg (paperless + teslamate)
- blumeops-pg.yaml
- external-secret-eblume.yaml
- external-secret-borgmatic.yaml
- external-secret-paperless.yaml
- external-secret-teslamate.yaml