Immich

Prerequisites

This guide assumes you have the following prerequisites in place:

Immich

Immich is a self-hosted photo and video backup solution. It provides a secure and private way to store and manage your media files.

Installation

  1. Create the following directory structure for Immich:

     immich/
     β”œβ”€β”€ immich-db.yml
     β”œβ”€β”€ immich-ingress.yml
     β”œβ”€β”€ immich-ml.yml
     β”œβ”€β”€ immich-pvc.yml
     β”œβ”€β”€ immich-redis.yml
     β”œβ”€β”€ immich-secret.yml
     β”œβ”€β”€ immich-service.yml
     └── immich.yml
    • Create this Dockerfile for custom postgres image:
      ARG PG_MAJOR=17
      ARG VCHORD_VERSION=1.1.1
      
      FROM ghcr.io/zalando/spilo-17:4.0-p3
      
      ARG PG_MAJOR
      ARG VCHORD_VERSION
      
      USER root
      
      RUN apt-get update && \
          apt-get install -y --no-install-recommends \
              postgresql-${PG_MAJOR}-pgvector && \
          rm -rf /var/lib/apt/lists/*
      
      RUN set -eux; \
          ARCH=$(dpkg --print-architecture); \
          DEB_URL="https://github.com/tensorchord/VectorChord/releases/download/${VCHORD_VERSION}/postgresql-${PG_MAJOR}-vchord_${VCHORD_VERSION}-1_${ARCH}.deb"; \
          curl -fsSL -o /tmp/vchord.deb "${DEB_URL}"; \
          dpkg -i /tmp/vchord.deb; \
          rm /tmp/vchord.deb
      
      USER postgres
    • Build and push to custom docker registry:
      docker build -t registry.com/username/repo:version
      docker push registry.com/username/repo:version
    • Create the immich-db.yml file:
      ---
      apiVersion: acid.zalan.do/v1
      kind: postgresql
      metadata:
        name: immich-db-cluster
        namespace: media
      spec:
        teamId: prod
        numberOfInstances: 2
      
        dockerImage: registry.com/username/repo:version
      
        postgresql:
          version: "17"
          parameters:
            shared_preload_libraries: "bg_mon,pg_stat_statements,pgextwlist,pg_auth_mon,pg_cron,pg_stat_kcache,vchord"
            extwlist.extensions: "btree_gin,btree_gist,citext,extra_window_functions,first_last_agg,hll,hstore,hypopg,intarray,ltree,pgcrypto,pgq,pgq_node,pg_trgm,postgres_fdw,roaringbitmap,tablefunc,uuid-ossp,vector,vchord,timescaledb,pg_partman"
      
        preparedDatabases:
          immich:
            defaultUsers: true
            extensions:
              vchord: public
              vector: public
              earthdistance: public
              cube: public
              pg_trgm: public
              unaccent: public
              uuid-ossp: public
              plpgsql: public
            schemas:
              public: {}
            secretNamespace: media
      
        volume:
          size: 5Gi
          storageClass: longhorn
      
        initContainers:
          - name: fix-permissions
            image: busybox
            command:
              - sh
              - -c
              - |
                chmod 2775 /home/postgres/pgdata
                chown 0:103 /home/postgres/pgdata
                mkdir -p /home/postgres/pgdata/pgroot
                chown -R 101:103 /home/postgres/pgdata/pgroot
                chmod 750 /home/postgres/pgdata/pgroot
            volumeMounts:
              - name: pgdata
                mountPath: /home/postgres/pgdata
            securityContext:
              runAsUser: 0
  2. Add the following content to immich/immich-ingress.yml:

    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: immich-ingress
      namespace: media
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-cloudflare
        traefik.ingress.kubernetes.io/router.entrypoints: websecure
    spec:
      ingressClassName: traefik
      tls:
      - hosts:
        - immich.example.com
        secretName: immich-tls
      rules:
      - host: immich.example.com
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: immich-service
                port:
                  number: 2283
  3. Add the following content to immich/immich-ml.yml:

    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: immich-ml
      namespace: media
    spec:
      strategy:
        type: Recreate
      replicas: 1
      selector:
        matchLabels:
          app: immich-ml
      template:
        metadata:
          labels:
            app: immich-ml
        spec:
          #runtimeClassName: nvidia                                            # For Nvidia GPUs only
          containers:
          - name: immich-machine-learning
            #image: ghcr.io/immich-app/immich-machine-learning:v2.5.6-cuda     # For NVIDIA GPUs, use the CUDA image
            #image: ghcr.io/immich-app/immich-machine-learning:v2.5.6-openvino # For Intel GPUs, use the OpenVINO image
            image: ghcr.io/immich-app/immich-machine-learning:v2.5.6           # For CPU-only, use the standard image
            ports:
            - containerPort: 3003
            env:
            - name: REDIS_HOSTNAME
              value: "immich-redis-service"
            #- name: NVIDIA_VISIBLE_DEVICES                                    # For NVIDIA GPUs only
            #  value: "all"                                                    # For NVIDIA GPUs only
            #- name: MACHINE_LEARNING_DEVICE_IDS                               # For NVIDIA GPUs only
            #  value: "0"                                                      # For NVIDIA GPUS only
            volumeMounts:
            - name: model-cache
              mountPath: /cache
            #- name: dri                                                       # For Intel GPUs only
            #  mountPath: /dev/dri                                             # For Intel GPUs only
            # For NVIDIA GPUs, uncomment the following lines to request GPU resources
            #resources:
            #  requests:
            #    nvidia.com/gpu: "1"
            #  limits:
            #    nvidia.com/gpu: "1"
            # For Intel GPUs, uncomment the following lines to request GPU resources
            #resources:
            #  limits:
            #    gpu.intel.com/i915: "1"
            #  requests:
            #    gpu.intel.com/i915: "1"
          volumes:
          - name: model-cache
            persistentVolumeClaim:
              claimName: immich-cache-longhorn
          #- name: dri                                                         # For Intel GPUs only
          #  hostPath:                                                         # For Intel GPUs only
          #    path: /dev/dri                                                  # For Intel GPUs only
  4. Add the following content to immich/immich-pvc.yml:

    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: immich-cache-longhorn
      namespace: media
    spec:
      accessModes:
        - ReadWriteOnce
      volumeMode: Filesystem
      resources:
        requests:
          storage: 10Gi
      storageClassName: longhorn
    
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: immich-pictures-pvc
      namespace: media
    spec:
      accessModes:
        - ReadWriteMany
      storageClassName: immich-pictures-pv
      resources:
        requests:
          storage: 100Gi
  5. Add the following content to immich/immich-redis.yml:

    ---
    apiVersion: dragonflydb.io/v1alpha1
    kind: Dragonfly
    metadata:
      name: immich-redis
      namespace: media
    spec:
      replicas: 3
      resources:
        requests:
          cpu: 100m
          memory: 128Mi
        limits:
          cpu: 500m
          memory: 512Mi
      args:
        - --maxmemory=256mb
  6. Add the following content to immich/immich-service.yml:

    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: immich-service
      namespace: media
    spec:
      selector:
        app: immich-app
      ports:
      - port: 2283
        targetPort: 2283
    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: immich-machine-learning-service
      namespace: media
    spec:
      selector:
        app: immich-ml
      ports:
      - port: 3003
        targetPort: 3003
    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: immich-psql
      namespace: media
    spec:
      selector:
        app: immich-psql
      ports:
        - name: postgres
          port: 5432
          targetPort: 5432
      clusterIP: None
    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: immich-redis
      namespace: media
    spec:
      selector:
        app: immich-redis
      ports:
        - name: redis
          port: 6379
          targetPort: 6379
      clusterIP: None
  7. Add the following content to immich/immich.yml:

    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: immich-app
      namespace: media
    spec:
      strategy:
        type: Recreate
      replicas: 1
      selector:
        matchLabels:
          app: immich-app
      template:
        metadata:
          labels:
            app: immich-app
        spec:
          containers:
          - name: immich-server
            image: ghcr.io/immich-app/immich-server:v2.5.6
            ports:
            - containerPort: 2283
            env:
            - name: REDIS_HOSTNAME
              value: "immich-redis.media.svc.cluster.local"
            - name: DB_USERNAME
              value: "postgres"
            - name: DB_DATABASE_NAME
              value: "immich"
            - name: DB_HOSTNAME
              value: "immich-db-cluster.media.svc.cluster.local"
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres.immich-db-cluster.credentials.postgresql.acid.zalan.do
                  key: password
            volumeMounts:
            - mountPath: /usr/src/app/upload
              name: pictures
          volumes:
          - name: pictures
            nfs:
              server: <nfs-server-ip>
              path: <nfs-export-path>
  8. Commit and push the changes to your Git repository. Flux will automatically deploy Immich to your Kubernetes cluster.