apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: immich namespace: cicd finalizers: - resources-finalizer.argocd.argoproj.io spec: project: default sources: # Deploy custom resources (PVs, PVCs, PostgreSQL, Middleware) - repoURL: http://git-server.cicd.svc.cluster.local/conf.git targetRevision: master path: f3s/immich/helm-chart # Deploy Immich Helm chart with custom values - repoURL: https://immich-app.github.io/immich-charts/ chart: immich targetRevision: 0.10.3 helm: releaseName: immich values: | valkey: enabled: true controllers: main: containers: main: probes: # NFS-aware liveness: valkey-cli must PONG AND a write to the # NFS-backed /data volume must succeed. Catches the "reads OK but # writes return ESTALE" stale-bind-mount state that follows a CARP # failover / NFS remount (the default ping-only probe stays green # because reads are served from the stale handle). On failure the # container restarts, which re-binds hostPath to the now-healthy # host NFS mount and clears the stale handle. liveness: enabled: true custom: true spec: exec: command: - sh - -c - "valkey-cli ping | grep -q PONG && echo probe > /data/.nfs-write-probe && rm -f /data/.nfs-write-probe" initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 10 failureThreshold: 3 persistence: data: enabled: true type: persistentVolumeClaim size: 1Gi storageClass: "" existingClaim: "immich-valkey-pvc" immich: persistence: library: existingClaim: "immich-library-pvc" server: enabled: true controllers: main: pod: labels: # Opt in to the node-level nfs-mount-monitor stale-bind-mount # reaper. The server's liveness probe is an HTTP /ping that # never touches the NFS volume, so a stale /data bind-mount # (writes return ESTALE, uploads 500) leaves the pod Running # and Ready and cannot self-heal. The chart hardcodes the # httpGet liveness and its value-merge refills httpGet, so an # in-pod exec write-probe cannot be set via Helm values (as is # done for valkey). Instead the node monitor execs a write # probe into this pod and recreates it when writes fail. nfs.stale-restart/enabled: "true" containers: main: image: # v3.x drops the pgvecto.rs extension; the Postgres bundle # was migrated to VectorChord first (Stage A), so the DB is # 3.x-ready and preloads vchord.so + vectors.so as 3.0.1+ needs. tag: v3.0.3 resources: requests: cpu: 500m memory: 512Mi limits: memory: 4Gi affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: - machine-learning topologyKey: "kubernetes.io/hostname" persistence: ext-albena-rw: enabled: true type: persistentVolumeClaim existingClaim: immich-ext-albena-pvc globalMounts: - path: /external-albena-rw ext-paul-rw: enabled: true type: persistentVolumeClaim existingClaim: immich-ext-paul-pvc globalMounts: - path: /external-paul-rw ext-videos-rw: enabled: true type: persistentVolumeClaim existingClaim: immich-ext-videos-rw-pvc globalMounts: - path: /external-videos-rw ext-videos-ro: enabled: true type: persistentVolumeClaim existingClaim: immich-ext-videos-ro-pvc globalMounts: - path: /external-videos-ro readOnly: true ingress: main: enabled: true annotations: spec.ingressClassName: traefik traefik.ingress.kubernetes.io/router.entrypoints: web traefik.ingress.kubernetes.io/router.middlewares: services-immich-body-size@kubernetescrd hosts: - host: immich.f3s.buetow.org paths: - path: "/" service: identifier: main port: 2283 machine-learning: enabled: true controllers: main: containers: main: image: # v3.x drops the pgvecto.rs extension; the Postgres bundle # was migrated to VectorChord first (Stage A), so the DB is # 3.x-ready and preloads vchord.so + vectors.so as 3.0.1+ needs. tag: v3.0.3 env: MACHINE_LEARNING_MODEL_INTRA_OP_THREADS: "4" MACHINE_LEARNING_MODEL_INTER_OP_THREADS: "1" MACHINE_LEARNING_WORKER_TIMEOUT: "300" resources: requests: cpu: 500m memory: 512Mi limits: memory: 4Gi pod: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: - server topologyKey: "kubernetes.io/hostname" - weight: 80 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - immich-postgres topologyKey: "kubernetes.io/hostname" persistence: cache: enabled: true type: persistentVolumeClaim size: 10Gi storageClass: "" existingClaim: "immich-ml-cache-pvc" controllers: main: containers: main: env: DB_HOSTNAME: immich-postgres DB_DATABASE_NAME: immich DB_USERNAME: immich DB_PASSWORD: valueFrom: secretKeyRef: name: immich-db-secret key: password destination: server: https://kubernetes.default.svc namespace: services syncPolicy: automated: prune: false selfHeal: true syncOptions: - CreateNamespace=false retry: limit: 3 backoff: duration: 5s factor: 2 maxDuration: 1m