From 2efe24dac928edf3776133064fb42e26a84d762a Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sun, 16 Jun 2024 16:46:08 +0200 Subject: [PATCH] Make permanent Immich deployment --- kubenix-modules/all.nix | 1 + kubenix-modules/base.nix | 20 -- kubenix-modules/immich.nix | 246 +++++++++++++++++++ kubenix-modules/volumes.nix | 3 +- nixos-modules/monitoring/gatus-endpoints.nix | 230 ----------------- secrets/kubernetes.yaml | 6 +- 6 files changed, 253 insertions(+), 253 deletions(-) create mode 100644 kubenix-modules/immich.nix delete mode 100644 nixos-modules/monitoring/gatus-endpoints.nix diff --git a/kubenix-modules/all.nix b/kubenix-modules/all.nix index 196271e..eb470c4 100644 --- a/kubenix-modules/all.nix +++ b/kubenix-modules/all.nix @@ -18,6 +18,7 @@ let ./blog.nix ./attic.nix ./atuin.nix + ./immich.nix # ./argo.nix # ./minecraft.nix ]; diff --git a/kubenix-modules/base.nix b/kubenix-modules/base.nix index 9cab73f..018f126 100644 --- a/kubenix-modules/base.nix +++ b/kubenix-modules/base.nix @@ -57,16 +57,6 @@ }; }; }; - - immich = { - chart = nixhelm.chartsDerivations.${system}.immich.immich; - includeCRDs = true; - values = { - immich.persistence.library.existingClaim = "immich-test"; - redis.enabled = true; - postgresql.enabled = true; - }; - }; }; resources.nodes = @@ -79,15 +69,5 @@ }) machinesWithKubernetesLabels; }; - - lab.ingresses.immich-test = { - host = "immich.kun.is"; - entrypoint = "localsecure"; - - service = { - name = "immich-server"; - portName = "http"; - }; - }; }; } diff --git a/kubenix-modules/immich.nix b/kubenix-modules/immich.nix new file mode 100644 index 0000000..c344197 --- /dev/null +++ b/kubenix-modules/immich.nix @@ -0,0 +1,246 @@ +{ + kubernetes.resources = { + deployments = { + immich-server = { + metadata.labels = { + app = "immich"; + component = "server"; + }; + + spec = { + selector.matchLabels = { + app = "immich"; + component = "server"; + }; + + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { + app = "immich"; + component = "server"; + }; + + spec = { + volumes.data.persistentVolumeClaim.claimName = "immich"; + + containers.immich = { + image = "ghcr.io/immich-app/immich-server:v1.106.4"; + imagePullPolicy = "Always"; + ports.web.containerPort = 3001; + + env = { + TZ.value = "Europe/Amsterdam"; + UPLOAD_LOCATION.value = "/library"; + # IMMICH_CONFIG_FILE.value = "?"; + REDIS_HOSTNAME.value = "immich-redis.default.svc.cluster.local"; + DB_HOSTNAME.value = "immich-postgres.default.svc.cluster.local"; + DB_USERNAME.value = "postgres"; + DB_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; + DB_DATABASE_NAME.value = "immich"; + IMMICH_MACHINE_LEARNING_URL.value = "http://immich-ml.default.svc.cluster.local"; + }; + + volumeMounts = [{ + name = "data"; + mountPath = "/library"; + }]; + }; + }; + }; + }; + }; + + immich-ml = { + metadata.labels = { + app = "immich"; + component = "machine-learning"; + }; + + spec = { + selector.matchLabels = { + app = "immich"; + component = "machine-learning"; + }; + + template = { + metadata.labels = { + app = "immich"; + component = "machine-learning"; + }; + + spec = { + containers.machine-learning = { + image = "ghcr.io/immich-app/immich-machine-learning:v1.106.4"; + imagePullPolicy = "Always"; + ports.ml.containerPort = 3003; + }; + }; + }; + }; + }; + + immich-redis = { + metadata.labels = { + app = "immich"; + component = "redis"; + }; + + spec = { + selector.matchLabels = { + app = "immich"; + component = "redis"; + }; + + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { + app = "immich"; + component = "redis"; + }; + + spec = { + containers.redis = { + image = "docker.io/redis:6.2-alpine@sha256:d6c2911ac51b289db208767581a5d154544f2b2fe4914ea5056443f62dc6e900"; + ports.redis.containerPort = 6379; + imagePullPolicy = "Always"; + }; + }; + }; + }; + }; + + immich-database = { + metadata.labels = { + app = "immich"; + component = "database"; + }; + + spec = { + selector.matchLabels = { + app = "immich"; + component = "database"; + }; + + strategy = { + type = "RollingUpdate"; + + rollingUpdate = { + maxSurge = 0; + maxUnavailable = 1; + }; + }; + + template = { + metadata.labels = { + app = "immich"; + component = "database"; + }; + + spec = { + volumes.data.persistentVolumeClaim.claimName = "immich-db"; + # securityContext.fsGroup = 0700; + + containers.postgres = { + image = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0"; + imagePullPolicy = "Always"; + command = [ "postgres" ]; + args = [ "-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" ]; + ports.postgres.containerPort = 5432; + securityContext.runAsUser = 999; + securityContext.runAsGroup = 999; + + env = { + POSTGRES_PASSWORD.value = "ref+sops://secrets/kubernetes.yaml#/immich/databasePassword"; + POSTGRES_USER.value = "postgres"; + POSTGRES_DB.value = "immich"; + POSTGRES_INITDB_ARGS.value = "--data-checksums"; + PGDATA.value = "/pgdata/data"; + }; + + volumeMounts = [{ + name = "data"; + mountPath = "/pgdata"; + }]; + }; + }; + }; + }; + }; + }; + + services = { + immich-server.spec = { + selector = { + app = "immich"; + component = "server"; + }; + + ports.web = { + port = 80; + targetPort = "web"; + }; + }; + + immich-redis.spec = { + selector = { + app = "immich"; + component = "redis"; + }; + + ports.redis = { + port = 6379; + targetPort = "redis"; + }; + }; + + immich-ml.spec = { + selector = { + app = "immich"; + component = "machine-learning"; + }; + + ports.machine-learning = { + port = 80; + targetPort = "ml"; + }; + }; + + immich-postgres.spec = { + selector = { + app = "immich"; + component = "database"; + }; + + ports.postgres = { + port = 5432; + targetPort = "postgres"; + }; + }; + }; + }; + + lab.ingresses.immich-test = { + host = "immich.kun.is"; + + service = { + name = "immich-server"; + portName = "web"; + }; + }; +} diff --git a/kubenix-modules/volumes.nix b/kubenix-modules/volumes.nix index 9231b7c..7ea3e15 100644 --- a/kubenix-modules/volumes.nix +++ b/kubenix-modules/volumes.nix @@ -25,9 +25,10 @@ bazarr.storage = "25Mi"; attic.storage = "15Gi"; attic-db.storage = "150Mi"; - immich-test.storage = "10Gi"; atuin.storage = "600Mi"; atuin-db.storage = "100Mi"; + immich.storage = "50Gi"; + immich-db.storage = "1Gi"; }; nfsVolumes = { diff --git a/nixos-modules/monitoring/gatus-endpoints.nix b/nixos-modules/monitoring/gatus-endpoints.nix deleted file mode 100644 index b5893cd..0000000 --- a/nixos-modules/monitoring/gatus-endpoints.nix +++ /dev/null @@ -1,230 +0,0 @@ -{ lib, config, machines, ... }: -let - cfg = config.lab.monitoring; - - status = code: "[STATUS] == ${toString code}"; - bodyContains = text: "[BODY] == pat(*${text}*)"; - maxResponseTime = ms: "[RESPONSE_TIME] < ${toString ms}"; - - machineEndpoints = lib.attrsets.mapAttrsToList - (name: machine: { - name = "Host ${name}"; - url = "icmp://${name}.dmz"; - conditions = [ "[RESPONSE_TIME] < 10" ]; - }) - machines; - - otherEndpoints = [ - { - name = "Forgejo"; - url = "https://git.kun.is"; - conditions = [ - (status 200) - (bodyContains "Forgejo: Beyond coding. We forge.") - (maxResponseTime 750) - ]; - } - { - name = "Nextcloud"; - url = "https://cloud.kun.is/status.php"; - conditions = [ - (status 200) - "[BODY].installed == true" - "[BODY].maintenance == false" - "[BODY].needsDbUpgrade == false" - (maxResponseTime 2000) - ]; - } - { - name = "Paperless-ngx"; - url = "https://paperless.kun.is/accounts/login/"; - conditions = [ - (status 200) - (bodyContains "Please sign in.") - (maxResponseTime 750) - ]; - } - { - name = "Radicale"; - url = "https://dav.kun.is/.web/"; - conditions = [ - (status 200) - (bodyContains "Login") - (maxResponseTime 750) - ]; - } - { - name = "FreshRSS"; - url = "https://rss.kun.is/i/"; - conditions = [ - (status 200) - (bodyContains "Login") - (maxResponseTime 750) - ]; - } - { - name = "KitchenOwl"; - url = "https://boodschappen.kun.is/signin"; - conditions = [ - (status 200) - (bodyContains "KitchenOwl") - (maxResponseTime 750) - ]; - } - { - name = "HedgeDoc"; - url = "https://md.kun.is/"; - conditions = [ - (status 200) - (bodyContains "The best platform to write and share markdown.") - (maxResponseTime 750) - ]; - } - { - name = "Cyberchef"; - url = "https://cyberchef.kun.is/"; - conditions = [ - (status 200) - (bodyContains "CyberChef - The Cyber Swiss Army Knife") - (maxResponseTime 750) - ]; - } - { - name = "Pi-hole"; - url = "https://pihole.kun.is:444/admin/login.php"; - conditions = [ - (status 200) - (bodyContains "Log in") - (maxResponseTime 750) - ]; - } - { - name = "Inbucket"; - url = "https://inbucket.kun.is:444/"; - conditions = [ - (status 200) - (bodyContains "Inbucket") - (maxResponseTime 750) - ]; - } - { - name = "kms"; - url = "tcp://kms.kun.is:1688"; - conditions = [ - "[CONNECTED] == true" - ]; - } - { - name = "Bazarr"; - url = "https://bazarr.kun.is:444/system/status"; - conditions = [ - (status 200) - (bodyContains "Bazarr") - (maxResponseTime 750) - ]; - } - { - name = "Sonarr"; - url = "https://sonarr.kun.is:444/system/status"; - conditions = [ - (status 200) - (bodyContains "Sonarr") - (maxResponseTime 750) - ]; - } - { - name = "Radarr"; - url = "https://radarr.kun.is:444/system/status"; - conditions = [ - (status 200) - (bodyContains "Radarr") - (maxResponseTime 750) - ]; - } - { - name = "Jellyfin"; - url = "https://media.kun.is/web/index.html#!/login.html?"; - conditions = [ - (status 200) - (bodyContains "Jellyfin") - (maxResponseTime 750) - ]; - } - { - name = "Jellyseerr"; - url = "https://jellyseerr.kun.is:444/login"; - conditions = [ - (status 200) - (bodyContains "Sign in to continue") - (maxResponseTime 750) - ]; - } - { - name = "Prowlarr"; - url = "https://prowlarr.kun.is:444/system/status"; - conditions = [ - (status 200) - (bodyContains "Prowlarr") - (maxResponseTime 750) - ]; - } - { - name = "Transmission"; - url = "https://transmission.kun.is:444/transmission/web/"; - conditions = [ - (status 200) - (bodyContains "Transmission Web Interface") - (maxResponseTime 750) - ]; - } - { - name = "Syncthing"; - url = "https://sync.kun.is:444/"; - conditions = [ - (status 401) - (maxResponseTime 750) - ]; - } - { - name = "Traefik"; - url = "https://traefik.kun.is:444/dashboard/#/"; - conditions = [ - (status 200) - (bodyContains "Traefik") - (maxResponseTime 750) - ]; - } - { - name = "BIND"; - url = "192.168.30.7"; - dns = { - query-type = "SOA"; - query-name = "kun.is"; - }; - conditions = [ - "[DNS_RCODE] == NOERROR" - ]; - } - { - name = "Pi-hole DNS"; - url = "192.168.30.8"; - dns = { - query-type = "SOA"; - query-name = "kun.is"; - }; - conditions = [ - "[DNS_RCODE] == NOERROR" - ]; - } - ]; -in -{ - config = lib.mkIf cfg.server.enable { - services.gatus.settings.endpoints = map - (endpoint: endpoint // { - interval = "5m"; - alerts = [{ type = "email"; }]; - }) - (machineEndpoints ++ otherEndpoints); - }; -} diff --git a/secrets/kubernetes.yaml b/secrets/kubernetes.yaml index 1b4449b..21c0773 100644 --- a/secrets/kubernetes.yaml +++ b/secrets/kubernetes.yaml @@ -23,6 +23,8 @@ attic: atuin: databaseURL: ENC[AES256_GCM,data:IBmND/J2Pzz+CDCeNBRtErxSQIi8PeUuLGN4rIXKSLwZ6TGJKcNmbuxQDvWkCnI1crx3oak=,iv:wc3G/00oIuaiGF4mA2vIm35wFGxT0a3Ox3k1C9YBAx4=,tag:MQPcsR+vrD85DttYYi6jUw==,type:str] databasePassword: ENC[AES256_GCM,data:qfWOmFfBOuguOfb1Z51F527ic3o=,iv:4Yx5rpzZHzRlfvZydcBNFRStEO0P4uIcjDqxgRgQmHE=,tag:pbJXcUdvul7nCrXQ9ylAdQ==,type:str] +immich: + databasePassword: ENC[AES256_GCM,data:fZtGYiHOhYjdzBxaSdnstjlOAJE=,iv:YV+o4upajDHtwWSU6Z9h3Ncl9fXbo65KT6YMqlh2evY=,tag:BWLRc3bdnS9M70jC3SZXlA==,type:str] sops: kms: [] gcp_kms: [] @@ -47,8 +49,8 @@ sops: aHpYZ2VtdVBVTkxZbGFOYzRpbGltZHMKJs4E+CsthuzQZqA0Yip4G/1XK4SuoiRP Lo65L33lfNibdSOeIygqnyo6GBwjD52TcNQpvzkVbr3M3hWlJs8wCA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-06-15T18:55:03Z" - mac: ENC[AES256_GCM,data:THDaTY91n6nTZoDFzSOL+6m0gi+jthNJsjr8sqDO9dRyuezuMj2cJcmfZQZrhxsXIeyr+yHkCxNuqvhpVkH1k/rfQQXbOLXAfdioJepTqr/6zjMy7lr/AoBgzNlcwicE8YVevO34BNE83QqfN3GfPdDfNlE0sku9k2Eda3W61SU=,iv:VI+7Kvf3p6J3l+XAFaadplNWl6t0Xqxoy5q/1zbvp0A=,tag:JeVv8d1GXxPKfdJZ4nbGRQ==,type:str] + lastmodified: "2024-06-16T14:30:15Z" + mac: ENC[AES256_GCM,data:dGFqNLSfoWvQ88l9ZEchJkRGmKyE0Ullactg+45t6gT9qzS9Y6crV1VOZEkfv6CabDrXWsq8cgadW9bD1z+vmpnRGdnsFIzYycw36y+ibiJ7ItCkT5KO86W8EsalzSxdy+Ac89Jp3Fv1xWzWcxKAO6jz0zluv6CrUl3kk5wTfBI=,iv:tdWY4pjE6ux5rbsYG5qTqnRDjspsIXAuWXqEnR6j4qI=,tag:Sw6fdDVKB8L1Me6Sa67O6Q==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1