feat(k8s/immich): add immich stack (HelmRelease suspended for migration)

This commit is contained in:
2026-02-22 18:20:21 +02:00
parent 2b299b6f73
commit 46e82016af
14 changed files with 816 additions and 2 deletions

View File

@@ -0,0 +1,291 @@
# Immich Migration Guide
This document describes how to migrate Immich from the existing Docker Compose stack (`docker/stacks/immich/`) to this Kubernetes deployment.
## Overview
The migration involves three categories of data:
1. **PostgreSQL database** — all Immich metadata, users, albums, face recognition data, search vectors
2. **Photo library** — already on Synology NAS via NFS, no data movement needed
3. **Ephemeral state** (ML model cache, Redis/Valkey) — will be recreated automatically
Only the PostgreSQL database requires active migration. Everything else either stays in place (photos) or regenerates on first start (model cache, Valkey).
### What Changes
| Aspect | Docker Compose | Kubernetes |
|---|---|---|
| Orchestration | Docker Compose via Portainer | Helm chart via Flux CD HelmRelease |
| PostgreSQL | Container with bind mount | StatefulSet with NFS-backed PVC |
| Redis | Standalone Redis 6.2 | Valkey (Redis fork) via Helm subchart |
| Backups (photos) | resticprofile with crond inside container | K8s CronJob running resticprofile |
| Backups (database) | postgres-backup-local (hourly local dumps) | K8s CronJob: pg_dump + rclone to R2 |
| Ingress | Traefik Docker labels | K8s Ingress with cert-manager TLS |
| Secrets | `stack.env.real` (plain text on disk) | SOPS-encrypted Secrets in Git |
| Network isolation | Docker network `immich` | K8s NetworkPolicies (default-deny + explicit allow) |
| Authentication | Immich built-in | Immich built-in (unchanged, no Authelia) |
### What Stays the Same
- Photo library location on NAS (same NFS path)
- Immich PostgreSQL image with vectorchord/pgvectors extensions
- Restic backup repository on Backblaze B2 (same repo, same key — history carries over)
- Database credentials (can be reused from `stack.env.real`)
## Prerequisites
- `kubectl` configured for the target cluster
- `sops` and `age` installed for encrypting secrets
- Docker Compose stack still running (for database dump)
- Note the following values from your Docker `stack.env.real`:
- `UPLOAD_LOCATION` — photo library path on NAS (this becomes `IMMICH_UPLOAD_NFS_PATH`)
- `DB_PASSWORD`, `DB_USERNAME`, `DB_DATABASE_NAME` — current database credentials
- Verify which Immich version Docker is running:
```bash
docker inspect immich-server --format '{{.Config.Image}}'
```
The HelmRelease pins `v2.0.0`. If Docker runs a different version, update `image.tag` in `release.yaml` to match before migrating, then upgrade after migration is verified.
## Phase 1: Deploy Infrastructure (Immich Suspended)
The HelmRelease is deployed in a suspended state so that only the supporting infrastructure (database, PVCs, secrets, network policies) is created. Immich app pods will not start until Phase 3.
1. Suspend the HelmRelease by adding `spec.suspend: true` to `release.yaml`:
```yaml
spec:
suspend: true
chart:
...
```
2. Fill in and encrypt all secrets:
```bash
# Edit with actual values, then encrypt
sops --encrypt --in-place kubernetes/app/immich/secret.sops.yaml
sops --encrypt --in-place kubernetes/app/immich/secret-rclone.sops.yaml
sops --encrypt --in-place kubernetes/app/immich/secret-backup.sops.yaml
```
3. Set `IMMICH_HOST` and `IMMICH_UPLOAD_NFS_PATH` in cluster-vars:
```bash
sops kubernetes/config/cluster-vars.sops.yaml
```
`IMMICH_UPLOAD_NFS_PATH` must be the same NAS path as Docker's `UPLOAD_LOCATION`.
4. Commit and push:
```bash
git add kubernetes/app/immich/ kubernetes/config/cluster-vars.sops.yaml
git commit -m "feat(k8s/immich): add immich stack (HelmRelease suspended for migration)"
git push
```
5. Wait for Flux to reconcile:
```bash
flux reconcile kustomization apps --with-source
kubectl get pvc -n immich
```
All PVCs should be `Bound`. The HelmRelease will show as `Suspended`.
6. Verify the database pod is ready:
```bash
kubectl wait --for=condition=ready pod -n immich -l app=immich-db --timeout=120s
```
## Phase 2: Migrate PostgreSQL Database
The StatefulSet is running from Phase 1 with an empty database. Dump from Docker and restore into K8s.
1. Dump the database from the running Docker container:
```bash
docker exec immich-database pg_dump -U immich -d immich --clean --if-exists > immich.sql
```
> The container name may differ — check with `docker ps | grep postgres`. Use the container running the `ghcr.io/immich-app/postgres` image.
2. Verify the dump is non-empty:
```bash
wc -l immich.sql
grep -c "CREATE TABLE" immich.sql
```
3. Copy the dump into the K8s pod and restore:
```bash
kubectl cp immich.sql immich/immich-db-0:/tmp/immich.sql
kubectl exec -n immich immich-db-0 -- psql -U immich -d immich -f /tmp/immich.sql
```
Some `DROP ... does not exist` notices are expected (from `--clean --if-exists`). Errors about extensions already existing are also normal.
4. Verify restoration:
```bash
# Check table count
kubectl exec -n immich immich-db-0 -- psql -U immich -d immich -c \
"SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public';"
# Check that vector extensions are present
kubectl exec -n immich immich-db-0 -- psql -U immich -d immich -c \
"SELECT extname, extversion FROM pg_extension WHERE extname LIKE '%vector%';"
# Check asset count (your photo count)
kubectl exec -n immich immich-db-0 -- psql -U immich -d immich -c \
"SELECT count(*) FROM asset;"
```
5. Verify the NFS library path is correct. The photo library PV should point to the same NFS directory as Docker's `UPLOAD_LOCATION`:
```bash
kubectl get pv immich-library -o jsonpath='{.spec.nfs.path}'
```
## Phase 3: Start Immich
With the database restored and NFS path verified, unsuspend the HelmRelease.
1. Remove `suspend: true` from `release.yaml`.
2. Commit and push:
```bash
git add kubernetes/app/immich/release.yaml
git commit -m "feat(k8s/immich): unsuspend HelmRelease after data migration"
git push
```
3. Wait for Flux to deploy the Helm chart:
```bash
flux reconcile kustomization apps --with-source
kubectl get helmrelease -n flux-system immich
kubectl get pods -n immich -w
```
You should see pods for: `immich-server`, `immich-machine-learning`, `immich-valkey-master`, and `immich-db-0` (already running).
4. The ML service will download models on first start — this is expected and may take several minutes.
## Post-Migration Verification
### Web Access
Open `https://<IMMICH_HOST>` in a browser. You should see the Immich login page with your existing users.
### Photo Library
- Log in and verify your photos and albums are visible
- Check that thumbnails load (they're stored in the upload directory)
- Verify face recognition data is intact (People tab)
### Ingress and TLS
```bash
kubectl get ingress -n immich
kubectl get certificate -n immich
```
The certificate should show `Ready: True` after cert-manager provisions it.
### Backup CronJobs
Trigger manual test runs:
```bash
# Test database backup
kubectl create job -n immich --from=cronjob/immich-db-backup immich-db-backup-test
kubectl logs -n immich -l job-name=immich-db-backup-test -f
# Test library backup (resticprofile)
kubectl create job -n immich --from=cronjob/immich-library-backup immich-library-backup-test
kubectl logs -n immich -l job-name=immich-library-backup-test -f
```
The library backup should connect to the existing Backblaze B2 restic repository and complete an incremental backup.
### Network Policies
```bash
# Verify immich-server can reach the database
kubectl exec -n immich deploy/immich-server -- nc -z immich-db 5432
```
## Stop Docker Compose Stack
Only after K8s is verified working:
In Portainer: Stop the immich stack.
Or via CLI:
```bash
docker compose -f docker-compose.yaml --env-file stack.env.real down
```
The photo library on the NAS remains accessible via the K8s NFS PV.
## Rollback
The Docker data is not modified during migration (pg_dump reads only, NFS path is shared). To roll back:
1. Revert the immich manifests from Git and push. Flux will delete the namespace and all resources via pruning.
Alternatively, suspend Flux and delete manually:
```bash
flux suspend kustomization apps
kubectl delete namespace immich
```
2. Re-deploy the Docker Compose stack from Portainer with the original `stack.env.real`.
## Pitfalls and Troubleshooting
### PostgreSQL PGDATA path difference
Docker uses `PGDATA=/var/lib/postgresql/data` (the mount root). The K8s StatefulSet sets `PGDATA=/var/lib/postgresql/data/pgdata` (a subdirectory). Never copy the Docker PostgreSQL data directory directly to the K8s PVC. Always use `pg_dump`/`psql`.
### Immich version mismatch
If Docker was running a different Immich version than the one pinned in the HelmRelease (`v2.0.0`), Immich may run database migrations on startup. This is normally fine (Immich handles forward migrations), but there is no rollback path for schema changes. Match versions first if unsure.
### NFS path mismatch
`IMMICH_UPLOAD_NFS_PATH` must resolve to exactly the same NAS directory as Docker's `UPLOAD_LOCATION`. If it differs, Immich will start but show no photos, and thumbnails will be broken. Verify by checking inside a running pod:
```bash
kubectl exec -n immich deploy/immich-server -- ls /usr/src/app/upload/
```
You should see directories like `library/`, `thumbs/`, `encoded-video/`, `upload/`, `profile/`.
### vectorchord/pgvectors extensions
The K8s StatefulSet uses the same custom PostgreSQL image (`ghcr.io/immich-app/postgres:14-vectorchord0.3.0-pgvectors0.2.0`) as Docker. Extensions are installed during `initdb` and preserved through `pg_dump`/`psql` restore. If you see errors about missing `vector` type, verify the extensions:
```bash
kubectl exec -n immich immich-db-0 -- psql -U immich -d immich -c "SELECT extname FROM pg_extension;"
```
### Restic lock errors
If the Docker resticprofile container was not cleanly stopped, a stale lock may exist in the Backblaze B2 restic repository. The K8s CronJob will fail with a lock error. Fix by running:
```bash
kubectl create job -n immich --from=cronjob/immich-library-backup immich-unlock-test --dry-run=client -o yaml | \
sed 's/backup && resticprofile.*forget/unlock/' | kubectl apply -f -
```
Or exec into a temporary pod with the restic key and AWS credentials and run `restic unlock`.

View File

@@ -0,0 +1,132 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: immich-db-backup
namespace: immich
labels:
app: immich-db-backup
spec:
schedule: "0 3 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
metadata:
labels:
app: immich-db-backup
spec:
restartPolicy: OnFailure
initContainers:
- name: pg-dump
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0-pgvectors0.2.0
env:
- name: PGHOST
value: immich-db
- name: PGUSER
valueFrom:
secretKeyRef:
name: immich-credentials
key: DB_USERNAME
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: immich-credentials
key: DB_PASSWORD
- name: PGDATABASE
valueFrom:
secretKeyRef:
name: immich-credentials
key: DB_DATABASE_NAME
command:
- sh
- -c
- pg_dump --clean --if-exists > /backup/dump.sql
volumeMounts:
- name: backup
mountPath: /backup
containers:
- name: rclone-upload
image: rclone/rclone:1.69
command:
- sh
- -c
- rclone copy /backup/dump.sql b2crypt:immich-db/ --config /config/rclone/rclone.conf
volumeMounts:
- name: backup
mountPath: /backup
- name: rclone-config
mountPath: /config/rclone
readOnly: true
volumes:
- name: backup
emptyDir: {}
- name: rclone-config
secret:
secretName: immich-rclone-config
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: immich-library-backup
namespace: immich
labels:
app: immich-library-backup
spec:
schedule: "0 4 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
metadata:
labels:
app: immich-library-backup
spec:
restartPolicy: OnFailure
containers:
- name: resticprofile-backup
image: creativeprojects/resticprofile:latest
command:
- sh
- -c
- resticprofile -c /etc/resticprofile/profiles.yaml backup && resticprofile -c /etc/resticprofile/profiles.yaml forget
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: immich-backup-credentials
key: AWS_ACCESS_KEY_ID
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: immich-backup-credentials
key: AWS_SECRET_ACCESS_KEY
volumeMounts:
- name: library
mountPath: /photos
readOnly: true
- name: resticprofile-config
mountPath: /etc/resticprofile
readOnly: true
- name: restic-key
mountPath: /etc/restic
readOnly: true
volumes:
- name: library
persistentVolumeClaim:
claimName: immich-library
- name: resticprofile-config
secret:
secretName: immich-backup-credentials
items:
- key: profiles.yaml
path: profiles.yaml
- name: restic-key
secret:
secretName: immich-backup-credentials
items:
- key: RESTIC_KEY
path: key

View File

@@ -0,0 +1,69 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: immich-db
namespace: immich
labels:
app: immich-db
spec:
replicas: 1
serviceName: immich-db
selector:
matchLabels:
app: immich-db
template:
metadata:
labels:
app: immich-db
spec:
securityContext:
runAsUser: 999
runAsGroup: 999
fsGroup: 999
containers:
- name: postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0-pgvectors0.2.0
env:
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: immich-credentials
key: DB_DATABASE_NAME
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: immich-credentials
key: DB_USERNAME
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: immich-credentials
key: DB_PASSWORD
- name: POSTGRES_INITDB_ARGS
value: --data-checksums
- name: DB_STORAGE_TYPE
value: HDD
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- containerPort: 5432
name: postgres
protocol: TCP
livenessProbe:
tcpSocket:
port: 5432
initialDelaySeconds: 30
periodSeconds: 30
failureThreshold: 5
readinessProbe:
tcpSocket:
port: 5432
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
persistentVolumeClaim:
claimName: immich-db

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: immich

View File

@@ -0,0 +1,94 @@
# Default deny all ingress in the immich namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: immich
spec:
podSelector: {}
policyTypes:
- Ingress
---
# Allow ingress controller to reach immich-server
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-controller
namespace: immich
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: server
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik
---
# immich-db: only reachable from immich app pods and backup jobs
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: immich-db
namespace: immich
spec:
podSelector:
matchLabels:
app: immich-db
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: server
- podSelector:
matchLabels:
app.kubernetes.io/name: microservices
- podSelector:
matchLabels:
app: immich-db-backup
---
# Allow immich pods to reach valkey
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-valkey
namespace: immich
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: valkey
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: server
- podSelector:
matchLabels:
app.kubernetes.io/name: microservices
---
# Allow immich pods to reach machine-learning
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-machine-learning
namespace: immich
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: machine-learning
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: server
- podSelector:
matchLabels:
app.kubernetes.io/name: microservices

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: immich-library
spec:
capacity:
storage: 1Ti
accessModes:
- ReadWriteMany
storageClassName: ""
persistentVolumeReclaimPolicy: Retain
mountOptions:
- hard
- nointr
nfs:
server: synology.storage.lviv
path: ${IMMICH_UPLOAD_NFS_PATH}

View File

@@ -0,0 +1,26 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: immich-library
namespace: immich
spec:
accessModes:
- ReadWriteMany
storageClassName: ""
volumeName: immich-library
resources:
requests:
storage: 1Ti
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: immich-db
namespace: immich
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-synology-ssd
resources:
requests:
storage: 10Gi

View File

@@ -0,0 +1,82 @@
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: immich
namespace: flux-system
spec:
suspend: true
chart:
spec:
chart: immich
reconcileStrategy: ChartVersion
sourceRef:
kind: HelmRepository
name: immich
namespace: flux-system
version: 0.10.3
interval: 1m0s
targetNamespace: immich
values:
controllers:
main:
containers:
main:
image:
tag: v2.5.6
env:
DB_HOSTNAME: immich-db
DB_USERNAME:
valueFrom:
secretKeyRef:
name: immich-credentials
key: DB_USERNAME
DB_PASSWORD:
valueFrom:
secretKeyRef:
name: immich-credentials
key: DB_PASSWORD
DB_DATABASE_NAME:
valueFrom:
secretKeyRef:
name: immich-credentials
key: DB_DATABASE_NAME
DB_STORAGE_TYPE: HDD
immich:
persistence:
library:
existingClaim: immich-library
server:
enabled: true
ingress:
main:
enabled: true
annotations:
cert-manager.io/cluster-issuer: letsencrypt
hosts:
- host: ${IMMICH_HOST}
paths:
- path: /
pathType: Prefix
tls:
- hosts:
- ${IMMICH_HOST}
secretName: immich-tls
machine-learning:
enabled: true
persistence:
cache:
enabled: true
storageClass: nfs-synology-ssd
accessMode: ReadWriteOnce
size: 10Gi
type: persistentVolumeClaim
valkey:
enabled: true
persistence:
data:
enabled: true
size: 1Gi
type: persistentVolumeClaim
accessMode: ReadWriteOnce
storageClass: nfs-synology-ssd

View File

@@ -0,0 +1,10 @@
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: immich
namespace: flux-system
spec:
interval: 1m0s
type: oci
url: oci://ghcr.io/immich-app/immich-charts

View File

@@ -0,0 +1,25 @@
apiVersion: v1
kind: Secret
metadata:
name: immich-backup-credentials
namespace: immich
stringData:
AWS_ACCESS_KEY_ID: ENC[AES256_GCM,data:lGrcLznG4NVn/xM+pyaRwdbnt1DMioucgA==,iv:4gb4Rdd2RCFS0SjK/nUjSbNcgcs8QrUlkz04BOimmv4=,tag:Q+3vV6Fknl/BpHcgeef2AA==,type:str]
AWS_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:Kw7Pt1HiDi/ZsWwZcSeyWgVAtBkmqyNi8XVW3wjU0Q==,iv:AjpZVeXZthyKtOqWzz4K/0CxEL2QB75PXD/EnFTI1wM=,tag:NdW8QJUKz2W4u5LCgk64XQ==,type:str]
RESTIC_KEY: ENC[AES256_GCM,data:dmb7QIwP35GF+L6+aKsYiyKgRrYOSw7LOdSakZVK6CRlKB7izmTboGAZHOitDHXw9lHASBfE3gYKkDZtLSK9tw==,iv:34i8s9xax+XVe2k5nyazbsz0wD+pWX0BWde+sf77TZY=,tag:VijQe0wBxCZNVv8hPopvgQ==,type:str]
profiles.yaml: ENC[AES256_GCM,data:WO05cJpUjcdvAqmd7DSfIL+o859jLOsMgx26U858rnXSZGYGFmAexkcePmb+XnRxxNoxGLdC1xyC1KcpLfWz9llorxN27FojkBIWm7ZlqBPpAoVpLoroYnPrMVlSQgZsuKW+zcN/wHWH1KmgU9ImPEfS5qtcLmcr3RZLmm6HPVwdtUBU6HDe6boYHuYV1FSFDvZWE2swWp9Ml6rCEwcr7dvOWRN/djEr8AMbZPhj8Qhe94VeX1Ocx/jzTSFBLZrhLN1xcwBrwPNSjb00+JtNrMhpA0z8/bJnLMhLWWDb/WbWNqQnJkJImJPFj2t3gI0klkdaosq29Rc5bHJcKzMDed3RSvdFu7dkQGr86cw+qBtPLYq7oTYEu4Zo1hXjDfeckcpk2tI+z++lNOws+O+L6SBbxx4ZPhlOymonf1xBvBeXH65LU9YOtjAp/fBmSIAXsgoYEOBhkXd/vAG8oblFp2VXvGSs8agZGbTZTeON4Kam8eyGnVeA92Vjk5OgpE+qW+dVdT2qSUyOdpJmJoQbxnpKjNs1Qft+arDNP87hA+cFav7/3i5+WawesFPTAuSTgZBSzCd3I2nJtmO/zonGVaB5,iv:qDSbTaPMqqTDBWw+pU5pKwOT8Vo8BQCGb81PmPh3qbM=,tag:uym01wpo+OMWiVxyWNr3cQ==,type:str]
sops:
age:
- recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5WFFRWVAwVkx6SjBPZUw5
Ykx2QnJjYS96VEJHaWFOTC9Yb0Q1ckppSEg4CjYvcGVYQ284c1JzRXJseTFPVDJQ
bDNHeXVKNXNydzcyVFlkWHJuQ0R0T1kKLS0tIHNuMThacHk1dko0N3hRd3NjZUxv
U25jVnVQQjhaQlI2TU5QSGhtcjRvZWcKNCiNhsb+lZehYXAx87a3h5G5mifOdqxQ
5xa/TTuqQwv4v5xrsMKcYvt2VvKipWYaByP/4F6D5mkH28GK2etlgg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-02-22T16:17:56Z"
mac: ENC[AES256_GCM,data:525DsywY9tCeDrNwU39oFdJoF3jtB4AoA+i4LLEomnYsvQrdpMQRRn5BKVS40nmGZ3wA37JrJkGRk8Be21Wri6M3Vh0hzExWmqYLY7Xhvc+6IK6UJzgL/RQ9ynl7vtw7buozWWZhOWoBjzC84t/hWxepNSA30XHR9NypWUF+TpE=,iv:3lA2d8MtVGLtmhDlWVUHcyqrM6u4aoNoFL/l8YYS4Kw=,tag:9L/gobcRaGxk9n6RRChtXw==,type:str]
encrypted_regex: ^(data|stringData|email)$
version: 3.11.0

View File

@@ -0,0 +1,22 @@
apiVersion: v1
kind: Secret
metadata:
name: immich-rclone-config
namespace: immich
stringData:
rclone.conf: ENC[AES256_GCM,data:CryFjZBVyHdDPT1yGlmhCGDthmyhT3tTAmj2RmUl+pmrO4qkiT1UdADn/aSdSNjIE89dXzHcn22bY/4K9EuKhKPHm+MzHx10isPtrwERNy1FAhc2a1/pwBRIi5ej4MWZrCNnJCyG5coWDtsJhW/nRev0aAc24Jsp2S4Iyw4ZZcVDPLmYGCb0GYunOQOFKQkB3R+q3aFeaPOJnrn7EJVRzsiwFAd4hiVyCpSFme7n6xddKkMMrDICsyFg6ICkKYgFgRp0JnXVleA+y9phI17F/P63VXJsaI25JE5SMENTNpRHQ0OIC/HYQO92fadGXh7lMwp3zNwaoLk5YY1j4FXYuEHoxmtd82eEuvLYwM7CL4qj/aYZ1CiYWWiRg3oaUrKt7btFLDmdgkr4dhiv2S6t9AzwTp0Fo7Gg,iv:bSN2tyGWIQJVZ26dgFr/GEhmEeDM6cmfx6b6yEBWXY0=,tag:wKWO4uYYmb51sWq7JQY4UQ==,type:str]
sops:
age:
- recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4NDg1WVBjbnB6YlFWTFpk
S2M3Tm1zVUZhUFRSZi9mcHVNWkhCcm5OQVNnCmNBTmllY2U0Mkw1dUpvSkpoR2Rj
SUN5T09kelNNZFBuaVFPMW1GUkhkNW8KLS0tIG1jNHdzczc0Z1c4bzVOVitBVHUy
U1V5QVBjdUptb3YrNkJjNkZzZ0xZZnMKyH1YkErMgv7n7t9Wr1aAE5LJvLKPO18r
z5gjcgUy7sCq77eRU4XjEgqivyy6fUcdbyTazhTGYIuUB5i3LbYSdQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-02-22T16:16:54Z"
mac: ENC[AES256_GCM,data:gq7I3d82pjWZyHtX97jk8l+vYHqes1te43BXyI+yqYazh/ZyBshJT+60B5EjnfK8RA/C/jGcVTpBHa2Gc8BkcAxX1eDEvd9g72X70owB4MW3UYGSQ4XmeBzIdKC3p/LIW6SSzGcQB4MZZpuQ8HyP0+qGDE7NZJrim7wp6zI6Ovo=,iv:2l3NX+UuDdAQ9wAcaTFpWbWpq1G98p6CJBZnmzLLCvg=,tag:fzpx0i+w6lwfiQBHBMU9+A==,type:str]
encrypted_regex: ^(data|stringData|email)$
version: 3.11.0

View File

@@ -0,0 +1,24 @@
apiVersion: v1
kind: Secret
metadata:
name: immich-credentials
namespace: immich
stringData:
DB_PASSWORD: ENC[AES256_GCM,data:VnoJR8ALDlw/BwU/3/b7KbCrMbwdTFMagRvit//NsWTw5flqsQirZ8JxXPek8VJxDkQkbmVUld+slgh4NkBBbQ==,iv:2Jttn6CmDEI8/i6LFJ8aAw7YvEZsT0iK/SEhnBYLPhw=,tag:4dyAA9HuA6Rm+vciXHqMag==,type:str]
DB_USERNAME: ENC[AES256_GCM,data:x5K6Si9p,iv:bt/DiC2SGDXz8vWvVATaHOSgz0SoL/jGJR7dNuYmaQc=,tag:iP3HIICt4SrMDJ0/XxZ0Qw==,type:str]
DB_DATABASE_NAME: ENC[AES256_GCM,data:yPids+wE,iv:eDtreKHSfi+SXSwX4g7Y5MNPTRsOW88TC/nA+YZ0Ww8=,tag:RdJDG7r8ncMYU5wOt9wr6A==,type:str]
sops:
age:
- recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNblZZWkZ0cnhPbGpUa2FK
R1RDZzBrUERMQ0tHUGw3QmZYZEptTGd0RHhnCkhOdmR5eGRoVitlbjRIaW5PdXpa
NmhRcnl1dDZ4ME5nMTRENUV2ZGkxVVUKLS0tIGcxUHFrVENQQTlpeDM0dmVWNGxh
MlRtZHFheTdIb0RZQTRDKzVKSEVtTHMKucqUfpKcxxyBU9rnoV/wVoAwM8gTVJGX
d615yxwcmsKtivzarkMbrSh14jFFjhJKiyYLZ1ExfwpfEykl9DpZ6w==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-02-23T17:43:35Z"
mac: ENC[AES256_GCM,data:AE6aKYrkZ+fOy/Cadjegrzlau9X1vFiegkRNMZs15JV6sN5hOQ1PqX5Fyi4gyHqzXDrD0BNED4ZT4+8z5zxeRxKxP7nmyh1rwz8UnT/vDsp9zdWNl2qYu62JH5rxnU1c/Vmi8NfqPGdaT2fVpCz+HhV//zusFOLP1mi3L06TK5M=,iv:4QdJr1Q2jP6ics/kOmo63+7YOM+5UIh5s2LjnSqfNx8=,tag:MHwd3RJ/3zo9ohgGdYM7Jg==,type:str]
encrypted_regex: ^(data|stringData|email)$
version: 3.11.0

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: immich-db
namespace: immich
labels:
app: immich-db
spec:
type: ClusterIP
ports:
- name: 5432-5432
port: 5432
targetPort: 5432
protocol: TCP
selector:
app: immich-db

View File

@@ -10,6 +10,8 @@ stringData:
SONARR_HOST: ENC[AES256_GCM,data:dMEgQYHxa0tIilY8HPkppFgOWzH52Q==,iv:yCUF8ZVOSY2IfULa9B44ALGjgFyZyQrQWPZsyQzqwbM=,tag:kfhsZhPE1rZNYUJ3X2rRSQ==,type:str]
RADARR_HOST: ENC[AES256_GCM,data:lsWSI+D/qzru3qHGvJjKRepYEGHe5Q==,iv:cq9yNVCMuon+ZUpFwfkwBvVg9oIT0MXagjDi6l/29YA=,tag:koGF34SrtHe0brRiNKP8rg==,type:str]
MEDIA_NFS_PATH: ENC[AES256_GCM,data:BSDMu0n2Vx4koYBIMF8=,iv:c9kGdcTxObNaaaTzEhSRkyHvo+dxSN+o+96n9UqJieU=,tag:W9+MbyAuK85xajjwntRi0Q==,type:str]
IMMICH_HOST: ENC[AES256_GCM,data:KnzX89wzQvb5Pa/MqX4YiHZ0JS5geA==,iv:05jEIwQEjJnvZ1Ot33Lkfs1TB3L/mwX5dqaTfsugcx4=,tag:LFzOLZSqHQ58bL3oVvGM9g==,type:str]
IMMICH_UPLOAD_NFS_PATH: ENC[AES256_GCM,data:l8F1AkmhGkNxo29X5UER,iv:Z/u0yLNv5ClQu44lPPzGIB2bEsADFCD/mCd+Kw8kuhc=,tag:a8QGaUEYF3iJbZKcAiRKUg==,type:str]
sops:
age:
- recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
@@ -21,7 +23,7 @@ sops:
LzhUN3Z4cExIL1IyS3ZCNWh5aWpLbDgKQ7c3MmLykA00NaLoctKVDfJvPqTqh3Ia
cDZJUc6jYJXOJYM6YYyZOYcCL2z8V2RpIfA9sPg8PB2eiipZxjk+Cg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-02-22T10:48:28Z"
mac: ENC[AES256_GCM,data:qw4wqmlHntZiybI2VPKcQEUJg0AG8kgWn7hEw6WlCltf7STbRWLLedR5TTRmKpcCQofE4T02ZZPLbzVVP7tSer1S4nAYSMwkfQhgkZ8DVvn/E2O/Yxzja/DXLV9tNMYpYexSkfVX8zYRS1zdd48VBgA4P4N0WR65kvoUnIScrgA=,iv:+brh3Gehjes1G6wNxPVDgHltI80Ih5d21Va/ADJxxCI=,tag:pay3NKWyLYF4BPZnCszW0Q==,type:str]
lastmodified: "2026-02-22T16:16:12Z"
mac: ENC[AES256_GCM,data:i8QGecMBJwUwb9dki6ZLFM+4cNPjSLtI31eeiGBqu5dqyeX/e60FprfIHBHfdiastFDDrCZ4SRLd49KKBocGsX3QbX/uk+8rmtHC83ACp6iYiv3kGUS+3u6OrRB/HzXqKiDI5w8cN1lWWUSFHelcXsPoWAv9jUNi1qEBaKAjmnk=,iv:gATtJAJacVoRAsYXhknZkWzASq6aMfjX10oHg3GEVuI=,tag:ekZMb7g0hD1KdjW5u85kkA==,type:str]
encrypted_regex: ^(data|stringData|email)$
version: 3.11.0