diff options
| author | Robert Günzler <r@gnzler.io> | 2025-09-07 17:32:13 +0200 |
|---|---|---|
| committer | Robert Günzler <r@gnzler.io> | 2025-09-07 17:42:42 +0200 |
| commit | 38be6c13f76e893cf47636257071b440dec0c5b2 (patch) | |
| tree | f7ded3235a7e3362cbd1ed3d91523968fe0faf90 /bundles/immich | |
initial commit
Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to 'bundles/immich')
| -rwxr-xr-x | bundles/immich/files/immich-api-tool | 49 | ||||
| -rw-r--r-- | bundles/immich/files/immich.yaml | 27 | ||||
| -rw-r--r-- | bundles/immich/files/kube.yaml | 104 | ||||
| -rw-r--r-- | bundles/immich/files/secret.yaml | 12 | ||||
| -rw-r--r-- | bundles/immich/items.py | 15 | ||||
| -rw-r--r-- | bundles/immich/metadata.py | 17 |
6 files changed, 224 insertions, 0 deletions
diff --git a/bundles/immich/files/immich-api-tool b/bundles/immich/files/immich-api-tool new file mode 100755 index 0000000..d0a1a41 --- /dev/null +++ b/bundles/immich/files/immich-api-tool @@ -0,0 +1,49 @@ +#!/bin/sh +set -eu + +API_URL=https://photos.gzr.im/api +API_KEY=zaJUJGHpFqY9OA6kAhuauTj9tC1YVfA8umtZc6ls8U + +request() { + ENDPOINT=${1:?} + shift 1 + + curl -sSfL "${API_URL}${ENDPOINT}" \ + -H "x-api-key: $API_KEY" \ + -H 'Content-Type: application/json' \ + "$@" +} + +validateAccessToken() { + request '/auth/validateToken' -X POST >/dev/null +} + +# returns full json response +searchFavorites() { + request '/search/metadata' \ + -H 'Accept: application/json' \ + -d '{"isFavorite": true}' +} + +# requires '{"assetIds":["list","of","ids",...]}' on stdin +# downloads to PWD +downloadArchive() { + request '/download/archive' \ + -H 'Accept: application/octet-stream' \ + -d @- \ + -o "archive.zip" \ + --no-silent +} + +main() { + validateAccessToken || exit 1 + + # download favorites as archive + searchFavorites | + jq '[.assets.items[].id] | {assetIds:.}' -rc | + downloadArchive +} + +test -n "${DEBUG:-}" && set -x +main +exit 0 diff --git a/bundles/immich/files/immich.yaml b/bundles/immich/files/immich.yaml new file mode 100644 index 0000000..fd2454a --- /dev/null +++ b/bundles/immich/files/immich.yaml @@ -0,0 +1,27 @@ +storageTemplate: + enabled: false + hashVerificationEnabled: true + template: '{{y}}/{{MM}}-{{MMM}}/{{filetype}}_{{y}}{{MM}}{{dd}}_{{HH}}{{mm}}{{ss}}.{{ext}}' + +machineLearning: + enabled: false + # url: + +passwordLogin: + enabled: false +oauth: + enabled: true + autoLaunch: true + autoRegister: true + clientId: immich + clientSecret: '${repo.vault.password_for("authelia_client_secret_immich")}' + issuerUrl: https://login.gzr.im/.well-known/openid-configuration + # scope: 'openid email profile' + # profileSigningAlgorithm: none + # defaultStorageQuota: 0 + # signingAlgorithm: RS256 + # storageLabelClaim: preferred_username + # storageQuotaClaim: immich_quota + buttonText: 'Login with SSO' + # mobileOverrideEnabled: false + # mobileRedirectUri: https://photos.gzr.im/api/oauth/mobile-redirect diff --git a/bundles/immich/files/kube.yaml b/bundles/immich/files/kube.yaml new file mode 100644 index 0000000..523c073 --- /dev/null +++ b/bundles/immich/files/kube.yaml @@ -0,0 +1,104 @@ +apiVersion: v1 +kind: Pod +metadata: + name: immich + labels: + traefik.enable: true + traefik.http.routers.immich.tls: true + traefik.http.routers.immich.tls.certresolver: le + traefik.http.routers.immich.entrypoints: http,https + traefik.http.routers.immich.rule: Host(`photos.gzr.im`) + traefik.http.routers.immich.service: immich + traefik.http.services.immich.loadbalancer.server.port: 2283 + + # TODO: https://immich.app/docs/features/monitoring + # https://github.com/immich-app/immich/blob/v1.121.0/docker/prometheus.yml + # + # metrics + # traefik.http.routers.immich-metrics.entrypoints: metrics + # traefik.http.routers.immich-metrics.rule: Path(`/metrics/immich`) + # traefik.http.routers.immich-metrics.middlewares: replacepath-metrics +spec: + restartPolicy: Always + dnsPolicy: Default + containers: + - name: immich + image: ghcr.io/immich-app/immich-server:v1.140.1 + envFrom: + - secretRef: + name: immich + env: + - name: IMMICH_CONFIG_FILE + value: /immich.yaml + ports: + - containerPort: 2283 + protocol: TCP + # NOTE: required to make tv app work + hostPort: 2283 + volumeMounts: + - name: config + mountPath: /immich.yaml + - name: data + mountPath: /usr/src/app/upload + - name: media + mountPath: /media + readOnly: true + # resources: + # limits: + # cpu: 300m + # memory: 512Mi + - name: redis + image: docker.io/redis:6.2-alpine@sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8 + livenessProbe: + exec: + command: ["sh", "-c", "redis-cli ping || exit 1"] + - name: postgres + image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 + envFrom: + - secretRef: + name: immich + env: + - name: POSTGRES_INITDB_ARGS + value: --data-checksums + volumeMounts: + - name: pg-data + mountPath: /var/lib/postgresql/data + livenessProbe: + exec: + command: + - /bin/sh + - -c + - pg_isready --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' || exit 1 + # ; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1 + command: + - docker-entrypoint.sh + - -c + - shared_preload_libraries=vectors.so + - -c + - search_path="$$user", public, vectors + - -c + - logging_collector=on + - -c + - max_wal_size=2GB + - -c + - shared_buffers=512MB + - -c + - wal_compression=on + + volumes: + - name: config + hostPath: + path: /var/lib/immich/immich.yaml + type: File + - name: data + hostPath: + path: /var/lib/immich/app + type: DirectoryOrCreate + - name: pg-data + hostPath: + path: /var/lib/immich/db + type: DirectoryOrCreate + - name: media + hostPath: + path: /media/hayasui/media + type: Directory diff --git a/bundles/immich/files/secret.yaml b/bundles/immich/files/secret.yaml new file mode 100644 index 0000000..daf0f4f --- /dev/null +++ b/bundles/immich/files/secret.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Secret +metadata: + name: immich +data: + DB_USERNAME: ${repo.libs.util.base64("immich")} + POSTGRES_USER: ${repo.libs.util.base64("immich")} + DB_PASSWORD: ${repo.vault.password_for("immich_db_pw").b64encode().value} + POSTGRES_PASSWORD: ${repo.vault.password_for("immich_db_pw").b64encode().value} + DB_DATABASE_NAME: ${repo.libs.util.base64("immich")} + POSTGRES_DB: ${repo.libs.util.base64("immich")} + DB_HOSTNAME: ${repo.libs.util.base64(f"localhost")} diff --git a/bundles/immich/items.py b/bundles/immich/items.py new file mode 100644 index 0000000..450027c --- /dev/null +++ b/bundles/immich/items.py @@ -0,0 +1,15 @@ +files = { + "/etc/deployments/immich/kube.yaml": { + "triggers": {"svc_s6rc:immich:restart"}, + }, + "/etc/deployments/immich/secret.yaml": { + "content_type": "mako", + "mode": "0600", + "triggers": {"svc_s6rc:immich:restart"}, + }, + "/var/lib/immich/immich.yaml": { + "content_type": "mako", + "mode": "0600", + "triggers": {"svc_s6rc:immich:restart"}, + }, +} diff --git a/bundles/immich/metadata.py b/bundles/immich/metadata.py new file mode 100644 index 0000000..2a0a806 --- /dev/null +++ b/bundles/immich/metadata.py @@ -0,0 +1,17 @@ +defaults = { + # https://immich.app/docs/administration/backup-and-restore/#manual-backup-and-restore + "backup": { + "includes": { + "/var/lib/immich/app/backups", + "/var/lib/immich/app/profile", + "/var/lib/immich/app/upload", + # "/media/hayasui/media/pictures", + } + }, + "containers": { + "immich": {}, + }, + # "metrics": { + # "immich": {}, + # }, +} |