apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: immich-server namespace: photo spec: interval: 30m chartRef: kind: OCIRepository name: immich driftDetection: mode: enabled values: controllers: server: containers: app: image: repository: ghcr.io/immich-app/immich-server tag: release env: TZ: Europe/Moscow DB_HOSTNAME: immich-postgres DB_PORT: "5432" DB_USERNAME: postgres DB_DATABASE_NAME: immich DB_PASSWORD: valueFrom: secretKeyRef: name: immich-secrets key: DB_PASSWORD REDIS_HOSTNAME: immich-redis REDIS_PORT: "6379" IMMICH_MACHINE_LEARNING_URL: http://immich-ml:3003 probes: # first boot runs DB migrations + vector index setup, which # can take a while - without a startup probe the default # liveness probe (periodSeconds=10, failureThreshold=3) kills # the container ~30s in, well before it's finished binding # the port, causing an endless restart loop. startup: enabled: true spec: periodSeconds: 5 failureThreshold: 60 liveness: enabled: true readiness: enabled: true resources: requests: cpu: 200m memory: 512Mi limits: memory: 4Gi # one-shot migration copy from the old NAS-hosted docker install # into this install's own library volume (see "library" below). # rsync is idempotent, so a pod restart mid-copy just resumes # cleanly; once done it sleeps forever instead of exiting, so the # container doesn't restart-loop and the status page stays up. rsync: image: repository: python tag: 3.13-alpine command: - sh - -c - apk add --no-cache rsync >/dev/null && python3 /app/rsync.py resources: requests: cpu: 50m memory: 64Mi limits: memory: 256Mi rsync-web: image: repository: nginx tag: 1.27-alpine probes: # explicit port: this controller has two services (app:2283, # rsync-web:80) and probe auto-detection picks the # controller's primary service port rather than this # container's own - without this it checks the wrong port. liveness: enabled: true port: 80 readiness: enabled: true port: 80 resources: requests: cpu: 10m memory: 16Mi limits: memory: 64Mi service: app: controller: server ports: http: port: 2283 rsync-web: controller: server ports: http: port: 80 ingress: app: className: traefik annotations: cert-manager.io/cluster-issuer: letsencrypt-prod hosts: - host: photo.aggtaa.com paths: - path: / pathType: Prefix service: identifier: app port: http tls: - secretName: immich-tls hosts: - photo.aggtaa.com rsync-web: className: traefik annotations: cert-manager.io/cluster-issuer: letsencrypt-prod hosts: - host: rsync.photo.aggtaa.com paths: - path: / pathType: Prefix service: identifier: rsync-web port: http tls: - secretName: immich-rsync-tls hosts: - rsync.photo.aggtaa.com persistence: # brand new, dedicated library - deliberately not reusing the old # docker-compose install's NAS data, and not nfs-photo either. library: type: persistentVolumeClaim accessMode: ReadWriteOnce size: 800Gi storageClass: longhorn-single-replica retain: true globalMounts: - path: /data nas-source: type: persistentVolumeClaim existingClaim: immich-nas-source advancedMounts: server: rsync: - path: /source readOnly: true rsync-script: type: configMap name: immich-rsync-script advancedMounts: server: rsync: - path: /app/rsync.py subPath: rsync.py readOnly: true rsync-www: type: emptyDir advancedMounts: server: rsync: - path: /www rsync-web: - path: /usr/share/nginx/html