Files
homelab-manifests/immich-system/immich.yaml
T
admin e459b0d262 immich/renovate: roll back immich-postgres v17 -> v16 (PG major datadir incompat) + gate postgres-family images
Renovate PR #76 (merged 2026-06-06 10:48) bumped ghcr.io/immich-app/postgres
from `16-vectorchord0.3.0` to `17-vectorchord0.3.0`. PostgreSQL major
upgrades require pg_upgrade or pg_dump/restore — the new server binary
refuses to open a data directory initialized by the previous major:

  FATAL: database files are incompatible with server
  DETAIL: The data directory was initialized by PostgreSQL version 16,
          which is not compatible with this version 17.6

Both immich-postgres and immich-server (depends on Postgres) went into
CrashLoopBackOff. PVC still holds the v16 datadir.

This PR:
  1. Reverts ghcr.io/immich-app/postgres back to `16-vectorchord0.3.0`
     so immich recovers immediately.
  2. Adds a packageRule with `dependencyDashboardApproval: true` covering
     `postgres`, `postgis/postgis`, and `ghcr.io/immich-app/postgres`.
     Any update to these images is now held on the Dashboard's "Pending
     Approval" section -- Renovate won't even open a PR until the user
     explicitly ticks the box. Forces the migration plan to be made
     BEFORE the change reaches main.

This is the same recovery pattern we just used for meilisearch (PR #77)
-- a class of stateful images where the on-disk format isn't
forward-compatible across version bumps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-06 11:00:32 +02:00

537 lines
14 KiB
YAML

---
apiVersion: v1
kind: Namespace
metadata:
name: immich-system
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: immich-postgres
namespace: immich-system
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: longhorn
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: immich-postgres
namespace: immich-system
labels:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: postgres
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: postgres
template:
metadata:
labels:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: postgres
annotations:
match-regex.version-checker.io/postgres: '^\d+-vectorchord\d+\.\d+\.\d+$'
spec:
securityContext:
fsGroup: 999
containers:
- name: postgres
image: ghcr.io/immich-app/postgres:16-vectorchord0.3.0
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: immich-db
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: immich-db
key: password
- name: POSTGRES_DB
value: immich
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- containerPort: 5432
name: postgres
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
subPath: data
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 1
memory: 1Gi
volumes:
- name: data
persistentVolumeClaim:
claimName: immich-postgres
---
apiVersion: v1
kind: Service
metadata:
name: immich-postgres
namespace: immich-system
spec:
type: ClusterIP
ports:
- port: 5432
targetPort: postgres
name: postgres
selector:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: postgres
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: immich-machine-learning
labels:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: machine-learning
app.kubernetes.io/version: v2.5.5
namespace: immich-system
spec:
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: "10Gi"
storageClassName: "longhorn"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: immich-valkey
labels:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: valkey
app.kubernetes.io/version: v2.5.5
namespace: immich-system
spec:
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: "1Gi"
storageClassName: "longhorn"
---
apiVersion: v1
kind: Service
metadata:
name: immich-machine-learning
labels:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: machine-learning
app.kubernetes.io/service: immich-machine-learning
app.kubernetes.io/version: v2.5.5
namespace: immich-system
spec:
type: ClusterIP
ports:
- port: 3003
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/controller: main
app.kubernetes.io/instance: immich
app.kubernetes.io/name: machine-learning
---
apiVersion: v1
kind: Service
metadata:
name: immich-server
labels:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: server
app.kubernetes.io/service: immich-server
app.kubernetes.io/version: v2.5.5
namespace: immich-system
spec:
type: ClusterIP
ports:
- port: 2283
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/controller: main
app.kubernetes.io/instance: immich
app.kubernetes.io/name: server
---
apiVersion: v1
kind: Service
metadata:
name: immich-valkey
labels:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: valkey
app.kubernetes.io/service: immich-valkey
app.kubernetes.io/version: v2.5.5
namespace: immich-system
spec:
type: ClusterIP
ports:
- port: 6379
targetPort: redis
protocol: TCP
name: redis
selector:
app.kubernetes.io/controller: main
app.kubernetes.io/instance: immich
app.kubernetes.io/name: valkey
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: immich-machine-learning
labels:
app.kubernetes.io/controller: main
app.kubernetes.io/instance: immich
app.kubernetes.io/name: machine-learning
app.kubernetes.io/version: v2.5.5
namespace: immich-system
spec:
revisionHistoryLimit: 3
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/controller: main
app.kubernetes.io/name: machine-learning
app.kubernetes.io/instance: immich
template:
metadata:
labels:
app.kubernetes.io/controller: main
app.kubernetes.io/instance: immich
app.kubernetes.io/name: machine-learning
spec:
enableServiceLinks: false
serviceAccountName: default
automountServiceAccountToken: true
hostIPC: false
hostNetwork: false
hostPID: false
dnsPolicy: ClusterFirst
containers:
- env:
- name: HF_XET_CACHE
value: /cache/huggingface-xet
- name: IMMICH_MACHINE_LEARNING_URL
value: http://immich-machine-learning:3003
- name: MPLCONFIGDIR
value: /cache/matplotlib-config
- name: REDIS_HOSTNAME
value: immich-valkey
- name: TRANSFORMERS_CACHE
value: /cache
image: ghcr.io/immich-app/immich-machine-learning:v2.7.5
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /ping
port: http
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 1
name: main
ports:
- containerPort: 3003
name: http
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /ping
port: http
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 1
startupProbe:
failureThreshold: 60
httpGet:
path: /ping
port: http
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 1
volumeMounts:
- mountPath: /cache
name: cache
volumes:
- name: cache
persistentVolumeClaim:
claimName: immich-machine-learning
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: immich-server
labels:
app.kubernetes.io/controller: main
app.kubernetes.io/instance: immich
app.kubernetes.io/name: server
app.kubernetes.io/version: v2.5.5
namespace: immich-system
spec:
revisionHistoryLimit: 3
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/controller: main
app.kubernetes.io/name: server
app.kubernetes.io/instance: immich
template:
metadata:
labels:
app.kubernetes.io/controller: main
app.kubernetes.io/instance: immich
app.kubernetes.io/name: server
spec:
enableServiceLinks: false
serviceAccountName: default
automountServiceAccountToken: true
hostIPC: false
hostNetwork: false
hostPID: false
dnsPolicy: ClusterFirst
containers:
- env:
- name: DB_HOSTNAME
value: immich-postgres
- name: DB_PORT
value: "5432"
- name: DB_DATABASE_NAME
value: immich
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: immich-db
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: immich-db
key: password
- name: IMMICH_MACHINE_LEARNING_URL
value: http://immich-machine-learning:3003
- name: REDIS_HOSTNAME
value: immich-valkey
image: ghcr.io/immich-app/immich-server:v2.7.5
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /api/server/ping
port: http
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 1
name: main
ports:
- containerPort: 2283
name: http
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /api/server/ping
port: http
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 1
startupProbe:
failureThreshold: 30
httpGet:
path: /api/server/ping
port: http
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 1
volumeMounts:
- mountPath: /data
name: data
volumes:
- name: data
hostPath:
path: /mnt/4_hdd/data/immich
type: Directory
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: immich-valkey
labels:
app.kubernetes.io/controller: main
app.kubernetes.io/instance: immich
app.kubernetes.io/name: valkey
app.kubernetes.io/version: v2.5.5
namespace: immich-system
spec:
revisionHistoryLimit: 3
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/controller: main
app.kubernetes.io/name: valkey
app.kubernetes.io/instance: immich
template:
metadata:
labels:
app.kubernetes.io/controller: main
app.kubernetes.io/instance: immich
app.kubernetes.io/name: valkey
spec:
enableServiceLinks: false
serviceAccountName: default
automountServiceAccountToken: true
hostIPC: false
hostNetwork: false
hostPID: false
dnsPolicy: ClusterFirst
containers:
- env:
- name: IMMICH_MACHINE_LEARNING_URL
value: http://immich-machine-learning:3003
- name: REDIS_HOSTNAME
value: immich-valkey
image: docker.io/valkey/valkey:9.1-alpine@sha256:a35428eba9043cc0b79dbe54100f0c92784f2de00ad09b01182bfb1c5c83d1bd
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- sh
- -c
- valkey-cli ping | grep PONG
failureThreshold: 3
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
name: main
ports:
- containerPort: 6379
name: redis
protocol: TCP
readinessProbe:
exec:
command:
- sh
- -c
- valkey-cli ping | grep PONG
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
startupProbe:
exec:
command:
- sh
- -c
- valkey-cli ping | grep PONG
failureThreshold: 30
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 5
volumeMounts:
- mountPath: /data
name: data
volumes:
- name: data
persistentVolumeClaim:
claimName: immich-valkey
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: immich-server
labels:
app.kubernetes.io/instance: immich
app.kubernetes.io/name: server
app.kubernetes.io/version: v2.5.5
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
external-dns.alpha.kubernetes.io/hostname: photos.dooplex.hu
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
# GeoIP-based access control
nginx.ingress.kubernetes.io/configuration-snippet: |
# GeoIP-based access control for Immich
# Allows Hungarian traffic everywhere, worldwide only for /share/* paths
set $geo_allowed 0;
# Allow private/local networks
if ($remote_addr ~ "^192\.168\.") { set $geo_allowed 1; }
if ($remote_addr ~ "^10\.") { set $geo_allowed 1; }
# Allow all Hungarian traffic
if ($geoip2_country_code = "HU") { set $geo_allowed 1; }
# Public share paths
if ($request_uri ~* "^/share") { set $geo_allowed 1; }
# API endpoints needed for shares
if ($request_uri ~* "^/api/shared-links") { set $geo_allowed 1; }
if ($request_uri ~* "^/api/assets") { set $geo_allowed 1; }
if ($request_uri ~* "^/api/albums") { set $geo_allowed 1; }
if ($request_uri ~* "^/api/server") { set $geo_allowed 1; }
if ($request_uri ~* "^/api/timeline") { set $geo_allowed 1; }
if ($request_uri ~* "^/api/users/me") { set $geo_allowed 1; }
# Static assets
if ($request_uri ~* "^/_app/") { set $geo_allowed 1; }
if ($request_uri ~* "\.(js|css|woff2?|ttf|svg|png|ico|jpg|jpeg|webp)$") { set $geo_allowed 1; }
if ($geo_allowed = 0) {
return 403 "Access restricted to Hungary";
}
namespace: immich-system
spec:
ingressClassName: nginx-internal
tls:
- hosts:
- "photos.dooplex.hu"
secretName: "immich-tls"
rules:
- host: "photos.dooplex.hu"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: immich-server
port:
number: 2283
- host: "photos.home"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: immich-server
port:
number: 2283