diff --git a/argocd/apps/immich.yaml b/argocd/apps/immich.yaml deleted file mode 100644 index 7efd263..0000000 --- a/argocd/apps/immich.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Immich - Self-hosted photo and video management -# High-performance Google Photos/iCloud alternative with AI features -# -# Kustomize manifests in argocd/manifests/immich/ -# Components: server, machine-learning, valkey (Redis) -# -# Prerequisites: -# 1. Create immich namespace and secrets: -# kubectl create namespace immich -# kubectl --context=minikube-indri create secret generic immich-db -n immich \ -# --from-literal=password="$(kubectl --context=minikube-indri -n databases get secret immich-pg-app -o jsonpath='{.data.password}' | base64 -d)" -# 2. Create immich-pg database and user (see immich-pg app) -# 3. NFS share on sifaka at /volume1/photos with read/write for indri -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: immich - namespace: argocd -spec: - project: default - source: - repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git - targetRevision: main - path: argocd/manifests/immich - destination: - server: https://kubernetes.default.svc - namespace: immich - syncPolicy: - syncOptions: - - CreateNamespace=true diff --git a/argocd/manifests/databases-ringtail/kustomization.yaml b/argocd/manifests/databases-ringtail/kustomization.yaml index 5c44bc2..971e2d4 100644 --- a/argocd/manifests/databases-ringtail/kustomization.yaml +++ b/argocd/manifests/databases-ringtail/kustomization.yaml @@ -6,3 +6,4 @@ namespace: databases resources: - immich-pg.yaml - external-secret-immich-borgmatic.yaml + - service-immich-pg-tailscale.yaml diff --git a/argocd/manifests/databases/service-immich-pg-tailscale.yaml b/argocd/manifests/databases-ringtail/service-immich-pg-tailscale.yaml similarity index 57% rename from argocd/manifests/databases/service-immich-pg-tailscale.yaml rename to argocd/manifests/databases-ringtail/service-immich-pg-tailscale.yaml index 78891dd..92deb14 100644 --- a/argocd/manifests/databases/service-immich-pg-tailscale.yaml +++ b/argocd/manifests/databases-ringtail/service-immich-pg-tailscale.yaml @@ -1,6 +1,8 @@ -# Tailscale LoadBalancer for immich-pg PostgreSQL access -# Canonical hostname: immich-pg.tail8d86e.ts.net -# Caddy L4 proxies pg.ops.eblu.me:5433 → this service for borgmatic backups +# Tailscale LoadBalancer for immich-pg PostgreSQL access on ringtail. +# Canonical hostname: immich-pg.tail8d86e.ts.net (claimed from the +# minikube side after the minikube service was removed during the +# immich-to-ringtail migration). Borgmatic on indri uses this +# hostname for nightly backups. apiVersion: v1 kind: Service metadata: diff --git a/argocd/manifests/databases/external-secret-immich-borgmatic.yaml b/argocd/manifests/databases/external-secret-immich-borgmatic.yaml deleted file mode 100644 index 8801c1a..0000000 --- a/argocd/manifests/databases/external-secret-immich-borgmatic.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# ExternalSecret for borgmatic backup user password on immich-pg cluster -# -# Reuses the same 1Password item as blumeops-pg-borgmatic. -# 1Password item: "borgmatic" in blumeops vault -# Field: "db-password" -# -apiVersion: external-secrets.io/v1 -kind: ExternalSecret -metadata: - name: immich-pg-borgmatic - namespace: databases -spec: - refreshInterval: 1h - secretStoreRef: - kind: ClusterSecretStore - name: onepassword-blumeops - target: - name: immich-pg-borgmatic - creationPolicy: Owner - template: - type: kubernetes.io/basic-auth - data: - username: borgmatic - password: "{{ .password }}" - data: - - secretKey: password - remoteRef: - key: borgmatic - property: db-password diff --git a/argocd/manifests/databases/immich-pg.yaml b/argocd/manifests/databases/immich-pg.yaml deleted file mode 100644 index 74c6f4e..0000000 --- a/argocd/manifests/databases/immich-pg.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# PostgreSQL Cluster for Immich -# Uses VectorChord (successor to pgvecto.rs) for AI-powered vector search -# See: https://github.com/immich-app/immich/discussions/9060 -# Managed by CloudNativePG operator -apiVersion: postgresql.cnpg.io/v1 -kind: Cluster -metadata: - name: immich-pg - namespace: databases -spec: - instances: 1 - # VectorChord image for PostgreSQL 17 with VectorChord 0.5.0 - # Immich v2.4.1 requires VectorChord >=0.3 <0.6 - # See: https://github.com/tensorchord/VectorChord - imageName: ghcr.io/tensorchord/cloudnative-vectorchord:17-0.5.0 - - storage: - size: 10Gi - storageClass: standard - - # Bootstrap creates initial database and owner - bootstrap: - initdb: - database: immich - owner: immich - postInitSQL: - # Extensions required by Immich - - CREATE EXTENSION IF NOT EXISTS vector; - - CREATE EXTENSION IF NOT EXISTS vchord CASCADE; - - CREATE EXTENSION IF NOT EXISTS cube CASCADE; - - CREATE EXTENSION IF NOT EXISTS earthdistance CASCADE; - - # Managed roles - # Note: connectionLimit, ensure, inherit are CNPG defaults added to prevent ArgoCD drift - managed: - roles: - # borgmatic read-only user for backups - - name: borgmatic - login: true - connectionLimit: -1 - ensure: present - inherit: true - inRoles: - - pg_read_all_data - passwordSecret: - name: immich-pg-borgmatic - - # Resource limits for minikube environment - resources: - requests: - memory: "256Mi" - cpu: "100m" - limits: - memory: "1Gi" - cpu: "500m" - - # PostgreSQL configuration - postgresql: - # VectorChord requires vchord.so in shared_preload_libraries - shared_preload_libraries: - - "vchord.so" - parameters: - max_connections: "50" - shared_buffers: "128MB" - password_encryption: "scram-sha-256" - pg_hba: - # Allow connections from k8s pods - - host all all 0.0.0.0/0 scram-sha-256 - - host all all ::/0 scram-sha-256 diff --git a/argocd/manifests/databases/kustomization.yaml b/argocd/manifests/databases/kustomization.yaml index b25e09e..692285a 100644 --- a/argocd/manifests/databases/kustomization.yaml +++ b/argocd/manifests/databases/kustomization.yaml @@ -5,13 +5,10 @@ namespace: databases resources: - blumeops-pg.yaml - - immich-pg.yaml - service-tailscale.yaml - - service-immich-pg-tailscale.yaml - service-metrics-tailscale.yaml - external-secret-eblume.yaml - external-secret-borgmatic.yaml - - external-secret-immich-borgmatic.yaml - external-secret-teslamate.yaml - external-secret-authentik.yaml - external-secret-paperless.yaml diff --git a/argocd/manifests/immich/README.md b/argocd/manifests/immich/README.md deleted file mode 100644 index a82a856..0000000 --- a/argocd/manifests/immich/README.md +++ /dev/null @@ -1,115 +0,0 @@ -# Immich - -Self-hosted photo and video management solution with AI-powered search and face recognition. - -## Prerequisites - -1. **NFS Share**: Create `/volume1/photos` on sifaka with NFS permissions for indri -2. **PostgreSQL**: The `immich-pg` cluster (with pgvecto.rs) must be healthy -3. **Secrets**: Create the database password secret - -## Deployment Order - -1. Sync `blumeops-pg` (to get CloudNativePG operator if not already running) -2. Wait for `immich-pg` cluster to be healthy -3. Create secrets (see below) -4. Sync `immich` (deploys all resources: storage, services, deployments) -5. Run `mise run provision-indri -- --tags caddy` to update Caddy config - -## Components - -| Component | Deployment | Service | Port | -|-----------|------------|---------|------| -| Server (web/API) | `immich-server` | `immich-server` | 2283 | -| Machine Learning | `immich-machine-learning` | `immich-machine-learning` | 3003 | -| Valkey (Redis) | `immich-valkey` | `immich-valkey` | 6379 | - -## Secret Setup - -The `immich-db` secret contains the database password, which is auto-generated by CloudNativePG -in the `immich-pg-app` secret. To create or regenerate the secret: - -```bash -# Create namespace if needed -kubectl --context=minikube-indri create namespace immich - -# Copy password from CNPG secret to immich namespace -kubectl --context=minikube-indri create secret generic immich-db -n immich \ - --from-literal=password="$(kubectl --context=minikube-indri -n databases get secret immich-pg-app -o jsonpath='{.data.password}' | base64 -d)" -``` - -Note: This secret is not managed by ExternalSecrets since the source of truth is the CNPG-generated secret. - -## Access - -- **URL**: https://photos.ops.eblu.me (after Caddy is updated) -- **Tailscale**: https://photos.tail8d86e.ts.net (direct) - -## First-Time Setup - -1. Navigate to https://photos.ops.eblu.me -2. Create an admin account -3. Configure external library (optional - for importing existing photos) - -## External Library (iCloud Photos) - -To import existing photos from iCloud sync on indri: - -1. In Immich Admin > External Libraries, create a new library -2. Set the import path to the location where iCloud photos sync -3. Configure scan schedule or trigger manual scan - -## Architecture - -``` -┌─────────────────┐ ┌─────────────────┐ -│ immich-server │────▶│ immich-pg │ -│ (web/api) │ │ (PostgreSQL │ -└────────┬────────┘ │ + pgvecto.rs) │ - │ └─────────────────┘ - │ -┌────────▼────────┐ ┌─────────────────┐ -│ immich-ml │ │ valkey │ -│ (ML inference) │ │ (Redis cache) │ -└─────────────────┘ └─────────────────┘ - │ -┌────────▼────────┐ -│ sifaka NFS │ -│ /volume1/photos│ -└─────────────────┘ -``` - -## Version Management - -Image versions are controlled via `kustomization.yaml`: - -```yaml -images: - - name: ghcr.io/immich-app/immich-server - newTag: v2.6.3 - - name: ghcr.io/immich-app/immich-machine-learning - newTag: v2.6.3 - - name: docker.io/valkey/valkey - newTag: "8.1-alpine" -``` - -To upgrade, update `newTag` values and sync via ArgoCD. - -## Troubleshooting - -```bash -# Check pods -kubectl --context=minikube-indri -n immich get pods - -# Check immich-pg cluster -kubectl --context=minikube-indri -n databases get cluster immich-pg - -# View server logs -kubectl --context=minikube-indri -n immich logs -l app=immich,component=server - -# View ML logs -kubectl --context=minikube-indri -n immich logs -l app=immich,component=machine-learning - -# Check PVC binding -kubectl --context=minikube-indri -n immich get pvc -``` diff --git a/argocd/manifests/immich/deployment-ml.yaml b/argocd/manifests/immich/deployment-ml.yaml deleted file mode 100644 index 57c4242..0000000 --- a/argocd/manifests/immich/deployment-ml.yaml +++ /dev/null @@ -1,63 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: immich-machine-learning - namespace: immich -spec: - replicas: 1 - selector: - matchLabels: - app: immich - component: machine-learning - template: - metadata: - labels: - app: immich - component: machine-learning - spec: - securityContext: - seccompProfile: - type: RuntimeDefault - containers: - - name: machine-learning - image: ghcr.io/immich-app/immich-machine-learning:kustomized - ports: - - name: http - containerPort: 3003 - env: - - name: TZ - value: "America/Los_Angeles" - - name: TRANSFORMERS_CACHE - value: /cache - - name: HF_XET_CACHE - value: /cache/huggingface-xet - - name: MPLCONFIGDIR - value: /cache/matplotlib-config - volumeMounts: - - name: cache - mountPath: /cache - livenessProbe: - httpGet: - path: /ping - port: 3003 - initialDelaySeconds: 30 - periodSeconds: 30 - timeoutSeconds: 5 - readinessProbe: - httpGet: - path: /ping - port: 3003 - initialDelaySeconds: 15 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - memory: "512Mi" - cpu: "100m" - limits: - memory: "4Gi" - volumes: - - name: cache - persistentVolumeClaim: - claimName: immich-ml-cache diff --git a/argocd/manifests/immich/deployment-server.yaml b/argocd/manifests/immich/deployment-server.yaml deleted file mode 100644 index 8ac7ab0..0000000 --- a/argocd/manifests/immich/deployment-server.yaml +++ /dev/null @@ -1,74 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: immich-server - namespace: immich -spec: - replicas: 1 - selector: - matchLabels: - app: immich - component: server - template: - metadata: - labels: - app: immich - component: server - spec: - securityContext: - seccompProfile: - type: RuntimeDefault - containers: - - name: server - image: ghcr.io/immich-app/immich-server:kustomized - ports: - - name: http - containerPort: 2283 - env: - - name: TZ - value: "America/Los_Angeles" - - name: DB_HOSTNAME - value: "immich-pg-rw.databases.svc.cluster.local" - - name: DB_PORT - value: "5432" - - name: DB_DATABASE_NAME - value: "immich" - - name: DB_USERNAME - value: "immich" - - name: DB_PASSWORD - valueFrom: - secretKeyRef: - name: immich-db - key: password - - name: REDIS_HOSTNAME - value: immich-valkey - - name: IMMICH_MACHINE_LEARNING_URL - value: "http://immich-machine-learning:3003" - volumeMounts: - - name: library - mountPath: /usr/src/app/upload - livenessProbe: - httpGet: - path: /api/server/ping - port: 2283 - initialDelaySeconds: 30 - periodSeconds: 30 - timeoutSeconds: 5 - readinessProbe: - httpGet: - path: /api/server/ping - port: 2283 - initialDelaySeconds: 15 - periodSeconds: 10 - timeoutSeconds: 5 - resources: - requests: - memory: "256Mi" - cpu: "100m" - limits: - memory: "2Gi" - volumes: - - name: library - persistentVolumeClaim: - claimName: immich-library diff --git a/argocd/manifests/immich/deployment-valkey.yaml b/argocd/manifests/immich/deployment-valkey.yaml deleted file mode 100644 index 1cf3346..0000000 --- a/argocd/manifests/immich/deployment-valkey.yaml +++ /dev/null @@ -1,42 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: immich-valkey - namespace: immich -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - app: immich - component: valkey - template: - metadata: - labels: - app: immich - component: valkey - spec: - securityContext: - seccompProfile: - type: RuntimeDefault - containers: - - name: valkey - image: docker.io/valkey/valkey:kustomized - ports: - - name: redis - containerPort: 6379 - volumeMounts: - - name: data - mountPath: /data - resources: - requests: - memory: "64Mi" - cpu: "25m" - limits: - memory: "256Mi" - volumes: - - name: data - emptyDir: - sizeLimit: 1Gi diff --git a/argocd/manifests/immich/ingress-tailscale.yaml b/argocd/manifests/immich/ingress-tailscale.yaml deleted file mode 100644 index 59a4c05..0000000 --- a/argocd/manifests/immich/ingress-tailscale.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Tailscale Ingress for Immich -# Exposes Immich at photos.tail8d86e.ts.net -# Caddy will proxy photos.ops.eblu.me to this endpoint -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: immich-tailscale - namespace: immich - annotations: - tailscale.com/funnel: "false" - tailscale.com/proxy-group: "ingress" - gethomepage.dev/enabled: "true" - gethomepage.dev/name: "Immich" - gethomepage.dev/group: "Content" - gethomepage.dev/icon: "immich.png" - gethomepage.dev/description: "Photo management" - gethomepage.dev/href: "https://photos.ops.eblu.me" - gethomepage.dev/pod-selector: "app=immich,component=server" - # TODO: Add Immich widget - requires API key from Account Settings > API Keys - # See: https://gethomepage.dev/widgets/services/immich/ - # gethomepage.dev/widget.type: "immich" - # gethomepage.dev/widget.url: "https://photos.ops.eblu.me" - # gethomepage.dev/widget.key: "{{HOMEPAGE_VAR_IMMICH_API_KEY}}" - # gethomepage.dev/widget.version: "2" -spec: - ingressClassName: tailscale - rules: - - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: immich-server - port: - number: 2283 - tls: - - hosts: - - photos diff --git a/argocd/manifests/immich/kustomization.yaml b/argocd/manifests/immich/kustomization.yaml deleted file mode 100644 index 5f8d02b..0000000 --- a/argocd/manifests/immich/kustomization.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -namespace: immich -resources: - - deployment-server.yaml - - deployment-ml.yaml - - deployment-valkey.yaml - - service.yaml - - service-ml.yaml - - service-valkey.yaml - - pvc-ml-cache.yaml - - pv-nfs.yaml - - pvc.yaml - - ingress-tailscale.yaml -images: - - name: ghcr.io/immich-app/immich-server - newTag: v2.6.3 - - name: ghcr.io/immich-app/immich-machine-learning - newTag: v2.6.3 - - name: docker.io/valkey/valkey - newName: registry.ops.eblu.me/blumeops/valkey - newTag: v8.1.6-r0-fabca04 diff --git a/argocd/manifests/immich/pv-nfs.yaml b/argocd/manifests/immich/pv-nfs.yaml deleted file mode 100644 index 0bd6ee2..0000000 --- a/argocd/manifests/immich/pv-nfs.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# NFS PersistentVolume for Immich photo library -# Requires: NFS share on sifaka at /volume1/photos with NFS permissions for indri -# -# To create on Synology: -# 1. Control Panel > Shared Folder > Create -# 2. Name: photos, Location: Volume 1 -# 3. Control Panel > File Services > NFS > NFS Rules -# 4. Add rule for "photos" share: Hostname=indri, Privilege=Read/Write, Squash=No mapping -apiVersion: v1 -kind: PersistentVolume -metadata: - name: immich-library-nfs-pv -spec: - capacity: - storage: 2Ti - accessModes: - - ReadWriteMany - persistentVolumeReclaimPolicy: Retain - storageClassName: "" - nfs: - server: sifaka - path: /volume1/photos diff --git a/argocd/manifests/immich/pvc-ml-cache.yaml b/argocd/manifests/immich/pvc-ml-cache.yaml deleted file mode 100644 index 1e5a3d6..0000000 --- a/argocd/manifests/immich/pvc-ml-cache.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: immich-ml-cache - namespace: immich -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi diff --git a/argocd/manifests/immich/pvc.yaml b/argocd/manifests/immich/pvc.yaml deleted file mode 100644 index c764636..0000000 --- a/argocd/manifests/immich/pvc.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# PersistentVolumeClaim for Immich photo library -# Binds to the NFS PV for sifaka:/volume1/photos -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: immich-library - namespace: immich -spec: - accessModes: - - ReadWriteMany - storageClassName: "" - volumeName: immich-library-nfs-pv - resources: - requests: - storage: 2Ti diff --git a/argocd/manifests/immich/service-ml.yaml b/argocd/manifests/immich/service-ml.yaml deleted file mode 100644 index 9bb935a..0000000 --- a/argocd/manifests/immich/service-ml.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: immich-machine-learning - namespace: immich -spec: - selector: - app: immich - component: machine-learning - ports: - - name: http - port: 3003 - targetPort: 3003 diff --git a/argocd/manifests/immich/service-valkey.yaml b/argocd/manifests/immich/service-valkey.yaml deleted file mode 100644 index eb42d3b..0000000 --- a/argocd/manifests/immich/service-valkey.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: immich-valkey - namespace: immich -spec: - selector: - app: immich - component: valkey - ports: - - name: redis - port: 6379 - targetPort: 6379 diff --git a/argocd/manifests/immich/service.yaml b/argocd/manifests/immich/service.yaml deleted file mode 100644 index d35410f..0000000 --- a/argocd/manifests/immich/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: immich-server - namespace: immich -spec: - selector: - app: immich - component: server - ports: - - name: http - port: 2283 - targetPort: 2283