Immich Deployment Notes
This guide summarizes key configuration details for running Immich with GitOps.
Prerequisites
- Kubernetes cluster with the Zalando Postgres Operator (
acid.zalan.do/v1
) installed immich
namespace created- External Secrets Operator available
- Helm CLI and
kubectl
configured
Configuration Overview
PostgreSQL Extensions
Ensure the Immich database includes the pgvector
and vectorchord
extensions:
# k8s/applications/media/immich/database.yaml
spec:
preparedDatabases:
immich:
extensions:
pgvector: public
vectorchord: public
Templated DB_URL
The application expects a single DB_URL
. Use ExternalSecrets to assemble the connection string:
# k8s/applications/media/immich/externalsecret.yaml
template:
data:
DB_URL: >-
postgres://immich:{{ .password }}@immich-postgresql:5432/immich?sslmode=require&sslmode=no-verify
External Secrets Permissions
Reference the cluster CA and grant read access to the Zalando secret:
zalando-k8s-store.yaml
referenceskube-root-ca.crt
.serviceaccount.yaml
grantsget
,list
, andwatch
on secrets as well asselfsubjectrulesreviews
.
Kustomization Layout
Use a root kustomization.yaml
to track all resources:
resources:
- namespace.yaml
- http-route.yaml
- externalsecret.yaml
- database.yaml
- pvc.yaml
- zalando-k8s-store.yaml
- serviceaccount.yaml
OAuth Configuration via ExternalSecret
Immich expects the OAuth client details inside its config file. The immich-config-external-secret.yaml
resource pulls these values from Bitwarden and renders the full configuration as a Secret:
# k8s/applications/media/immich/immich-server/immich-config-external-secret.yaml
spec:
template:
data:
immich-config.yaml: |
...
server:
externalDomain: https://photo.pc-tips.se
oauth:
enabled: true
issuerUrl: "https://sso.pc-tips.se/application/o/immich/"
scope: "openid email profile"
autoLaunch: true
autoRegister: true
buttonText: "Login with SSO"
clientId: "{{ .clientId }}"
clientSecret: "{{ .clientSecret }}"
passwordLogin:
enabled: false
This Secret is mounted by the StatefulSet at /config/immich-config.yaml
, allowing the application to start without additional environment variables.
The machine-learning deployment mounts the same Secret so both components read identical settings.
Resource Requests
Both pods need enough memory to process photos without crashing. A good starting point is:
Component | CPU Request | Memory Request | CPU Limit | Memory Limit |
---|---|---|---|---|
immich-server | 500m | 512Mi | 2000m | 2Gi |
immich-machine-learning | 200m | 1Gi | 1000m | 4Gi |
Library Storage
Immich stores uploaded files on a Persistent Volume Claim named library
. The claim
requests 40Gi from Longhorn:
# k8s/applications/media/immich/immich-server/statefulset.yaml
spec:
volumeClaimTemplates:
- metadata:
name: library
spec:
storageClassName: longhorn
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 40Gi