commit bfc9c119ecc8c9bc25934136af07e56e53693b91 Author: Tanguy Herbron <tanguy.herbron@outlook.com> Date: Mon Feb 24 20:25:38 2025 +0100 feat: Initial configuration diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml new file mode 100644 index 0000000..16c47ac --- /dev/null +++ b/manifests/configmap.yaml @@ -0,0 +1,210 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: immich-config + namespace: immich +data: + immich.json: | + { + "backup": { + "database": { + "cronExpression": "0 02 * * *", + "enabled": true, + "keepLastAmount": 14 + } + }, + "ffmpeg": { + "accel": "disabled", + "accelDecode": false, + "acceptedAudioCodecs": [ + "aac", + "mp3", + "libopus", + "pcm_s16le" + ], + "acceptedContainers": [ + "mov", + "ogg", + "webm" + ], + "acceptedVideoCodecs": [ + "h264" + ], + "bframes": -1, + "cqMode": "auto", + "crf": 23, + "gopSize": 0, + "maxBitrate": "0", + "preferredHwDevice": "auto", + "preset": "ultrafast", + "refs": 0, + "targetAudioCodec": "aac", + "targetResolution": "720", + "targetVideoCodec": "h264", + "temporalAQ": false, + "threads": 0, + "tonemap": "hable", + "transcode": "required", + "twoPass": false + }, + "image": { + "colorspace": "p3", + "extractEmbedded": false, + "preview": { + "format": "jpeg", + "quality": 80, + "size": 1440 + }, + "thumbnail": { + "format": "webp", + "quality": 80, + "size": 250 + } + }, + "job": { + "backgroundTask": { + "concurrency": 5 + }, + "faceDetection": { + "concurrency": 2 + }, + "library": { + "concurrency": 5 + }, + "metadataExtraction": { + "concurrency": 5 + }, + "migration": { + "concurrency": 5 + }, + "notifications": { + "concurrency": 5 + }, + "search": { + "concurrency": 5 + }, + "sidecar": { + "concurrency": 5 + }, + "smartSearch": { + "concurrency": 2 + }, + "thumbnailGeneration": { + "concurrency": 3 + }, + "videoConversion": { + "concurrency": 1 + } + }, + "library": { + "scan": { + "cronExpression": "0 0 * * *", + "enabled": true + }, + "watch": { + "enabled": false + } + }, + "logging": { + "enabled": true, + "level": "log" + }, + "machineLearning": { + "clip": { + "enabled": true, + "modelName": "ViT-B-32__openai" + }, + "duplicateDetection": { + "enabled": true, + "maxDistance": 0.01 + }, + "enabled": true, + "facialRecognition": { + "enabled": true, + "maxDistance": 0.5, + "minFaces": 3, + "minScore": 0.7, + "modelName": "buffalo_l" + }, + "urls": [ + "http://immich-svc.immich.svc.cluster.local:3003" + ] + }, + "map": { + "darkStyle": "https://tiles.immich.cloud/v1/style/dark.json", + "enabled": true, + "lightStyle": "https://tiles.immich.cloud/v1/style/light.json" + }, + "metadata": { + "faces": { + "import": false + } + }, + "newVersionCheck": { + "enabled": true + }, + "notifications": { + "smtp": { + "enabled": false, + "from": "", + "replyTo": "", + "transport": { + "host": "", + "ignoreCert": false, + "password": "", + "port": 587, + "username": "" + } + } + }, + "oauth": { + "autoLaunch": false, + "autoRegister": true, + "buttonText": "Login with OAuth", + "clientId": "", + "clientSecret": "", + "defaultStorageQuota": 0, + "enabled": false, + "issuerUrl": "", + "mobileOverrideEnabled": false, + "mobileRedirectUri": "", + "profileSigningAlgorithm": "none", + "scope": "openid email profile", + "signingAlgorithm": "RS256", + "storageLabelClaim": "preferred_username", + "storageQuotaClaim": "immich_quota" + }, + "passwordLogin": { + "enabled": true + }, + "reverseGeocoding": { + "enabled": true + }, + "server": { + "externalDomain": "", + "loginPageMessage": "", + "publicUsers": true + }, + "storageTemplate": { + "enabled": true, + "hashVerificationEnabled": true, + "template": "{{y}}/{{dd}}-{{MM}}/{{filename}}" + }, + "templates": { + "email": { + "albumInviteTemplate": "", + "albumUpdateTemplate": "", + "welcomeTemplate": "" + } + }, + "theme": { + "customCss": "" + }, + "trash": { + "days": 30, + "enabled": true + }, + "user": { + "deleteDelay": 7 + } + } diff --git a/manifests/database-backup.yaml b/manifests/database-backup.yaml new file mode 100644 index 0000000..70f2e49 --- /dev/null +++ b/manifests/database-backup.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: immich-db-backup + namespace: immich +spec: + schedule: "0 0 0 * * *" + backupOwnerReference: self + cluster: + name: immich-db diff --git a/manifests/database-ondemand-backup.yaml b/manifests/database-ondemand-backup.yaml new file mode 100644 index 0000000..0ac8991 --- /dev/null +++ b/manifests/database-ondemand-backup.yaml @@ -0,0 +1,8 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +metadata: + name: gitea-db-ondemand-backup-100225 + namespace: gitea +spec: + cluster: + name: gitea-db diff --git a/manifests/database-recovery.yaml b/manifests/database-recovery.yaml new file mode 100644 index 0000000..a8940ac --- /dev/null +++ b/manifests/database-recovery.yaml @@ -0,0 +1,48 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: gitea-db + namespace: gitea + +spec: + instances: 2 + + storage: + size: 1Gi + storageClass: local-path + + bootstrap: + recovery: + source: gitea-db + + postgresql: + pg_hba: + - host all all all md5 + + externalClusters: + - name: gitea-db + barmanObjectStore: + serverName: gitea-db + destinationPath: "s3://halis/cloudnativepg" + endpointURL: https://s3.halia.dev + s3Credentials: + accessKeyId: + name: s3-secret + key: AWS_ACCESS_KEY_ID + secretAccessKey: + name: s3-secret + key: AWS_SECRET_ACCESS_KEY + region: + name: s3-secret + key: AWS_REGION + wal: + compression: gzip + maxParallel: 8 + + resources: + requests: + cpu: 100m + memory: 100Mi + limits: + cpu: 500m + memory: 500Mi diff --git a/manifests/database.yaml b/manifests/database.yaml new file mode 100644 index 0000000..8ed693b --- /dev/null +++ b/manifests/database.yaml @@ -0,0 +1,73 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: immich-db + namespace: immich + +spec: + imageName: ghcr.io/tensorchord/cloudnative-pgvecto.rs:16.5-v0.3.0 + instances: 1 + + storage: + size: 1Gi + storageClass: local-path + + bootstrap: + initdb: + database: immich + owner: immich + secret: + name: immich-db + postInitSQL: + - ALTER SYSTEM SET search_path TO "$user", public, vectors; + - CREATE EXTENSION IF NOT EXISTS "vectors"; + dataChecksums: true + + postgresql: + pg_hba: + - host all all all md5 + shared_preload_libraries: + - "vectors.so" + parameters: + max_wal_size: 2GB + shared_buffers: 512MB + wal_compression: on + + backup: + barmanObjectStore: + destinationPath: "s3://halis/cloudnativepg" + endpointURL: https://s3.halia.dev + s3Credentials: + accessKeyId: + name: s3-secret + key: AWS_ACCESS_KEY_ID + secretAccessKey: + name: s3-secret + key: AWS_SECRET_ACCESS_KEY + region: + name: s3-secret + key: AWS_REGION + wal: + compression: gzip + maxParallel: 8 + + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 500m + memory: 1024Mi + + monitoring: + enablePodMonitor: true + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - worker-1 diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml new file mode 100644 index 0000000..fbf881b --- /dev/null +++ b/manifests/deployment.yaml @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: immich + namespace: immich +spec: + replicas: 1 + selector: + matchLabels: + app: immich + template: + metadata: + labels: + app: immich + spec: + hostname: immich + subdomain: immich + containers: + - name: immich-server + image: ghcr.io/immich-app/immich-server:v1.126.1 + ports: + - containerPort: 2283 + - containerPort: 8081 + name: metrics + env: + - name: IMMICH_TELEMETRY_INCLUDE + value: "all" + - name: IMMICH_CONFIG_FILE + value: "/usr/src/app/config/immich.json" + - name: REDIS_HOSTNAME + value: "redis-svc.immich.svc.cluster.local" + - name: REDIS_PORT + value: "6379" + - name: DB_HOSTNAME + value: "immich-db-rw.immich.svc.cluster.local" + - name: DB_USERNAME + valueFrom: + secretKeyRef: + name: immich-db + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: immich-db + key: password + volumeMounts: + - mountPath: "/usr/src/app/upload" + name: immich-upload + - mountPath: "/etc/localtime" + name: localtime + readOnly: true + - mountPath: "/usr/src/app/config/immich.json" + name: immich-config + subPath: immich.json + - name: immich-machine-learning + image: ghcr.io/immich-app/immich-machine-learning:v1.126.1 + ports: + - containerPort: 3003 + volumeMounts: + - mountPath: "/cache" + name: immich-model + - name: redis + image: redis:7.4.2 + ports: + - containerPort: 6379 + volumes: + - name: immich-upload + persistentVolumeClaim: + claimName: immich-pvc + - name: immich-model + persistentVolumeClaim: + claimName: immich-model-pvc + - name: immich-config + configMap: + name: immich-config + - name: localtime + hostPath: + path: /etc/localtime diff --git a/manifests/ingress.yaml b/manifests/ingress.yaml new file mode 100644 index 0000000..b1ea021 --- /dev/null +++ b/manifests/ingress.yaml @@ -0,0 +1,29 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: immich-ingress + namespace: immich + annotations: + cert-manager.io/cluster-issuer: letsencrypt-production + kubernetes.io/ingress.class: nginx-external + acme.cert-manager.io/http01-edit-in-place: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-read-timeout: "600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "600" +spec: + tls: + - hosts: + - photos.halis.io + secretName: photos-halis-io-tls + ingressClassName: nginx-external + rules: + - host: photos.halis.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: immich-svc + port: + number: 80 diff --git a/manifests/kustomization.yaml b/manifests/kustomization.yaml new file mode 100644 index 0000000..47c5f32 --- /dev/null +++ b/manifests/kustomization.yaml @@ -0,0 +1,16 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - namespace.yaml + - secrets.yaml + - database.yaml + - deployment.yaml + - database-backup.yaml + - service.yaml + - servicemonitor.yaml + - redis-service.yaml + - ingress.yaml + - configmap.yaml + - pvc.yaml + - model-pvc.yaml diff --git a/manifests/model-pvc.yaml b/manifests/model-pvc.yaml new file mode 100644 index 0000000..2d46aaf --- /dev/null +++ b/manifests/model-pvc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: immich-model-pvc + namespace: immich + labels: + recurring-job.longhorn.io/source: enabled + recurring-job-group.longhorn.io/standard-pvc: enabled +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + storageClassName: redundant-storage-class diff --git a/manifests/namespace.yaml b/manifests/namespace.yaml new file mode 100644 index 0000000..c796392 --- /dev/null +++ b/manifests/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: immich diff --git a/manifests/pvc.yaml b/manifests/pvc.yaml new file mode 100644 index 0000000..601e4b2 --- /dev/null +++ b/manifests/pvc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: immich-pvc + namespace: immich + labels: + recurring-job.longhorn.io/source: enabled + recurring-job-group.longhorn.io/standard-pvc: enabled +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi + storageClassName: redundant-storage-class diff --git a/manifests/redis-service.yaml b/manifests/redis-service.yaml new file mode 100644 index 0000000..54c244c --- /dev/null +++ b/manifests/redis-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: redis-svc + namespace: immich + labels: + app.kubernetes.io/name: immich +spec: + ports: + - name: http + port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: immich diff --git a/manifests/secrets.yaml b/manifests/secrets.yaml new file mode 100644 index 0000000..146750f --- /dev/null +++ b/manifests/secrets.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: immich-secrets + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + source: + repoURL: https://git.halis.io/athens-school/k3s-secrets + targetRevision: prod-migration + path: immich + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false + - ApplyOutOfSyncOnly=true + - PruneLast=true + destination: + server: https://kubernetes.default.svc + namespace: immich diff --git a/manifests/service.yaml b/manifests/service.yaml new file mode 100644 index 0000000..0c57900 --- /dev/null +++ b/manifests/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: immich-svc + namespace: immich + labels: + app.kubernetes.io/name: immich +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 2283 + - name: ml + port: 3003 + protocol: TCP + targetPort: 3003 + selector: + app: immich diff --git a/manifests/servicemonitor.yaml b/manifests/servicemonitor.yaml new file mode 100644 index 0000000..199c504 --- /dev/null +++ b/manifests/servicemonitor.yaml @@ -0,0 +1,14 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: immich + namespace: immich + labels: + team: core +spec: + selector: + matchLabels: + app.kubernetes.io/name: immich + endpoints: + - port: metrics + path: /metrics