From feb76efafcbefde1befc542affc6dc2ecd3809fe Mon Sep 17 00:00:00 2001 From: Tanguy Herbron Date: Thu, 20 Mar 2025 13:39:58 +0100 Subject: [PATCH] feat: Initial commit --- README.md | 0 manifests/configmap.yaml | 210 ++++++++++++++++++++++++ manifests/database-backup.yaml | 10 ++ manifests/database-ondemand-backup.yaml | 8 + manifests/database-recovery.yaml | 55 +++++++ manifests/database.yaml | 52 ++++++ manifests/deployment.yaml | 70 ++++++++ manifests/ingress.yaml | 29 ++++ manifests/kustomization.yaml | 13 ++ manifests/namespace.yaml | 4 + manifests/pvc.yaml | 15 ++ manifests/redis-service.yaml | 15 ++ manifests/secrets.yaml | 24 +++ manifests/service.yaml | 15 ++ manifests/servicemonitor.yaml | 18 ++ 15 files changed, 538 insertions(+) create mode 100644 README.md create mode 100644 manifests/configmap.yaml create mode 100644 manifests/database-backup.yaml create mode 100644 manifests/database-ondemand-backup.yaml create mode 100644 manifests/database-recovery.yaml create mode 100644 manifests/database.yaml create mode 100644 manifests/deployment.yaml create mode 100644 manifests/ingress.yaml create mode 100644 manifests/kustomization.yaml create mode 100644 manifests/namespace.yaml create mode 100644 manifests/pvc.yaml create mode 100644 manifests/redis-service.yaml create mode 100644 manifests/secrets.yaml create mode 100644 manifests/service.yaml create mode 100644 manifests/servicemonitor.yaml 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..0a76fc0 --- /dev/null +++ b/manifests/database-backup.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: postiz-db-backup + namespace: postiz +spec: + schedule: "0 0 0 * * *" + backupOwnerReference: self + cluster: + name: postiz-db diff --git a/manifests/database-ondemand-backup.yaml b/manifests/database-ondemand-backup.yaml new file mode 100644 index 0000000..555ae18 --- /dev/null +++ b/manifests/database-ondemand-backup.yaml @@ -0,0 +1,8 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +metadata: + name: immich-db-ondemand-backup-280225 + namespace: immich +spec: + cluster: + name: immich-db diff --git a/manifests/database-recovery.yaml b/manifests/database-recovery.yaml new file mode 100644 index 0000000..93f6df1 --- /dev/null +++ b/manifests/database-recovery.yaml @@ -0,0 +1,55 @@ +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: + recovery: + source: immich-db + + postgresql: + pg_hba: + - host all all all md5 + shared_preload_libraries: + - "vectors.so" + parameters: + max_wal_size: "2GB" + shared_buffers: "512MB" + wal_compression: "on" + + externalClusters: + - name: immich-db + barmanObjectStore: + serverName: immich-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: 512Mi + limits: + cpu: 500m + memory: 1Gi diff --git a/manifests/database.yaml b/manifests/database.yaml new file mode 100644 index 0000000..f64f170 --- /dev/null +++ b/manifests/database.yaml @@ -0,0 +1,52 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: postiz-db + namespace: postiz + +spec: + instances: 3 + + storage: + size: 1Gi + storageClass: local-path + + bootstrap: + initdb: + database: postiz + owner: postiz + secret: + name: postiz-db + + postgresql: + pg_hba: + - host all all all md5 + + 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: 1Gi + + monitoring: + enablePodMonitor: true diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml new file mode 100644 index 0000000..7bcd1c5 --- /dev/null +++ b/manifests/deployment.yaml @@ -0,0 +1,70 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postiz + namespace: postiz +spec: + replicas: 1 + selector: + matchLabels: + app: postiz + template: + metadata: + labels: + app: postiz + spec: + containers: + - name: postiz-web + image: ghcr.io/gitroomhq/postiz-app:v1.36.1-arm64 + ports: + - containerPort: 5000 + envFrom: + - secretRef: + name: postiz-providers + env: + - name: MAIN_URL + value: "https://postiz.halis.io" + - name: FRONTEND_URL + value: "https://postiz.halis.io" + - name: NEXT_PUBLIC_BACKEND_URL + value: "https://postiz.halis.io/api" + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: postiz-secrets + key: JWT_SECRET + - name: DB_USER + valueFrom: + secretKeyRef: + name: postiz-db + key: username + - name: DB_PASS + valueFrom: + secretKeyRef: + name: postiz-db + key: password + - name: DATABASE_URL + value: "postgresql://$(DB_USER):$(DB_PASS)@postiz-db-rw.postiz.svc.cluster.local:5432/postiz" + - name: REDIS_URL + value: "redis://redis-svc.postiz.svc.cluster.local:6379" + - name: BACKEND_INTERNAL_URL + value: "http://localhost:3000" + - name: IS_GENERAL + value: "true" + - name: STORAGE_PROVIDER + value: "local" + - name: UPLOAD_DIRECTORY + value: "/uploads" + - name: NEXT_PUBLIC_UPLOAD_DIRECTORY + value: "/uploads" + volumeMounts: + - mountPath: "/uploads" + name: postiz-data + - name: redis + image: redis:7.4.2 + ports: + - containerPort: 6379 + volumes: + - name: postiz-data + persistentVolumeClaim: + claimName: postiz-pvc diff --git a/manifests/ingress.yaml b/manifests/ingress.yaml new file mode 100644 index 0000000..339a25a --- /dev/null +++ b/manifests/ingress.yaml @@ -0,0 +1,29 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: postiz-ingress + namespace: postiz + 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: + - postiz.halis.io + secretName: postiz-halis-io-tls + ingressClassName: nginx-external + rules: + - host: postiz.halis.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: postiz-svc + port: + number: 80 diff --git a/manifests/kustomization.yaml b/manifests/kustomization.yaml new file mode 100644 index 0000000..c707e96 --- /dev/null +++ b/manifests/kustomization.yaml @@ -0,0 +1,13 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - namespace.yaml + - secrets.yaml + - database.yaml + - deployment.yaml + - database-backup.yaml + - service.yaml + - redis-service.yaml + - ingress.yaml + - pvc.yaml diff --git a/manifests/namespace.yaml b/manifests/namespace.yaml new file mode 100644 index 0000000..0c4d534 --- /dev/null +++ b/manifests/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: postiz diff --git a/manifests/pvc.yaml b/manifests/pvc.yaml new file mode 100644 index 0000000..a8e8bfa --- /dev/null +++ b/manifests/pvc.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postiz-pvc + namespace: postiz + labels: + recurring-job.longhorn.io/source: enabled + recurring-job-group.longhorn.io/standard-pvc: enabled +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 20Gi + storageClassName: redundant-storage-class diff --git a/manifests/redis-service.yaml b/manifests/redis-service.yaml new file mode 100644 index 0000000..c6fe63d --- /dev/null +++ b/manifests/redis-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: redis-svc + namespace: postiz + labels: + app.kubernetes.io/name: postiz +spec: + ports: + - name: http + port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: postiz diff --git a/manifests/secrets.yaml b/manifests/secrets.yaml new file mode 100644 index 0000000..f519514 --- /dev/null +++ b/manifests/secrets.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: postiz-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: postiz + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false + - ApplyOutOfSyncOnly=true + - PruneLast=true + destination: + server: https://kubernetes.default.svc + namespace: postiz diff --git a/manifests/service.yaml b/manifests/service.yaml new file mode 100644 index 0000000..d1fea43 --- /dev/null +++ b/manifests/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: postiz-svc + namespace: postiz + labels: + app.kubernetes.io/name: postiz +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 5000 + selector: + app: postiz diff --git a/manifests/servicemonitor.yaml b/manifests/servicemonitor.yaml new file mode 100644 index 0000000..acf0b29 --- /dev/null +++ b/manifests/servicemonitor.yaml @@ -0,0 +1,18 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: postiz + namespace: postiz + labels: + team: core +spec: + selector: + matchLabels: + app.kubernetes.io/name: postiz + endpoints: + - port: streaming + path: /metrics + - port: web-metrics + path: /metrics + - port: sidekiq-metrics + path: /metrics