From e102d910bc9914356a75e99c4609f03cf7079b91 Mon Sep 17 00:00:00 2001 From: Alex Lebens Date: Sat, 29 Nov 2025 21:41:00 -0600 Subject: [PATCH] add render manifest workflow --- .gitea/workflows/render-manifests.yaml | 94 +++ clusters/cl01tl/helm/actual/Chart.yaml | 21 + .../actual/templates/external-secret.yaml | 55 ++ .../helm/actual/templates/http-route.yaml | 28 + .../actual/templates/replication-source.yaml | 25 + clusters/cl01tl/helm/actual/values.yaml | 56 ++ .../cl01tl/helm/audiobookshelf/Chart.yaml | 23 + .../templates/external-secret.yaml | 135 +++ .../audiobookshelf/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 36 + .../templates/persistent-volume.yaml | 23 + .../templates/replication-source.yaml | 52 ++ .../templates/service-monitor.yaml | 19 + .../cl01tl/helm/audiobookshelf/values.yaml | 94 +++ clusters/cl01tl/helm/bazarr/Chart.yaml | 23 + .../bazarr/templates/external-secret.yaml | 55 ++ .../helm/bazarr/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../bazarr/templates/persistent-volume.yaml | 23 + .../bazarr/templates/replication-source.yaml | 30 + clusters/cl01tl/helm/bazarr/values.yaml | 57 ++ clusters/cl01tl/helm/booklore/Chart.yaml | 24 + .../booklore/templates/external-secret.yaml | 332 ++++++++ .../helm/booklore/templates/http-route.yaml | 28 + .../helm/booklore/templates/namespace.yaml | 10 + .../templates/persistent-volume-claim.yaml | 36 + .../booklore/templates/persistent-volume.yaml | 48 ++ .../templates/replication-destination.yaml | 15 + .../templates/replication-source.yaml | 129 +++ .../helm/booklore/templates/service.yaml | 14 + clusters/cl01tl/helm/booklore/values.yaml | 155 ++++ clusters/cl01tl/helm/code-server/Chart.yaml | 28 + .../templates/external-secret.yaml | 51 ++ .../code-server/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + clusters/cl01tl/helm/code-server/values.yaml | 47 ++ clusters/cl01tl/helm/directus/Chart.yaml | 33 + .../directus/templates/external-secret.yaml | 245 ++++++ .../templates/object-bucket-claim.yaml | 11 + .../directus/templates/redis-replication.yaml | 35 + .../directus/templates/redis-sentinel.yaml | 30 + .../directus/templates/service-monitor.yaml | 43 + clusters/cl01tl/helm/directus/values.yaml | 214 +++++ clusters/cl01tl/helm/element-web/Chart.yaml | 27 + .../templates/external-secret.yaml | 21 + clusters/cl01tl/helm/element-web/values.yaml | 28 + clusters/cl01tl/helm/ephemera/Chart.yaml | 23 + .../ephemera/templates/external-secret.yaml | 101 +++ .../helm/ephemera/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../ephemera/templates/persistent-volume.yaml | 23 + .../templates/replication-source.yaml | 26 + clusters/cl01tl/helm/ephemera/values.yaml | 107 +++ clusters/cl01tl/helm/freshrss/Chart.yaml | 33 + .../freshrss/templates/external-secret.yaml | 219 +++++ .../templates/replication-source.yaml | 35 + clusters/cl01tl/helm/freshrss/values.yaml | 251 ++++++ .../cl01tl/helm/home-assistant/Chart.yaml | 23 + .../templates/external-secret.yaml | 51 ++ .../home-assistant/templates/http-route.yaml | 58 ++ .../templates/service-monitor.yaml | 23 + .../cl01tl/helm/home-assistant/values.yaml | 70 ++ clusters/cl01tl/helm/homepage-dev/Chart.yaml | 27 + .../templates/external-secret.yaml | 21 + clusters/cl01tl/helm/homepage-dev/values.yaml | 167 ++++ clusters/cl01tl/helm/homepage/Chart.yaml | 21 + .../templates/cluster-role-binding.yaml | 17 + .../helm/homepage/templates/cluster-role.yaml | 50 ++ .../homepage/templates/external-secret.yaml | 105 +++ .../helm/homepage/templates/http-route.yaml | 28 + .../helm/homepage/templates/service.yaml | 46 + clusters/cl01tl/helm/homepage/values.yaml | 795 ++++++++++++++++++ clusters/cl01tl/helm/huntarr/Chart.yaml | 21 + .../helm/huntarr/templates/http-route.yaml | 28 + clusters/cl01tl/helm/huntarr/values.yaml | 39 + clusters/cl01tl/helm/immich/Chart.yaml | 26 + .../immich/templates/external-secrets.yaml | 88 ++ .../helm/immich/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../immich/templates/persistent-volume.yaml | 23 + .../immich/templates/redis-replication.yaml | 32 + .../immich/templates/service-monitor.yaml | 44 + clusters/cl01tl/helm/immich/values.yaml | 260 ++++++ clusters/cl01tl/helm/jellyfin/Chart.yaml | 25 + .../jellyfin/templates/external-secret.yaml | 55 ++ .../helm/jellyfin/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 36 + .../jellyfin/templates/persistent-volume.yaml | 48 ++ .../templates/replication-source.yaml | 26 + clusters/cl01tl/helm/jellyfin/values.yaml | 68 ++ clusters/cl01tl/helm/jellystat/Chart.yaml | 27 + .../jellystat/templates/external-secret.yaml | 159 ++++ .../helm/jellystat/templates/http-route.yaml | 28 + .../templates/replication-source.yaml | 25 + clusters/cl01tl/helm/jellystat/values.yaml | 136 +++ clusters/cl01tl/helm/karakeep/Chart.yaml | 32 + .../karakeep/templates/external-secret.yaml | 161 ++++ .../templates/object-bucket-claim.yaml | 11 + .../templates/replication-source.yaml | 25 + .../karakeep/templates/service-monitor.yaml | 23 + clusters/cl01tl/helm/karakeep/values.yaml | 155 ++++ clusters/cl01tl/helm/kiwix/Chart.yaml | 21 + .../helm/kiwix/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../kiwix/templates/persistent-volume.yaml | 23 + clusters/cl01tl/helm/kiwix/values.yaml | 38 + clusters/cl01tl/helm/libation/Chart.yaml | 22 + .../templates/persistent-volume-claim.yaml | 36 + .../libation/templates/persistent-volume.yaml | 23 + clusters/cl01tl/helm/libation/values.yaml | 44 + clusters/cl01tl/helm/lidarr/Chart.yaml | 30 + .../lidarr/templates/external-secret.yaml | 122 +++ .../helm/lidarr/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../lidarr/templates/persistent-volume.yaml | 23 + .../lidarr/templates/prometheus-rule.yaml | 32 + .../lidarr/templates/replication-source.yaml | 28 + .../lidarr/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/lidarr/values.yaml | 151 ++++ clusters/cl01tl/helm/lidatube/Chart.yaml | 22 + .../lidatube/templates/external-secret.yaml | 21 + .../helm/lidatube/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../lidatube/templates/persistent-volume.yaml | 23 + clusters/cl01tl/helm/lidatube/values.yaml | 66 ++ clusters/cl01tl/helm/listenarr/Chart.yaml | 20 + .../helm/listenarr/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../templates/persistent-volume.yaml | 23 + clusters/cl01tl/helm/listenarr/values.yaml | 46 + clusters/cl01tl/helm/omni-tools/Chart.yaml | 20 + .../helm/omni-tools/templates/http-route.yaml | 28 + clusters/cl01tl/helm/omni-tools/values.yaml | 25 + clusters/cl01tl/helm/outline/Chart.yaml | 34 + .../outline/templates/external-secret.yaml | 148 ++++ .../templates/object-bucket-claim.yaml | 30 + .../outline/templates/redis-replication.yaml | 32 + .../outline/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/outline/values.yaml | 203 +++++ clusters/cl01tl/helm/overseerr/Chart.yaml | 21 + .../overseerr/templates/external-secret.yaml | 55 ++ .../helm/overseerr/templates/http-route.yaml | 28 + .../templates/replication-source.yaml | 25 + clusters/cl01tl/helm/overseerr/values.yaml | 40 + clusters/cl01tl/helm/photoview/Chart.yaml | 26 + .../photoview/templates/external-secrets.yaml | 65 ++ .../helm/photoview/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../templates/persistent-volume.yaml | 23 + clusters/cl01tl/helm/photoview/values.yaml | 130 +++ clusters/cl01tl/helm/plex/Chart.yaml | 26 + .../helm/plex/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../plex/templates/persistent-volume.yaml | 23 + clusters/cl01tl/helm/plex/values.yaml | 61 ++ clusters/cl01tl/helm/postiz/Chart.yaml | 32 + .../postiz/templates/external-secret.yaml | 292 +++++++ .../helm/postiz/templates/http-route.yaml | 28 + .../postiz/templates/redis-replication.yaml | 35 + .../postiz/templates/replication-source.yaml | 52 ++ .../postiz/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/postiz/values.yaml | 163 ++++ clusters/cl01tl/helm/prowlarr/Chart.yaml | 23 + .../prowlarr/templates/external-secret.yaml | 55 ++ .../helm/prowlarr/templates/http-route.yaml | 28 + .../templates/replication-source.yaml | 35 + clusters/cl01tl/helm/prowlarr/values.yaml | 51 ++ clusters/cl01tl/helm/radarr-4k/Chart.yaml | 33 + .../radarr-4k/templates/external-secret.yaml | 122 +++ .../helm/radarr-4k/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../templates/persistent-volume.yaml | 23 + .../radarr-4k/templates/prometheus-rule.yaml | 32 + .../templates/replication-source.yaml | 30 + .../radarr-4k/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/radarr-4k/values.yaml | 151 ++++ clusters/cl01tl/helm/radarr-anime/Chart.yaml | 33 + .../templates/external-secret.yaml | 122 +++ .../radarr-anime/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../templates/persistent-volume.yaml | 23 + .../templates/prometheus-rule.yaml | 32 + .../templates/replication-source.yaml | 30 + .../templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/radarr-anime/values.yaml | 145 ++++ .../cl01tl/helm/radarr-standup/Chart.yaml | 32 + .../templates/external-secret.yaml | 122 +++ .../radarr-standup/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../templates/persistent-volume.yaml | 23 + .../templates/prometheus-rule.yaml | 32 + .../templates/replication-source.yaml | 30 + .../templates/service-monitor.yaml | 19 + .../cl01tl/helm/radarr-standup/values.yaml | 145 ++++ clusters/cl01tl/helm/radarr/Chart.yaml | 32 + .../radarr/templates/external-secret.yaml | 122 +++ .../helm/radarr/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../radarr/templates/persistent-volume.yaml | 23 + .../radarr/templates/prometheus-rule.yaml | 32 + .../radarr/templates/replication-source.yaml | 30 + .../radarr/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/radarr/values.yaml | 151 ++++ clusters/cl01tl/helm/roundcube/Chart.yaml | 27 + .../roundcube/templates/external-secret.yaml | 145 ++++ .../helm/roundcube/templates/http-route.yaml | 28 + .../templates/replication-source.yaml | 25 + clusters/cl01tl/helm/roundcube/values.yaml | 263 ++++++ clusters/cl01tl/helm/searxng/Chart.yaml | 20 + .../searxng/templates/external-secret.yaml | 85 ++ .../helm/searxng/templates/http-route.yaml | 28 + .../searxng/templates/redis-replication.yaml | 32 + .../searxng/templates/replication-source.yaml | 25 + .../searxng/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/searxng/values.yaml | 113 +++ .../cl01tl/helm/site-documentation/Chart.yaml | 28 + .../templates/external-secret.yaml | 21 + .../helm/site-documentation/values.yaml | 30 + clusters/cl01tl/helm/site-profile/Chart.yaml | 28 + .../templates/external-secret.yaml | 21 + clusters/cl01tl/helm/site-profile/values.yaml | 30 + clusters/cl01tl/helm/slskd/Chart.yaml | 25 + .../helm/slskd/templates/external-secret.yaml | 67 ++ .../helm/slskd/templates/http-route.yaml | 28 + .../helm/slskd/templates/namespace.yaml | 11 + .../templates/persistent-volume-claim.yaml | 17 + .../slskd/templates/persistent-volume.yaml | 23 + .../helm/slskd/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/slskd/values.yaml | 153 ++++ clusters/cl01tl/helm/sonarr-4k/Chart.yaml | 33 + .../sonarr-4k/templates/external-secret.yaml | 122 +++ .../helm/sonarr-4k/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../templates/persistent-volume.yaml | 23 + .../sonarr-4k/templates/prometheus-rule.yaml | 32 + .../templates/replication-source.yaml | 30 + .../sonarr-4k/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/sonarr-4k/values.yaml | 148 ++++ clusters/cl01tl/helm/sonarr-anime/Chart.yaml | 32 + .../templates/external-secret.yaml | 122 +++ .../sonarr-anime/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../templates/persistent-volume.yaml | 23 + .../templates/prometheus-rule.yaml | 32 + .../templates/replication-source.yaml | 30 + .../templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/sonarr-anime/values.yaml | 148 ++++ clusters/cl01tl/helm/sonarr/Chart.yaml | 32 + .../sonarr/templates/external-secret.yaml | 122 +++ .../helm/sonarr/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../sonarr/templates/persistent-volume.yaml | 23 + .../sonarr/templates/prometheus-rule.yaml | 32 + .../sonarr/templates/replication-source.yaml | 30 + .../sonarr/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/sonarr/values.yaml | 149 ++++ clusters/cl01tl/helm/tautulli/Chart.yaml | 21 + .../tautulli/templates/external-secret.yaml | 55 ++ .../helm/tautulli/templates/http-route.yaml | 28 + .../templates/replication-source.yaml | 25 + clusters/cl01tl/helm/tautulli/values.yaml | 148 ++++ clusters/cl01tl/helm/tdarr/Chart.yaml | 29 + .../helm/tdarr/templates/external-secret.yaml | 112 +++ .../helm/tdarr/templates/http-route.yaml | 28 + .../templates/persistent-volume-claim.yaml | 17 + .../tdarr/templates/persistent-volume.yaml | 23 + .../tdarr/templates/replication-source.yaml | 52 ++ clusters/cl01tl/helm/tdarr/values.yaml | 156 ++++ clusters/cl01tl/helm/tubearchivist/Chart.yaml | 24 + .../templates/elasticsearch.yaml | 42 + .../templates/external-secret.yaml | 88 ++ .../tubearchivist/templates/http-route.yaml | 28 + .../tubearchivist/templates/namespace.yaml | 11 + .../templates/persistent-volume-claim.yaml | 17 + .../templates/persistent-volume.yaml | 23 + .../templates/redis-replication.yaml | 32 + .../templates/service-monitor.yaml | 19 + .../cl01tl/helm/tubearchivist/values.yaml | 107 +++ clusters/cl01tl/helm/vaultwarden/Chart.yaml | 34 + .../templates/external-secret.yaml | 145 ++++ .../templates/replication-source.yaml | 25 + clusters/cl01tl/helm/vaultwarden/values.yaml | 107 +++ clusters/cl01tl/helm/yamtrack/Chart.yaml | 28 + .../yamtrack/templates/external-secret.yaml | 111 +++ .../helm/yamtrack/templates/http-route.yaml | 28 + .../yamtrack/templates/redis-replication.yaml | 32 + .../yamtrack/templates/service-monitor.yaml | 19 + clusters/cl01tl/helm/yamtrack/values.yaml | 127 +++ 288 files changed, 15801 insertions(+) create mode 100644 .gitea/workflows/render-manifests.yaml create mode 100644 clusters/cl01tl/helm/actual/Chart.yaml create mode 100644 clusters/cl01tl/helm/actual/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/actual/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/actual/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/actual/values.yaml create mode 100644 clusters/cl01tl/helm/audiobookshelf/Chart.yaml create mode 100644 clusters/cl01tl/helm/audiobookshelf/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/audiobookshelf/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/audiobookshelf/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/audiobookshelf/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/audiobookshelf/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/audiobookshelf/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/audiobookshelf/values.yaml create mode 100644 clusters/cl01tl/helm/bazarr/Chart.yaml create mode 100644 clusters/cl01tl/helm/bazarr/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/bazarr/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/bazarr/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/bazarr/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/bazarr/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/bazarr/values.yaml create mode 100644 clusters/cl01tl/helm/booklore/Chart.yaml create mode 100644 clusters/cl01tl/helm/booklore/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/booklore/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/booklore/templates/namespace.yaml create mode 100644 clusters/cl01tl/helm/booklore/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/booklore/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/booklore/templates/replication-destination.yaml create mode 100644 clusters/cl01tl/helm/booklore/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/booklore/templates/service.yaml create mode 100644 clusters/cl01tl/helm/booklore/values.yaml create mode 100644 clusters/cl01tl/helm/code-server/Chart.yaml create mode 100644 clusters/cl01tl/helm/code-server/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/code-server/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/code-server/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/code-server/values.yaml create mode 100644 clusters/cl01tl/helm/directus/Chart.yaml create mode 100644 clusters/cl01tl/helm/directus/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/directus/templates/object-bucket-claim.yaml create mode 100644 clusters/cl01tl/helm/directus/templates/redis-replication.yaml create mode 100644 clusters/cl01tl/helm/directus/templates/redis-sentinel.yaml create mode 100644 clusters/cl01tl/helm/directus/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/directus/values.yaml create mode 100644 clusters/cl01tl/helm/element-web/Chart.yaml create mode 100644 clusters/cl01tl/helm/element-web/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/element-web/values.yaml create mode 100644 clusters/cl01tl/helm/ephemera/Chart.yaml create mode 100644 clusters/cl01tl/helm/ephemera/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/ephemera/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/ephemera/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/ephemera/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/ephemera/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/ephemera/values.yaml create mode 100644 clusters/cl01tl/helm/freshrss/Chart.yaml create mode 100644 clusters/cl01tl/helm/freshrss/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/freshrss/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/freshrss/values.yaml create mode 100644 clusters/cl01tl/helm/home-assistant/Chart.yaml create mode 100644 clusters/cl01tl/helm/home-assistant/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/home-assistant/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/home-assistant/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/home-assistant/values.yaml create mode 100644 clusters/cl01tl/helm/homepage-dev/Chart.yaml create mode 100644 clusters/cl01tl/helm/homepage-dev/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/homepage-dev/values.yaml create mode 100644 clusters/cl01tl/helm/homepage/Chart.yaml create mode 100644 clusters/cl01tl/helm/homepage/templates/cluster-role-binding.yaml create mode 100644 clusters/cl01tl/helm/homepage/templates/cluster-role.yaml create mode 100644 clusters/cl01tl/helm/homepage/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/homepage/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/homepage/templates/service.yaml create mode 100644 clusters/cl01tl/helm/homepage/values.yaml create mode 100644 clusters/cl01tl/helm/huntarr/Chart.yaml create mode 100644 clusters/cl01tl/helm/huntarr/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/huntarr/values.yaml create mode 100644 clusters/cl01tl/helm/immich/Chart.yaml create mode 100644 clusters/cl01tl/helm/immich/templates/external-secrets.yaml create mode 100644 clusters/cl01tl/helm/immich/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/immich/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/immich/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/immich/templates/redis-replication.yaml create mode 100644 clusters/cl01tl/helm/immich/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/immich/values.yaml create mode 100644 clusters/cl01tl/helm/jellyfin/Chart.yaml create mode 100644 clusters/cl01tl/helm/jellyfin/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/jellyfin/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/jellyfin/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/jellyfin/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/jellyfin/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/jellyfin/values.yaml create mode 100644 clusters/cl01tl/helm/jellystat/Chart.yaml create mode 100644 clusters/cl01tl/helm/jellystat/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/jellystat/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/jellystat/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/jellystat/values.yaml create mode 100644 clusters/cl01tl/helm/karakeep/Chart.yaml create mode 100644 clusters/cl01tl/helm/karakeep/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/karakeep/templates/object-bucket-claim.yaml create mode 100644 clusters/cl01tl/helm/karakeep/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/karakeep/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/karakeep/values.yaml create mode 100644 clusters/cl01tl/helm/kiwix/Chart.yaml create mode 100644 clusters/cl01tl/helm/kiwix/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/kiwix/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/kiwix/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/kiwix/values.yaml create mode 100644 clusters/cl01tl/helm/libation/Chart.yaml create mode 100644 clusters/cl01tl/helm/libation/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/libation/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/libation/values.yaml create mode 100644 clusters/cl01tl/helm/lidarr/Chart.yaml create mode 100644 clusters/cl01tl/helm/lidarr/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/lidarr/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/lidarr/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/lidarr/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/lidarr/templates/prometheus-rule.yaml create mode 100644 clusters/cl01tl/helm/lidarr/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/lidarr/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/lidarr/values.yaml create mode 100644 clusters/cl01tl/helm/lidatube/Chart.yaml create mode 100644 clusters/cl01tl/helm/lidatube/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/lidatube/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/lidatube/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/lidatube/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/lidatube/values.yaml create mode 100644 clusters/cl01tl/helm/listenarr/Chart.yaml create mode 100644 clusters/cl01tl/helm/listenarr/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/listenarr/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/listenarr/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/listenarr/values.yaml create mode 100644 clusters/cl01tl/helm/omni-tools/Chart.yaml create mode 100644 clusters/cl01tl/helm/omni-tools/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/omni-tools/values.yaml create mode 100644 clusters/cl01tl/helm/outline/Chart.yaml create mode 100644 clusters/cl01tl/helm/outline/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/outline/templates/object-bucket-claim.yaml create mode 100644 clusters/cl01tl/helm/outline/templates/redis-replication.yaml create mode 100644 clusters/cl01tl/helm/outline/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/outline/values.yaml create mode 100644 clusters/cl01tl/helm/overseerr/Chart.yaml create mode 100644 clusters/cl01tl/helm/overseerr/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/overseerr/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/overseerr/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/overseerr/values.yaml create mode 100644 clusters/cl01tl/helm/photoview/Chart.yaml create mode 100644 clusters/cl01tl/helm/photoview/templates/external-secrets.yaml create mode 100644 clusters/cl01tl/helm/photoview/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/photoview/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/photoview/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/photoview/values.yaml create mode 100644 clusters/cl01tl/helm/plex/Chart.yaml create mode 100644 clusters/cl01tl/helm/plex/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/plex/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/plex/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/plex/values.yaml create mode 100644 clusters/cl01tl/helm/postiz/Chart.yaml create mode 100644 clusters/cl01tl/helm/postiz/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/postiz/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/postiz/templates/redis-replication.yaml create mode 100644 clusters/cl01tl/helm/postiz/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/postiz/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/postiz/values.yaml create mode 100644 clusters/cl01tl/helm/prowlarr/Chart.yaml create mode 100644 clusters/cl01tl/helm/prowlarr/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/prowlarr/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/prowlarr/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/prowlarr/values.yaml create mode 100644 clusters/cl01tl/helm/radarr-4k/Chart.yaml create mode 100644 clusters/cl01tl/helm/radarr-4k/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/radarr-4k/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/radarr-4k/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/radarr-4k/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/radarr-4k/templates/prometheus-rule.yaml create mode 100644 clusters/cl01tl/helm/radarr-4k/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/radarr-4k/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/radarr-4k/values.yaml create mode 100644 clusters/cl01tl/helm/radarr-anime/Chart.yaml create mode 100644 clusters/cl01tl/helm/radarr-anime/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/radarr-anime/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/radarr-anime/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/radarr-anime/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/radarr-anime/templates/prometheus-rule.yaml create mode 100644 clusters/cl01tl/helm/radarr-anime/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/radarr-anime/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/radarr-anime/values.yaml create mode 100644 clusters/cl01tl/helm/radarr-standup/Chart.yaml create mode 100644 clusters/cl01tl/helm/radarr-standup/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/radarr-standup/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/radarr-standup/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/radarr-standup/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/radarr-standup/templates/prometheus-rule.yaml create mode 100644 clusters/cl01tl/helm/radarr-standup/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/radarr-standup/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/radarr-standup/values.yaml create mode 100644 clusters/cl01tl/helm/radarr/Chart.yaml create mode 100644 clusters/cl01tl/helm/radarr/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/radarr/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/radarr/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/radarr/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/radarr/templates/prometheus-rule.yaml create mode 100644 clusters/cl01tl/helm/radarr/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/radarr/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/radarr/values.yaml create mode 100644 clusters/cl01tl/helm/roundcube/Chart.yaml create mode 100644 clusters/cl01tl/helm/roundcube/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/roundcube/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/roundcube/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/roundcube/values.yaml create mode 100644 clusters/cl01tl/helm/searxng/Chart.yaml create mode 100644 clusters/cl01tl/helm/searxng/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/searxng/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/searxng/templates/redis-replication.yaml create mode 100644 clusters/cl01tl/helm/searxng/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/searxng/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/searxng/values.yaml create mode 100644 clusters/cl01tl/helm/site-documentation/Chart.yaml create mode 100644 clusters/cl01tl/helm/site-documentation/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/site-documentation/values.yaml create mode 100644 clusters/cl01tl/helm/site-profile/Chart.yaml create mode 100644 clusters/cl01tl/helm/site-profile/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/site-profile/values.yaml create mode 100644 clusters/cl01tl/helm/slskd/Chart.yaml create mode 100644 clusters/cl01tl/helm/slskd/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/slskd/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/slskd/templates/namespace.yaml create mode 100644 clusters/cl01tl/helm/slskd/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/slskd/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/slskd/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/slskd/values.yaml create mode 100644 clusters/cl01tl/helm/sonarr-4k/Chart.yaml create mode 100644 clusters/cl01tl/helm/sonarr-4k/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/sonarr-4k/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/sonarr-4k/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/sonarr-4k/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/sonarr-4k/templates/prometheus-rule.yaml create mode 100644 clusters/cl01tl/helm/sonarr-4k/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/sonarr-4k/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/sonarr-4k/values.yaml create mode 100644 clusters/cl01tl/helm/sonarr-anime/Chart.yaml create mode 100644 clusters/cl01tl/helm/sonarr-anime/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/sonarr-anime/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/sonarr-anime/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/sonarr-anime/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/sonarr-anime/templates/prometheus-rule.yaml create mode 100644 clusters/cl01tl/helm/sonarr-anime/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/sonarr-anime/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/sonarr-anime/values.yaml create mode 100644 clusters/cl01tl/helm/sonarr/Chart.yaml create mode 100644 clusters/cl01tl/helm/sonarr/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/sonarr/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/sonarr/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/sonarr/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/sonarr/templates/prometheus-rule.yaml create mode 100644 clusters/cl01tl/helm/sonarr/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/sonarr/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/sonarr/values.yaml create mode 100644 clusters/cl01tl/helm/tautulli/Chart.yaml create mode 100644 clusters/cl01tl/helm/tautulli/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/tautulli/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/tautulli/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/tautulli/values.yaml create mode 100644 clusters/cl01tl/helm/tdarr/Chart.yaml create mode 100644 clusters/cl01tl/helm/tdarr/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/tdarr/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/tdarr/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/tdarr/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/tdarr/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/tdarr/values.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/Chart.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/templates/elasticsearch.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/templates/namespace.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/templates/persistent-volume-claim.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/templates/persistent-volume.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/templates/redis-replication.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/tubearchivist/values.yaml create mode 100644 clusters/cl01tl/helm/vaultwarden/Chart.yaml create mode 100644 clusters/cl01tl/helm/vaultwarden/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/vaultwarden/templates/replication-source.yaml create mode 100644 clusters/cl01tl/helm/vaultwarden/values.yaml create mode 100644 clusters/cl01tl/helm/yamtrack/Chart.yaml create mode 100644 clusters/cl01tl/helm/yamtrack/templates/external-secret.yaml create mode 100644 clusters/cl01tl/helm/yamtrack/templates/http-route.yaml create mode 100644 clusters/cl01tl/helm/yamtrack/templates/redis-replication.yaml create mode 100644 clusters/cl01tl/helm/yamtrack/templates/service-monitor.yaml create mode 100644 clusters/cl01tl/helm/yamtrack/values.yaml diff --git a/.gitea/workflows/render-manifests.yaml b/.gitea/workflows/render-manifests.yaml new file mode 100644 index 000000000..bfd059890 --- /dev/null +++ b/.gitea/workflows/render-manifests.yaml @@ -0,0 +1,94 @@ +name: render-manifests + +on: + push: + branches: + - main + paths: + - "clusters/**" + - ! "clusters/*/archive" + +jobs: + render-manifests-helm: + runs-on: ubuntu-js + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Set up Helm + uses: azure/setup-helm@v4 + with: + token: ${{ secrets.GITEA_TOKEN }} + version: latest + + - name: Render Helm Manifests + env: + CLUSTERS: cl01tl + run: | + for cluster in $CLUSTERS; do + mkdir clusters/$CLUSTER/manifests + + for chart_path in clusters/$CLUSTER/helm/; do + chart_name=$(basename "$chart") + + echo "--- Rendering chart: $chart_name ---" + + if [ -f "$chart_path/Chart.yaml" ]; then + OUTPUT_FILE="clusters/$CLUSTER/manifests/$chart_name.yaml" + + helm template "$chart_name" "$chart" --namespace "$chart_name" > "$OUTPUT_FILE" + + echo "Manifests for $chart_name rendered to $OUTPUT_FILE" + else + echo "Directory $chart_path does not contain a Chart.yaml. Skipping ..." + fi + done + done + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITEA_TOKEN }} + commit-message: "chore: Update manifests after chart change" + branch: auto/update-manifests + base: manifests + title: "Manifest Update: App Changes" + body: | + This PR contains the newly rendered Kubernetes manifests. + + * Triggered by workflow run ${{ github.run_id }} + * Review the `files changed` tab for the full YAML diff. + add-paths: "clusters/*/rendered-manifests/" + + - name: ntfy Success + uses: niniyas/ntfy-action@master + if: success() + with: + url: "${{ secrets.NTFY_URL }}" + topic: "${{ secrets.NTFY_TOPIC }}" + title: "Manifest Render Success - Infrastructure" + priority: 3 + headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}' + tags: action,successfully,completed + details: "Manifest rendering for Infrastructure has succeeded" + icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png" + + - name: ntfy Failed + uses: niniyas/ntfy-action@master + if: failure() + with: + url: "${{ secrets.NTFY_URL }}" + topic: "${{ secrets.NTFY_TOPIC }}" + title: "Manifest Render Failure - Infrastructure" + priority: 4 + headers: '{"Authorization": "Bearer ${{ secrets.NTFY_CRED }}"}' + tags: action,failed + details: "Manifest rendering for Infrastructure has failed!" + icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/gitea.png" + actions: '[{"action": "view", "label": "Open Gitea", "url": "https://gitea.alexlebens.dev/alexlebens/infrastructure/actions?workflow=render-manifests.yaml", "clear": true}]' + image: true diff --git a/clusters/cl01tl/helm/actual/Chart.yaml b/clusters/cl01tl/helm/actual/Chart.yaml new file mode 100644 index 000000000..6b8121ad6 --- /dev/null +++ b/clusters/cl01tl/helm/actual/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: actual +version: 1.0.0 +description: Actual +keywords: + - actual + - budget +home: https://wiki.alexlebens.dev/s/86192f45-94b7-45de-872c-6ef3fec7df5e +sources: + - https://github.com/actualbudget/actual + - https://github.com/actualbudget/actual/pkgs/container/actual + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: actual + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/actual-budget.png +appVersion: 25.11.0 diff --git a/clusters/cl01tl/helm/actual/templates/external-secret.yaml b/clusters/cl01tl/helm/actual/templates/external-secret.yaml new file mode 100644 index 000000000..f22be7ac2 --- /dev/null +++ b/clusters/cl01tl/helm/actual/templates/external-secret.yaml @@ -0,0 +1,55 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: actual-data-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: actual-data-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/actual/actual-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/actual/templates/http-route.yaml b/clusters/cl01tl/helm/actual/templates/http-route.yaml new file mode 100644 index 000000000..4b308cee3 --- /dev/null +++ b/clusters/cl01tl/helm/actual/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-actual + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-actual + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - actual.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: actual + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/actual/templates/replication-source.yaml b/clusters/cl01tl/helm/actual/templates/replication-source.yaml new file mode 100644 index 000000000..ba1340760 --- /dev/null +++ b/clusters/cl01tl/helm/actual/templates/replication-source.yaml @@ -0,0 +1,25 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: actual-data-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: actual-data-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: actual-data + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: actual-data-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/actual/values.yaml b/clusters/cl01tl/helm/actual/values.yaml new file mode 100644 index 000000000..4bec1142c --- /dev/null +++ b/clusters/cl01tl/helm/actual/values.yaml @@ -0,0 +1,56 @@ +actual: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/actualbudget/actual + tag: 25.11.0 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + resources: + requests: + cpu: 10m + memory: 128Mi + probes: + liveness: + enabled: true + custom: true + spec: + exec: + command: + - /usr/bin/env + - bash + - -c + - node src/scripts/health-check.js + failureThreshold: 5 + initialDelaySeconds: 60 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 10 + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 5006 + protocol: HTTP + persistence: + data: + forceRename: actual-data + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 2Gi + retain: true + advancedMounts: + main: + main: + - path: /data + readOnly: false diff --git a/clusters/cl01tl/helm/audiobookshelf/Chart.yaml b/clusters/cl01tl/helm/audiobookshelf/Chart.yaml new file mode 100644 index 000000000..34b451361 --- /dev/null +++ b/clusters/cl01tl/helm/audiobookshelf/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: audiobookshelf +version: 1.0.0 +description: Audiobookshelf +keywords: + - audiobookshelf + - books + - podcasts + - audiobooks +home: https://wiki.alexlebens.dev/s/d4d6719f-cd1c-4b6e-b78e-2d2d7a5097d7 +sources: + - https://github.com/advplyr/audiobookshelf + - https://github.com/advplyr/audiobookshelf/pkgs/container/audiobookshelf + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: audiobookshelf + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/audiobookshelf.png +appVersion: 2.21.0 diff --git a/clusters/cl01tl/helm/audiobookshelf/templates/external-secret.yaml b/clusters/cl01tl/helm/audiobookshelf/templates/external-secret.yaml new file mode 100644 index 000000000..d1da422a3 --- /dev/null +++ b/clusters/cl01tl/helm/audiobookshelf/templates/external-secret.yaml @@ -0,0 +1,135 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: audiobookshelf-apprise-config + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: audiobookshelf-apprise-config + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ntfy-url + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/audiobookshelf/apprise + metadataPolicy: None + property: ntfy-url + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: audiobookshelf-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: audiobookshelf-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/audiobookshelf/audiobookshelf-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: audiobookshelf-metadata-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: audiobookshelf-metadata-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/audiobookshelf/audiobookshelf-metadata" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/audiobookshelf/templates/http-route.yaml b/clusters/cl01tl/helm/audiobookshelf/templates/http-route.yaml new file mode 100644 index 000000000..1d9329717 --- /dev/null +++ b/clusters/cl01tl/helm/audiobookshelf/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-audiobookshelf + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-audiobookshelf + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - audiobookshelf.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: audiobookshelf + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/audiobookshelf/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/audiobookshelf/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..d31621e69 --- /dev/null +++ b/clusters/cl01tl/helm/audiobookshelf/templates/persistent-volume-claim.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: audiobookshelf-nfs-storage-backup + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: audiobookshelf-nfs-storage-backup + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeMode: Filesystem + storageClassName: nfs-client + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: audiobookshelf-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: audiobookshelf-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: audiobookshelf-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/audiobookshelf/templates/persistent-volume.yaml b/clusters/cl01tl/helm/audiobookshelf/templates/persistent-volume.yaml new file mode 100644 index 000000000..793addc71 --- /dev/null +++ b/clusters/cl01tl/helm/audiobookshelf/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: audiobookshelf-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: audiobookshelf-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/audiobookshelf/templates/replication-source.yaml b/clusters/cl01tl/helm/audiobookshelf/templates/replication-source.yaml new file mode 100644 index 000000000..844a9a5ab --- /dev/null +++ b/clusters/cl01tl/helm/audiobookshelf/templates/replication-source.yaml @@ -0,0 +1,52 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: audiobookshelf-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: audiobookshelf-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: audiobookshelf-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: audiobookshelf-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot + +--- +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: audiobookshelf-metadata-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: audiobookshelf-metadata-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: audiobookshelf-metadata + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: audiobookshelf-metadata-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/audiobookshelf/templates/service-monitor.yaml b/clusters/cl01tl/helm/audiobookshelf/templates/service-monitor.yaml new file mode 100644 index 000000000..5e6974279 --- /dev/null +++ b/clusters/cl01tl/helm/audiobookshelf/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: audiobookshelf-apprise + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: audiobookshelf-apprise + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + endpoints: + - port: apprise + interval: 30s + scrapeTimeout: 15s + path: /metrics + selector: + matchLabels: + app.kubernetes.io/name: audiobookshelf + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/clusters/cl01tl/helm/audiobookshelf/values.yaml b/clusters/cl01tl/helm/audiobookshelf/values.yaml new file mode 100644 index 000000000..91d1126da --- /dev/null +++ b/clusters/cl01tl/helm/audiobookshelf/values.yaml @@ -0,0 +1,94 @@ +audiobookshelf: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/advplyr/audiobookshelf + tag: 2.30.0 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + resources: + requests: + cpu: 10m + memory: 128Mi + apprise-api: + image: + repository: caronc/apprise + tag: 1.2.6 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PGID + value: "1000" + - name: PUID + value: "1000" + - name: APPRISE_STORAGE_MODE + value: memory + - name: APPRISE_STATEFUL_MODE + value: disabled + - name: APPRISE_WORKER_COUNT + value: 1 + - name: APPRISE_STATELESS_URLS + valueFrom: + secretKeyRef: + name: audiobookshelf-apprise-config + key: ntfy-url + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 80 + protocol: HTTP + apprise: + port: 8000 + targetPort: 8000 + protocol: HTTP + persistence: + config: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 2Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + metadata: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 10Gi + retain: true + advancedMounts: + main: + main: + - path: /metadata + readOnly: false + backup: + existingClaim: audiobookshelf-nfs-storage-backup + advancedMounts: + main: + main: + - path: /metadata/backups + readOnly: false + audiobooks: + existingClaim: audiobookshelf-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store/ + readOnly: false diff --git a/clusters/cl01tl/helm/bazarr/Chart.yaml b/clusters/cl01tl/helm/bazarr/Chart.yaml new file mode 100644 index 000000000..cc20db826 --- /dev/null +++ b/clusters/cl01tl/helm/bazarr/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: bazarr +version: 1.0.0 +description: Bazarr +keywords: + - bazarr + - servarr + - subtitles +home: https://wiki.alexlebens.dev/s/92784d53-1d43-42fd-b509-f42c73454226 +sources: + - https://github.com/morpheus65535/bazarr + - https://github.com/linuxserver/docker-bazarr + - https://github.com/linuxserver/docker-bazarr/pkgs/container/bazarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: bazarr + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/bazarr.png +appVersion: 1.5.2 diff --git a/clusters/cl01tl/helm/bazarr/templates/external-secret.yaml b/clusters/cl01tl/helm/bazarr/templates/external-secret.yaml new file mode 100644 index 000000000..40e7170bb --- /dev/null +++ b/clusters/cl01tl/helm/bazarr/templates/external-secret.yaml @@ -0,0 +1,55 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: bazarr-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: bazarr-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/bazarr/bazarr-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/bazarr/templates/http-route.yaml b/clusters/cl01tl/helm/bazarr/templates/http-route.yaml new file mode 100644 index 000000000..3e5439d60 --- /dev/null +++ b/clusters/cl01tl/helm/bazarr/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-bazarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-bazarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - bazarr.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: bazarr + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/bazarr/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/bazarr/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..6cf8cb968 --- /dev/null +++ b/clusters/cl01tl/helm/bazarr/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: bazarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: bazarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: bazarr-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/bazarr/templates/persistent-volume.yaml b/clusters/cl01tl/helm/bazarr/templates/persistent-volume.yaml new file mode 100644 index 000000000..c61824875 --- /dev/null +++ b/clusters/cl01tl/helm/bazarr/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: bazarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: bazarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/bazarr/templates/replication-source.yaml b/clusters/cl01tl/helm/bazarr/templates/replication-source.yaml new file mode 100644 index 000000000..fee25927c --- /dev/null +++ b/clusters/cl01tl/helm/bazarr/templates/replication-source.yaml @@ -0,0 +1,30 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: bazarr-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: bazarr-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: bazarr-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: bazarr-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/bazarr/values.yaml b/clusters/cl01tl/helm/bazarr/values.yaml new file mode 100644 index 000000000..0b824381d --- /dev/null +++ b/clusters/cl01tl/helm/bazarr/values.yaml @@ -0,0 +1,57 @@ +bazarr: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: ghcr.io/linuxserver/bazarr + tag: 1.5.3@sha256:2be164c02c0bb311b6c32e57d3d0ddc2813d524e89ab51a3408c1bf6fafecda5 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + resources: + requests: + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 6767 + protocol: HTTP + persistence: + config: + forceRename: bazarr-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + media: + existingClaim: bazarr-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false diff --git a/clusters/cl01tl/helm/booklore/Chart.yaml b/clusters/cl01tl/helm/booklore/Chart.yaml new file mode 100644 index 000000000..db03241d0 --- /dev/null +++ b/clusters/cl01tl/helm/booklore/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: booklore +version: 1.0.0 +description: booklore +keywords: + - booklore + - books +home: https://wiki.alexlebens.dev/ +sources: + - https://github.com/booklore-app/BookLore + - https://github.com/booklore-app/booklore/pkgs/container/booklore + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: booklore + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: mariadb-cluster + version: 25.10.2 + repository: https://helm.mariadb.com/mariadb-operator +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/booklore.png +appVersion: v.1.10.0 diff --git a/clusters/cl01tl/helm/booklore/templates/external-secret.yaml b/clusters/cl01tl/helm/booklore/templates/external-secret.yaml new file mode 100644 index 000000000..bae429731 --- /dev/null +++ b/clusters/cl01tl/helm/booklore/templates/external-secret.yaml @@ -0,0 +1,332 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: booklore-database-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-database-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: password + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/booklore/database + metadataPolicy: None + property: password + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: booklore-data-replication-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-data-replication-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: psk.txt + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/booklore/replication + metadataPolicy: None + property: psk.txt + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: booklore-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/booklore/booklore-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /volsync/restic/digital-ocean + metadataPolicy: None + property: BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /volsync/restic/digital-ocean + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: AWS_ACCESS_KEY_ID + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: AWS_SECRET_ACCESS_KEY + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: booklore-data-backup-secret-local + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-data-backup-secret-local + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/booklore/booklore-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /volsync/restic/garage-local + metadataPolicy: None + property: BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /volsync/restic/garage-local + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/volsync-backups + metadataPolicy: None + property: ACCESS_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/volsync-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/volsync-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: booklore-data-backup-secret-remote + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-data-backup-secret-remote + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/booklore/booklore-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /volsync/restic/garage-remote + metadataPolicy: None + property: BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /volsync/restic/garage-remote + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/volsync-backups + metadataPolicy: None + property: ACCESS_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/volsync-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/volsync-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: booklore-data-backup-secret-external + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-data-backup-secret-external + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/booklore/booklore-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /volsync/restic/digital-ocean + metadataPolicy: None + property: BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /volsync/restic/digital-ocean + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: AWS_ACCESS_KEY_ID + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: AWS_SECRET_ACCESS_KEY + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: booklore-mariadb-cluster-backup-secret-external + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-mariadb-cluster-backup-secret-external + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: access + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/mariadb-backups + metadataPolicy: None + property: access + - secretKey: secret + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/mariadb-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: booklore-mariadb-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-mariadb-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: access + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/mariadb-backups + metadataPolicy: None + property: access + - secretKey: secret + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/mariadb-backups + metadataPolicy: None + property: secret diff --git a/clusters/cl01tl/helm/booklore/templates/http-route.yaml b/clusters/cl01tl/helm/booklore/templates/http-route.yaml new file mode 100644 index 000000000..a6156305e --- /dev/null +++ b/clusters/cl01tl/helm/booklore/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-booklore + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-booklore + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - booklore.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: booklore + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/booklore/templates/namespace.yaml b/clusters/cl01tl/helm/booklore/templates/namespace.yaml new file mode 100644 index 000000000..11d8d8e2e --- /dev/null +++ b/clusters/cl01tl/helm/booklore/templates/namespace.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: booklore + annotations: + volsync.backube/privileged-movers: "true" + labels: + app.kubernetes.io/name: booklore + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} diff --git a/clusters/cl01tl/helm/booklore/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/booklore/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..f21d20472 --- /dev/null +++ b/clusters/cl01tl/helm/booklore/templates/persistent-volume-claim.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: booklore-books-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-books-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: booklore-books-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: booklore-books-import-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-books-import-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: booklore-books-import-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/booklore/templates/persistent-volume.yaml b/clusters/cl01tl/helm/booklore/templates/persistent-volume.yaml new file mode 100644 index 000000000..f50dc7e7a --- /dev/null +++ b/clusters/cl01tl/helm/booklore/templates/persistent-volume.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: booklore-books-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-books-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/Books + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac + +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: booklore-books-import-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-books-import-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/Books Import + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/booklore/templates/replication-destination.yaml b/clusters/cl01tl/helm/booklore/templates/replication-destination.yaml new file mode 100644 index 000000000..5b70c0281 --- /dev/null +++ b/clusters/cl01tl/helm/booklore/templates/replication-destination.yaml @@ -0,0 +1,15 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationDestination +metadata: + name: booklore-data-replication-destination + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-data-replication-destination + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + rsyncTLS: + copyMethod: Direct + accessModes: ["ReadWriteMany"] + destinationPVC: booklore-books-nfs-storage + keySecret: booklore-data-replication-secret diff --git a/clusters/cl01tl/helm/booklore/templates/replication-source.yaml b/clusters/cl01tl/helm/booklore/templates/replication-source.yaml new file mode 100644 index 000000000..e7d891619 --- /dev/null +++ b/clusters/cl01tl/helm/booklore/templates/replication-source.yaml @@ -0,0 +1,129 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: booklore-data-replication-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-data-replication-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: booklore-data + trigger: + schedule: "0 0 * * *" + rsyncTLS: + keySecret: booklore-data-replication-secret + address: volsync-rsync-tls-dst-booklore-data-replication-destination + copyMethod: Snapshot + +--- +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: booklore-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: booklore-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: booklore-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot + cacheCapacity: 10Gi + +--- +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: booklore-data-backup-source-local + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-data-backup-source-local + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: booklore-data + trigger: + schedule: 0 2 * * * + restic: + pruneIntervalDays: 7 + repository: booklore-data-backup-secret-local + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot + cacheCapacity: 10Gi + +--- +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: booklore-data-backup-source-remote + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-data-backup-source-remote + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: booklore-data + trigger: + schedule: 0 3 * * * + restic: + pruneIntervalDays: 7 + repository: booklore-data-backup-secret-remote + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot + cacheCapacity: 10Gi + +--- +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: booklore-data-backup-source-external + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: booklore-data-backup-source-external + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: booklore-data + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: booklore-data-backup-secret-external + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot + cacheCapacity: 10Gi diff --git a/clusters/cl01tl/helm/booklore/templates/service.yaml b/clusters/cl01tl/helm/booklore/templates/service.yaml new file mode 100644 index 000000000..4d10a9638 --- /dev/null +++ b/clusters/cl01tl/helm/booklore/templates/service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: garage-ps10rp + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: garage-ps10rp + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + annotations: + tailscale.com/tailnet-fqdn: garage-ps10rp.boreal-beaufort.ts.net +spec: + externalName: placeholder + type: ExternalName diff --git a/clusters/cl01tl/helm/booklore/values.yaml b/clusters/cl01tl/helm/booklore/values.yaml new file mode 100644 index 000000000..e8ca17ea5 --- /dev/null +++ b/clusters/cl01tl/helm/booklore/values.yaml @@ -0,0 +1,155 @@ +booklore: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/booklore-app/booklore + tag: v1.12.0 + pullPolicy: IfNotPresent + env: + - name: TZ + value: America/Chicago + - name: DATABASE_URL + value: jdbc:mariadb://booklore-mariadb-cluster-primary.booklore:3306/booklore + - name: DATABASE_USERNAME + value: booklore + - name: DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: booklore-database-secret + key: password + - name: BOOKLORE_PORT + value: 6060 + - name: SWAGGER_ENABLED + value: false + resources: + requests: + cpu: 50m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 6060 + protocol: HTTP + persistence: + config: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /app/data + readOnly: false + data: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 10Gi + retain: true + advancedMounts: + main: + main: + - path: /data + readOnly: false + books-import: + type: emptyDir + advancedMounts: + main: + main: + - path: /bookdrop + readOnly: false + ingest: + existingClaim: booklore-books-import-nfs-storage + advancedMounts: + main: + main: + - path: /bookdrop/ingest + readOnly: false +mariadb-cluster: + mariadb: + rootPasswordSecretKeyRef: + generate: false + name: booklore-database-secret + key: password + storage: + size: 5Gi + replicas: 3 + galera: + enabled: true + databases: + - name: booklore + characterSet: utf8 + collate: utf8_general_ci + cleanupPolicy: Delete + requeueInterval: 10h + users: + - name: booklore + passwordSecretKeyRef: + name: booklore-database-secret + key: password + host: '%' + cleanupPolicy: Delete + requeueInterval: 10h + retryInterval: 30s + grants: + - name: booklore + privileges: + - "ALL PRIVILEGES" + database: "booklore" + table: "*" + username: booklore + grantOption: true + host: '%' + cleanupPolicy: Delete + requeueInterval: 10h + retryInterval: 30s + physicalBackups: + - name: backup-external + schedule: + cron: "0 0 * * 0" + suspend: false + immediate: true + compression: gzip + maxRetention: 720h + storage: + s3: + bucket: mariadb-backups-b230a2f5aecf080a4b372c08 + prefix: cl01tl/booklore + endpoint: nyc3.digitaloceanspaces.com + region: us-east-1 + accessKeyIdSecretKeyRef: + name: booklore-mariadb-cluster-backup-secret-external + key: access + secretAccessKeySecretKeyRef: + name: booklore-mariadb-cluster-backup-secret-external + key: secret + tls: + enabled: true + - name: backup-garage + schedule: + cron: "0 0 * * *" + suspend: false + immediate: true + compression: gzip + maxRetention: 360h + storage: + s3: + bucket: mariadb-backups + prefix: cl01tl/booklore + endpoint: garage-main.garage:3900 + region: us-east-1 + accessKeyIdSecretKeyRef: + name: booklore-mariadb-cluster-backup-secret-garage + key: access + secretAccessKeySecretKeyRef: + name: booklore-mariadb-cluster-backup-secret-garage + key: secret diff --git a/clusters/cl01tl/helm/code-server/Chart.yaml b/clusters/cl01tl/helm/code-server/Chart.yaml new file mode 100644 index 000000000..6dab9e91c --- /dev/null +++ b/clusters/cl01tl/helm/code-server/Chart.yaml @@ -0,0 +1,28 @@ +apiVersion: v2 +name: code-server +version: 1.0.0 +description: Code Server +keywords: + - code-server + - code + - ide +home: https://wiki.alexlebens.dev/s/233f96bb-db70-47e4-8b22-a8efcbb0f93d +sources: + - https://github.com/coder/code-server + - https://github.com/cloudflare/cloudflared + - https://hub.docker.com/r/linuxserver/code-server + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: code-server + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: cloudflared + alias: cloudflared + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/visual-studio-code.png +appVersion: 4.100.2 diff --git a/clusters/cl01tl/helm/code-server/templates/external-secret.yaml b/clusters/cl01tl/helm/code-server/templates/external-secret.yaml new file mode 100644 index 000000000..4ec6bb8ac --- /dev/null +++ b/clusters/cl01tl/helm/code-server/templates/external-secret.yaml @@ -0,0 +1,51 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: codeserver-password-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: codeserver-password-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/code-server/auth + metadataPolicy: None + property: PASSWORD + - secretKey: SUDO_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/code-server/auth + metadataPolicy: None + property: SUDO_PASSWORD + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: code-server-cloudflared-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: code-server-cloudflared-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/codeserver + metadataPolicy: None + property: token diff --git a/clusters/cl01tl/helm/code-server/templates/http-route.yaml b/clusters/cl01tl/helm/code-server/templates/http-route.yaml new file mode 100644 index 000000000..0bd454572 --- /dev/null +++ b/clusters/cl01tl/helm/code-server/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-code-server + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-code-server + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - code-server.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: code-server + port: 8443 + weight: 100 diff --git a/clusters/cl01tl/helm/code-server/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/code-server/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..b4900de2a --- /dev/null +++ b/clusters/cl01tl/helm/code-server/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: code-server-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: code-server-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeMode: Filesystem + storageClassName: nfs-client + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/code-server/values.yaml b/clusters/cl01tl/helm/code-server/values.yaml new file mode 100644 index 000000000..6d44cc286 --- /dev/null +++ b/clusters/cl01tl/helm/code-server/values.yaml @@ -0,0 +1,47 @@ +code-server: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/linuxserver/code-server + tag: 4.106.2@sha256:a98afdbcb59559f11e5e8df284062e55da1076b2e470e13db4aae133ea82bad0 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + - name: DEFAULT_WORKSPACE + value: /config + envFrom: + - secretRef: + name: codeserver-password-secret + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 8443 + targetPort: 8443 + protocol: HTTP + persistence: + config: + existingClaim: code-server-nfs-storage + advancedMounts: + main: + main: + - path: /config + readOnly: false +cloudflared: + existingSecretName: code-server-cloudflared-secret diff --git a/clusters/cl01tl/helm/directus/Chart.yaml b/clusters/cl01tl/helm/directus/Chart.yaml new file mode 100644 index 000000000..a5b6f8b16 --- /dev/null +++ b/clusters/cl01tl/helm/directus/Chart.yaml @@ -0,0 +1,33 @@ +apiVersion: v2 +name: directus +version: 1.0.0 +description: Directus +keywords: + - directus + - cms +home: https://wiki.alexlebens.dev/s/c2d242de-dcaa-4801-86a2-c4761dc8bf9b +sources: + - https://github.com/directus/directus + - https://github.com/cloudflare/cloudflared + - https://github.com/cloudnative-pg/cloudnative-pg + - https://hub.docker.com/r/directus/directus + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: directus + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: cloudflared + alias: cloudflared-directus + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/directus.png +appVersion: 11.7.2 diff --git a/clusters/cl01tl/helm/directus/templates/external-secret.yaml b/clusters/cl01tl/helm/directus/templates/external-secret.yaml new file mode 100644 index 000000000..a225e81e2 --- /dev/null +++ b/clusters/cl01tl/helm/directus/templates/external-secret.yaml @@ -0,0 +1,245 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: directus-config + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: directus-config + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: admin-email + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/directus/config + metadataPolicy: None + property: admin-email + - secretKey: admin-password + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/directus/config + metadataPolicy: None + property: admin-password + - secretKey: secret + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/directus/config + metadataPolicy: None + property: secret + - secretKey: key + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/directus/config + metadataPolicy: None + property: key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: directus-metric-token + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: directus-metric-token + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: metric-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/directus/metrics + metadataPolicy: None + property: metric-token + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: directus-redis-config + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: directus-redis-config + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: user + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/directus/redis + metadataPolicy: None + property: user + - secretKey: password + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/directus/redis + metadataPolicy: None + property: password + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: directus-oidc-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: directus-oidc-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: OIDC_CLIENT_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/directus + metadataPolicy: None + property: client + - secretKey: OIDC_CLIENT_SECRET + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/directus + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: directus-cloudflared-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: directus-cloudflared-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/directus + metadataPolicy: None + property: token + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: directus-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: directus-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: directus-postgresql-17-cluster-backup-secret-weekly + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: directus-postgresql-17-cluster-backup-secret-weekly + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: directus-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: directus-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/directus/templates/object-bucket-claim.yaml b/clusters/cl01tl/helm/directus/templates/object-bucket-claim.yaml new file mode 100644 index 000000000..a512754f0 --- /dev/null +++ b/clusters/cl01tl/helm/directus/templates/object-bucket-claim.yaml @@ -0,0 +1,11 @@ +apiVersion: objectbucket.io/v1alpha1 +kind: ObjectBucketClaim +metadata: + name: ceph-bucket-directus + labels: + app.kubernetes.io/name: ceph-bucket-directus + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + generateBucketName: bucket-directus + storageClassName: ceph-bucket diff --git a/clusters/cl01tl/helm/directus/templates/redis-replication.yaml b/clusters/cl01tl/helm/directus/templates/redis-replication.yaml new file mode 100644 index 000000000..7fcb79d3b --- /dev/null +++ b/clusters/cl01tl/helm/directus/templates/redis-replication.yaml @@ -0,0 +1,35 @@ +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: redis-replication-directus + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-directus + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + clusterSize: 3 + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + kubernetesConfig: + image: quay.io/opstree/redis:v8.2.1 + imagePullPolicy: IfNotPresent + redisSecret: + name: directus-redis-config + key: password + resources: + requests: + cpu: 50m + memory: 128Mi + storage: + volumeClaimTemplate: + spec: + storageClassName: ceph-block + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + redisExporter: + enabled: true + image: quay.io/opstree/redis-exporter:v1.76.0 diff --git a/clusters/cl01tl/helm/directus/templates/redis-sentinel.yaml b/clusters/cl01tl/helm/directus/templates/redis-sentinel.yaml new file mode 100644 index 000000000..b7fdb8a6a --- /dev/null +++ b/clusters/cl01tl/helm/directus/templates/redis-sentinel.yaml @@ -0,0 +1,30 @@ +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisSentinel +metadata: + name: redis-sentinel-directus + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-sentinel-directus + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + clusterSize: 3 + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + redisSentinelConfig: + redisReplicationName: redis-replication-directus + redisReplicationPassword: + secretKeyRef: + name: directus-redis-config + key: password + kubernetesConfig: + image: quay.io/opstree/redis-sentinel:v7.0.15 + imagePullPolicy: IfNotPresent + redisSecret: + name: directus-redis-config + key: password + resources: + requests: + cpu: 10m + memory: 128Mi diff --git a/clusters/cl01tl/helm/directus/templates/service-monitor.yaml b/clusters/cl01tl/helm/directus/templates/service-monitor.yaml new file mode 100644 index 000000000..2e0768ec2 --- /dev/null +++ b/clusters/cl01tl/helm/directus/templates/service-monitor.yaml @@ -0,0 +1,43 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: directus + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: directus + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: directus + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: http + interval: 30s + scrapeTimeout: 15s + path: /metrics + bearerTokenSecret: + name: directus-metric-token + key: metric-token + +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: redis-replication-directus + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-directus + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + redis-operator: "true" + env: production +spec: + selector: + matchLabels: + redis_setup_type: replication + endpoints: + - port: redis-exporter + interval: 30s + scrapeTimeout: 10s diff --git a/clusters/cl01tl/helm/directus/values.yaml b/clusters/cl01tl/helm/directus/values.yaml new file mode 100644 index 000000000..10200a62b --- /dev/null +++ b/clusters/cl01tl/helm/directus/values.yaml @@ -0,0 +1,214 @@ +directus: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: directus/directus + tag: 11.13.4 + pullPolicy: IfNotPresent + env: + - name: PUBLIC_URL + value: https://directus.alexlebens.dev + - name: WEBSOCKETS_ENABLED + value: true + - name: ADMIN_EMAIL + valueFrom: + secretKeyRef: + name: directus-config + key: admin-email + - name: ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: directus-config + key: admin-password + - name: SECRET + valueFrom: + secretKeyRef: + name: directus-config + key: secret + - name: KEY + valueFrom: + secretKeyRef: + name: directus-config + key: key + - name: DB_CLIENT + value: postgres + - name: DB_HOST + valueFrom: + secretKeyRef: + name: directus-postgresql-17-cluster-app + key: host + - name: DB_DATABASE + valueFrom: + secretKeyRef: + name: directus-postgresql-17-cluster-app + key: dbname + - name: DB_PORT + valueFrom: + secretKeyRef: + name: directus-postgresql-17-cluster-app + key: port + - name: DB_USER + valueFrom: + secretKeyRef: + name: directus-postgresql-17-cluster-app + key: user + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: directus-postgresql-17-cluster-app + key: password + - name: SYNCHRONIZATION_STORE + value: redis + - name: CACHE_ENABLED + value: true + - name: CACHE_STORE + value: redis + - name: REDIS_ENABLED + value: true + - name: REDIS_HOST + value: redis-replication-directus-master + - name: REDIS_USERNAME + valueFrom: + secretKeyRef: + name: directus-redis-config + key: user + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: directus-redis-config + key: password + - name: STORAGE_LOCATIONS + value: s3 + - name: STORAGE_S3_DRIVER + value: s3 + - name: STORAGE_S3_KEY + valueFrom: + secretKeyRef: + name: ceph-bucket-directus + key: AWS_ACCESS_KEY_ID + - name: STORAGE_S3_SECRET + valueFrom: + secretKeyRef: + name: ceph-bucket-directus + key: AWS_SECRET_ACCESS_KEY + - name: STORAGE_S3_BUCKET + valueFrom: + configMapKeyRef: + name: ceph-bucket-directus + key: BUCKET_NAME + - name: STORAGE_S3_REGION + value: us-east-1 + - name: STORAGE_S3_ENDPOINT + value: http://rook-ceph-rgw-ceph-objectstore.rook-ceph.svc:80 + - name: STORAGE_S3_FORCE_PATH_STYLE + value: true + - name: AUTH_PROVIDERS + value: AUTHENTIK + - name: AUTH_AUTHENTIK_DRIVER + value: openid + - name: AUTH_AUTHENTIK_CLIENT_ID + valueFrom: + secretKeyRef: + name: directus-oidc-secret + key: OIDC_CLIENT_ID + - name: AUTH_AUTHENTIK_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: directus-oidc-secret + key: OIDC_CLIENT_SECRET + - name: AUTH_AUTHENTIK_SCOPE + value: openid profile email + - name: AUTH_AUTHENTIK_ISSUER_URL + value: https://auth.alexlebens.dev/application/o/directus/.well-known/openid-configuration + - name: AUTH_AUTHENTIK_IDENTIFIER_KEY + value: email + - name: AUTH_AUTHENTIK_ALLOW_PUBLIC_REGISTRATION + value: true + - name: AUTH_AUTHENTIK_LABEL + value: Authentik + - name: TELEMETRY + value: false + - name: METRICS_ENABLED + value: true + - name: METRICS_TOKENS + valueFrom: + secretKeyRef: + name: directus-metric-token + key: metric-token + resources: + requests: + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8055 + protocol: TCP +cloudflared-directus: + name: cloudflared-directus + existingSecretName: directus-cloudflared-secret +postgres-17-cluster: + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/directus/directus-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: directus-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/directus/directus-postgresql-17-cluster + index: 1 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/directus/directus-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: directus-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/directus/directus-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: directus-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 0 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/element-web/Chart.yaml b/clusters/cl01tl/helm/element-web/Chart.yaml new file mode 100644 index 000000000..15490271e --- /dev/null +++ b/clusters/cl01tl/helm/element-web/Chart.yaml @@ -0,0 +1,27 @@ +apiVersion: v2 +name: element-web +version: 1.0.0 +description: Element Web +keywords: + - element-web + - chat + - matrix +home: https://wiki.alexlebens.dev/s/e3b03481-1a1d-4b56-8cd9-e75a8dcc0f6c +sources: + - https://github.com/element-hq/element-web + - https://github.com/cloudflare/cloudflared + - https://hub.docker.com/r/vectorim/element-web + - https://gitlab.com/ananace/charts/-/tree/master/charts/element-web + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared +maintainers: + - name: alexlebens +dependencies: + - name: element-web + version: 1.4.24 + repository: https://ananace.gitlab.io/charts + - name: cloudflared + alias: cloudflared + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/element.png +appVersion: v1.11.100 diff --git a/clusters/cl01tl/helm/element-web/templates/external-secret.yaml b/clusters/cl01tl/helm/element-web/templates/external-secret.yaml new file mode 100644 index 000000000..276c3f4a4 --- /dev/null +++ b/clusters/cl01tl/helm/element-web/templates/external-secret.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: element-web-cloudflared-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: element-web-cloudflared-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/element + metadataPolicy: None + property: token diff --git a/clusters/cl01tl/helm/element-web/values.yaml b/clusters/cl01tl/helm/element-web/values.yaml new file mode 100644 index 000000000..970e993ee --- /dev/null +++ b/clusters/cl01tl/helm/element-web/values.yaml @@ -0,0 +1,28 @@ +element-web: + replicaCount: 1 + image: + repository: vectorim/element-web + tag: v1.12.4 + pullPolicy: IfNotPresent + defaultServer: + url: https://matrix.alexlebens.dev + name: alexlebens.dev + identity_url: https://alexlebens.dev + config: + disable_3pid_login: true + brand: "Alex Lebens" + branding: + welcome_background_url: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/background.jpg + auth_header_logo_url: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/logo-new-round.png + sso_redirect_options: + immediate: true + default_theme: dark + default_country_code: US + ingress: + enabled: false + resources: + requests: + cpu: 10m + memory: 128Mi +cloudflared: + existingSecretName: element-web-cloudflared-secret diff --git a/clusters/cl01tl/helm/ephemera/Chart.yaml b/clusters/cl01tl/helm/ephemera/Chart.yaml new file mode 100644 index 000000000..607d0716b --- /dev/null +++ b/clusters/cl01tl/helm/ephemera/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: ephemera +version: 1.0.0 +description: ephemera +keywords: + - ephemera + - books +home: https://wiki.alexlebens.dev/ +sources: + - https://github.com/OrwellianEpilogue/ephemera + - https://github.com/FlareSolverr/FlareSolverr + - https://github.com/orwellianepilogue/ephemera/pkgs/container/ephemera + - https://github.com/flaresolverr/FlareSolverr/pkgs/container/flaresolverr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: ephemera + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/ephemera.png +appVersion: 1.3.1 diff --git a/clusters/cl01tl/helm/ephemera/templates/external-secret.yaml b/clusters/cl01tl/helm/ephemera/templates/external-secret.yaml new file mode 100644 index 000000000..492cdad34 --- /dev/null +++ b/clusters/cl01tl/helm/ephemera/templates/external-secret.yaml @@ -0,0 +1,101 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: ephemera-key-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: ephemera-key-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: key + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/ephemera/config + metadataPolicy: None + property: key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: ephemera-apprise-config + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: ephemera-apprise-config + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ntfy-url + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/ephemera/config + metadataPolicy: None + property: ntfy-url + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: ephemera-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: ephemera-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/ephemera/ephemera-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/ephemera/templates/http-route.yaml b/clusters/cl01tl/helm/ephemera/templates/http-route.yaml new file mode 100644 index 000000000..16c8b2bbd --- /dev/null +++ b/clusters/cl01tl/helm/ephemera/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-ephemera + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-ephemera + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - ephemera.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: ephemera + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/ephemera/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/ephemera/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..1efb18d02 --- /dev/null +++ b/clusters/cl01tl/helm/ephemera/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: ephemera-import-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: ephemera-import-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: ephemera-import-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/ephemera/templates/persistent-volume.yaml b/clusters/cl01tl/helm/ephemera/templates/persistent-volume.yaml new file mode 100644 index 000000000..78d5b4e6f --- /dev/null +++ b/clusters/cl01tl/helm/ephemera/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: ephemera-import-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: ephemera-import-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/Books Import + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/ephemera/templates/replication-source.yaml b/clusters/cl01tl/helm/ephemera/templates/replication-source.yaml new file mode 100644 index 000000000..cffd4fcdf --- /dev/null +++ b/clusters/cl01tl/helm/ephemera/templates/replication-source.yaml @@ -0,0 +1,26 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: ephemera-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: ephemera-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: ephemera-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: ephemera-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot + cacheCapacity: 10Gi diff --git a/clusters/cl01tl/helm/ephemera/values.yaml b/clusters/cl01tl/helm/ephemera/values.yaml new file mode 100644 index 000000000..6fca7ddfb --- /dev/null +++ b/clusters/cl01tl/helm/ephemera/values.yaml @@ -0,0 +1,107 @@ +ephemera: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/orwellianepilogue/ephemera + tag: 1.3.1 + pullPolicy: IfNotPresent + env: + - name: AA_BASE_URL + value: https://annas-archive.org + # - name: AA_API_KEY + # valueFrom: + # secretKeyRef: + # name: ephemera-key-secret + # key: key + - name: FLARESOLVERR_URL + value: http://127.0.0.1:8191 + - name: LG_BASE_URL + value: https://gen.com + - name: PUID + value: 0 + - name: PGID + value: 0 + resources: + requests: + cpu: 50m + memory: 128Mi + flaresolverr: + image: + repository: ghcr.io/flaresolverr/flaresolverr + tag: v3.4.5 + pullPolicy: IfNotPresent + env: + - name: LOG_LEVEL + value: info + - name: LOG_HTML + value: false + - name: CAPTCHA_SOLVER + value: none + - name: TZ + value: America/Chicago + resources: + requests: + cpu: 10m + memory: 128Mi + apprise-api: + image: + repository: caronc/apprise + tag: 1.2.6 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: APPRISE_STORAGE_MODE + value: memory + - name: APPRISE_STATEFUL_MODE + value: disabled + - name: APPRISE_WORKER_COUNT + value: 1 + - name: APPRISE_STATELESS_URLS + valueFrom: + secretKeyRef: + name: ephemera-apprise-config + key: ntfy-url + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8286 + protocol: HTTP + persistence: + config: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /app/data + readOnly: false + cache: + type: emptyDir + advancedMounts: + main: + main: + - path: /app/downloads + readOnly: false + ingest: + existingClaim: ephemera-import-nfs-storage + advancedMounts: + main: + main: + - path: /app/ingest + readOnly: false diff --git a/clusters/cl01tl/helm/freshrss/Chart.yaml b/clusters/cl01tl/helm/freshrss/Chart.yaml new file mode 100644 index 000000000..8cfa7feab --- /dev/null +++ b/clusters/cl01tl/helm/freshrss/Chart.yaml @@ -0,0 +1,33 @@ +apiVersion: v2 +name: freshrss +version: 1.0.0 +description: FreshRSS +keywords: + - freshrss + - rss +home: https://wiki.alexlebens.dev/s/251cb7cb-2797-4bbb-8597-32757aa96391 +sources: + - https://github.com/FreshRSS/FreshRSS + - https://github.com/cloudflare/cloudflared + - https://github.com/cloudnative-pg/cloudnative-pg + - https://hub.docker.com/r/freshrss/freshrss + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: freshrss + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: cloudflared + alias: cloudflared + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/freshrss.png +appVersion: 1.26.2 diff --git a/clusters/cl01tl/helm/freshrss/templates/external-secret.yaml b/clusters/cl01tl/helm/freshrss/templates/external-secret.yaml new file mode 100644 index 000000000..c604c9e81 --- /dev/null +++ b/clusters/cl01tl/helm/freshrss/templates/external-secret.yaml @@ -0,0 +1,219 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: freshrss-install-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: freshrss-install-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ADMIN_EMAIL + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/freshrss/config + metadataPolicy: None + property: ADMIN_EMAIL + - secretKey: ADMIN_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/freshrss/config + metadataPolicy: None + property: ADMIN_PASSWORD + - secretKey: ADMIN_API_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/freshrss/config + metadataPolicy: None + property: ADMIN_API_PASSWORD + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: freshrss-oidc-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: freshrss-oidc-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: OIDC_CLIENT_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/freshrss + metadataPolicy: None + property: client + - secretKey: OIDC_CLIENT_SECRET + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/freshrss + metadataPolicy: None + property: secret + - secretKey: OIDC_CLIENT_CRYPTO_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/freshrss + metadataPolicy: None + property: crypto-key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: freshrss-cloudflared-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: freshrss-cloudflared-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/freshrss + metadataPolicy: None + property: token + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: freshrss-data-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: freshrss-data-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/freshrss/freshrss-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: freshrss-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: freshrss-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: freshrss-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: freshrss-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/freshrss/templates/replication-source.yaml b/clusters/cl01tl/helm/freshrss/templates/replication-source.yaml new file mode 100644 index 000000000..0b0e03a62 --- /dev/null +++ b/clusters/cl01tl/helm/freshrss/templates/replication-source.yaml @@ -0,0 +1,35 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: freshrss-data-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: freshrss-data-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: freshrss-data + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: freshrss-data-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 568 + runAsGroup: 568 + fsGroup: 568 + fsGroupChangePolicy: OnRootMismatch + supplementalGroups: + - 44 + - 100 + - 109 + - 65539 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/freshrss/values.yaml b/clusters/cl01tl/helm/freshrss/values.yaml new file mode 100644 index 000000000..c328f13ec --- /dev/null +++ b/clusters/cl01tl/helm/freshrss/values.yaml @@ -0,0 +1,251 @@ +freshrss: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + initContainers: + init-download-extension-1: + securityContext: + runAsUser: 0 + image: + repository: alpine + tag: 3.22.2 + pullPolicy: IfNotPresent + command: + - /bin/sh + - -ec + - | + apk add --no-cache git; + cd /tmp; + git clone -n --depth=1 --filter=tree:0 https://github.com/cn-tools/cntools_FreshRssExtensions.git; + cd cntools_FreshRssExtensions; + git sparse-checkout set --no-cone /xExtension-YouTubeChannel2RssFeed; + git checkout; + rm -rf /var/www/FreshRSS/extensions/xExtension-YouTubeChannel2RssFeed + cp -r xExtension-YouTubeChannel2RssFeed /var/www/FreshRSS/extensions + chown -R 568:568 /var/www/FreshRSS/extensions/xExtension-YouTubeChannel2RssFeed + resources: + requests: + cpu: 10m + memory: 128Mi + init-download-extension-2: + securityContext: + runAsUser: 0 + image: + repository: alpine + tag: 3.22.2 + pullPolicy: IfNotPresent + command: + - /bin/sh + - -ec + - | + apk add --no-cache git; + cd /tmp; + git clone -n --depth=1 --filter=tree:0 https://github.com/FreshRSS/Extensions.git; + cd Extensions; + git sparse-checkout set --no-cone /xExtension-ImageProxy; + git checkout; + rm -rf /var/www/FreshRSS/extensions/xExtension-ImageProxy + cp -r xExtension-ImageProxy /var/www/FreshRSS/extensions + chown -R 568:568 /var/www/FreshRSS/extensions/xExtension-ImageProxy + resources: + requests: + cpu: 10m + memory: 128Mi + init-download-extension-3: + securityContext: + runAsUser: 0 + image: + repository: alpine + tag: 3.22.2 + pullPolicy: IfNotPresent + command: + - /bin/sh + - -ec + - | + cd /tmp; + wget https://github.com/zimmra/xExtension-karakeep-button/archive/refs/tags/v1.1.tar.gz; + tar -xvzf *.tar.gz; + rm -rf /var/www/FreshRSS/extensions/xExtension-karakeep-button + mkdir /var/www/FreshRSS/extensions/xExtension-karakeep-button + cp -r /tmp/xExtension-karakeep-button-*/* /var/www/FreshRSS/extensions/xExtension-karakeep-button + chown -R 568:568 /var/www/FreshRSS/extensions/xExtension-karakeep-button + resources: + requests: + cpu: 10m + memory: 128Mi + containers: + main: + image: + repository: freshrss/freshrss + tag: 1.27.1 + pullPolicy: IfNotPresent + env: + - name: PGID + value: "568" + - name: PUID + value: "568" + - name: TZ + value: US/Central + - name: FRESHRSS_ENV + value: production + - name: CRON_MIN + value: 13,43 + - name: BASE_URL + value: https://rss.alexlebens.dev + - name: DB_HOST + valueFrom: + secretKeyRef: + name: freshrss-postgresql-17-cluster-app + key: host + - name: DB_BASE + valueFrom: + secretKeyRef: + name: freshrss-postgresql-17-cluster-app + key: dbname + - name: DB_USER + valueFrom: + secretKeyRef: + name: freshrss-postgresql-17-cluster-app + key: user + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: freshrss-postgresql-17-cluster-app + key: password + - name: FRESHRSS_INSTALL + value: | + --api-enabled + --base-url $(BASE_URL) + --db-base $(DB_BASE) + --db-host $(DB_HOST) + --db-password $(DB_PASSWORD) + --db-type pgsql + --db-user $(DB_USER) + --auth-type http_auth + --default-user admin + --language en + - name: FRESHRSS_USER + value: | + --api-password $(ADMIN_API_PASSWORD) + --email $(ADMIN_EMAIL) + --language en + --password $(ADMIN_PASSWORD) + --user admin + - name: OIDC_ENABLED + value: 1 + - name: OIDC_PROVIDER_METADATA_URL + value: https://auth.alexlebens.dev/application/o/freshrss/.well-known/openid-configuration + - name: OIDC_X_FORWARDED_HEADERS + value: X-Forwarded-Port X-Forwarded-Proto X-Forwarded-Host + - name: OIDC_SCOPES + value: openid email profile + - name: OIDC_REMOTE_USER_CLAIM + value: preferred_username + envFrom: + - secretRef: + name: freshrss-oidc-secret + - secretRef: + name: freshrss-install-secret + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 80 + protocol: HTTP + persistence: + data: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /var/www/FreshRSS/data + readOnly: false + extensions: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 1Gi + retain: true + advancedMounts: + main: + init-download-extension-1: + - path: /var/www/FreshRSS/extensions + readOnly: false + init-download-extension-2: + - path: /var/www/FreshRSS/extensions + readOnly: false + init-download-extension-3: + - path: /var/www/FreshRSS/extensions + readOnly: false + main: + - path: /var/www/FreshRSS/extensions + readOnly: false +cloudflared: + existingSecretName: freshrss-cloudflared-secret +postgres-17-cluster: + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/freshrss/freshrss-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: freshrss-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/freshrss/freshrss-postgresql-17-cluster + index: 1 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/freshrss/freshrss-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: freshrss-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/freshrss/freshrss-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: freshrss-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 2 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/home-assistant/Chart.yaml b/clusters/cl01tl/helm/home-assistant/Chart.yaml new file mode 100644 index 000000000..e31b127db --- /dev/null +++ b/clusters/cl01tl/helm/home-assistant/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: home-assistant +version: 1.0.0 +description: Home Assistant +keywords: + - home-assistant + - home + - automation +home: https://wiki.alexlebens.dev/s/5462c17e-cd39-4082-ad01-94545a2fa3ca +sources: + - https://www.home-assistant.io/ + - https://github.com/home-assistant/core + - https://github.com/home-assistant/core/pkgs/container/home-assistant + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: home-assistant + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/home-assistant.png +appVersion: 2025.5.2 diff --git a/clusters/cl01tl/helm/home-assistant/templates/external-secret.yaml b/clusters/cl01tl/helm/home-assistant/templates/external-secret.yaml new file mode 100644 index 000000000..8831bf961 --- /dev/null +++ b/clusters/cl01tl/helm/home-assistant/templates/external-secret.yaml @@ -0,0 +1,51 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: home-assistant-code-server-password-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: home-assistant-code-server-password-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/home-assistant/code-server/auth + metadataPolicy: None + property: PASSWORD + - secretKey: SUDO_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/home-assistant/code-server/auth + metadataPolicy: None + property: SUDO_PASSWORD + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: home-assistant-token-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: home-assistant-token-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: bearer-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/home-assistant/auth + metadataPolicy: None + property: bearer-token diff --git a/clusters/cl01tl/helm/home-assistant/templates/http-route.yaml b/clusters/cl01tl/helm/home-assistant/templates/http-route.yaml new file mode 100644 index 000000000..3c74c7c72 --- /dev/null +++ b/clusters/cl01tl/helm/home-assistant/templates/http-route.yaml @@ -0,0 +1,58 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-home-assistant + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-home-assistant + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - home-assistant.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: home-assistant-main + port: 80 + weight: 100 + +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-home-assistant-code-server + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-home-assistant-code-server + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - home-assistant-code-server.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: home-assistant-code-server + port: 8443 + weight: 100 diff --git a/clusters/cl01tl/helm/home-assistant/templates/service-monitor.yaml b/clusters/cl01tl/helm/home-assistant/templates/service-monitor.yaml new file mode 100644 index 000000000..fa644fab1 --- /dev/null +++ b/clusters/cl01tl/helm/home-assistant/templates/service-monitor.yaml @@ -0,0 +1,23 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: home-assistant + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: home-assistant + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: home-assistant + app.kubernetes.io/service: home-assistant-main + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: http + interval: 3m + scrapeTimeout: 1m + path: /api/prometheus + bearerTokenSecret: + name: home-assistant-token-secret + key: bearer-token diff --git a/clusters/cl01tl/helm/home-assistant/values.yaml b/clusters/cl01tl/helm/home-assistant/values.yaml new file mode 100644 index 000000000..8e49734a4 --- /dev/null +++ b/clusters/cl01tl/helm/home-assistant/values.yaml @@ -0,0 +1,70 @@ +home-assistant: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/home-assistant/home-assistant + tag: 2025.11.3 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + resources: + requests: + cpu: 50m + memory: 512Mi + code-server: + image: + repository: ghcr.io/linuxserver/code-server + tag: 4.106.2@sha256:a98afdbcb59559f11e5e8df284062e55da1076b2e470e13db4aae133ea82bad0 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + - name: DEFAULT_WORKSPACE + value: /config + envFrom: + - secretRef: + name: home-assistant-code-server-password-secret + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8123 + protocol: TCP + code-server: + controller: main + ports: + http: + port: 8443 + targetPort: 8443 + protocol: HTTP + persistence: + config: + forceRename: home-assistant-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + advancedMounts: + main: + main: + - path: /config + readOnly: false + code-server: + - path: /config/home-assistant + readOnly: false diff --git a/clusters/cl01tl/helm/homepage-dev/Chart.yaml b/clusters/cl01tl/helm/homepage-dev/Chart.yaml new file mode 100644 index 000000000..4b115d15b --- /dev/null +++ b/clusters/cl01tl/helm/homepage-dev/Chart.yaml @@ -0,0 +1,27 @@ +apiVersion: v2 +name: homepage +version: 1.0.0 +description: Homepage +keywords: + - homepage + - dashboard +home: https://wiki.alexlebens.dev/s/a5fabd91-3d89-4e2b-9417-06111aedaeaa +sources: + - https://github.com/gethomepage/homepage + - https://github.com/cloudflare/cloudflared + - https://github.com/gethomepage/homepage/pkgs/container/homepage + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: homepage + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: cloudflared + alias: cloudflared + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/homepage.png +appVersion: v1.2.0 diff --git a/clusters/cl01tl/helm/homepage-dev/templates/external-secret.yaml b/clusters/cl01tl/helm/homepage-dev/templates/external-secret.yaml new file mode 100644 index 000000000..d0292e50a --- /dev/null +++ b/clusters/cl01tl/helm/homepage-dev/templates/external-secret.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: homepage-dev-cloudflared-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: homepage-dev-cloudflared-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/homepage-dev + metadataPolicy: None + property: token diff --git a/clusters/cl01tl/helm/homepage-dev/values.yaml b/clusters/cl01tl/helm/homepage-dev/values.yaml new file mode 100644 index 000000000..75dcc2964 --- /dev/null +++ b/clusters/cl01tl/helm/homepage-dev/values.yaml @@ -0,0 +1,167 @@ +homepage: + global: + nameOverride: homepage + controllers: + main: + type: deployment + annotations: + reloader.stakater.com/auto: "true" + strategy: Recreate + containers: + main: + image: + repository: ghcr.io/gethomepage/homepage + tag: v1.7.0 + pullPolicy: IfNotPresent + env: + - name: HOMEPAGE_ALLOWED_HOSTS + value: home.alexlebens.dev + resources: + requests: + cpu: 10m + memory: 128Mi + configMaps: + config: + enabled: true + data: + docker.yaml: "" + kubernetes.yaml: "" + settings.yaml: | + favicon: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/logo-new-round.svg + headerStyle: clean + hideVersion: true + color: zinc + background: + image: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/background.jpg + brightness: 50 + theme: dark + disableCollapse: true + widgets.yaml: | + - logo: + icon: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/logo-new-round.png + - datetime: + text_size: xl + format: + dateStyle: long + timeStyle: short + hour12: false + - openmeteo: + label: St. Paul + latitude: 44.954445 + longitude: -93.091301 + timezone: America/Chicago + units: metric + cache: 5 + format: + maximumFractionDigits: 0 + services.yaml: | + - Applications: + - Auth: + icon: sh-authentik.webp + description: Authentik + href: https://auth.alexlebens.dev + siteMonitor: https://auth.alexlebens.dev + statusStyle: dot + - Gitea: + icon: sh-gitea.webp + description: Gitea + href: https://gitea.alexlebens.dev + siteMonitor: https://gitea.alexlebens.dev + statusStyle: dot + - Code: + icon: sh-visual-studio-code.webp + description: VS Code + href: https://codeserver.alexlebens.dev + siteMonitor: https://codeserver.alexlebens.dev + statusStyle: dot + - Site: + icon: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/logo-new-round.png + description: Profile Website + href: https://www.alexlebens.dev + siteMonitor: https://www.alexlebens.dev + statusStyle: dot + - Content Management: + icon: directus.png + description: Directus + href: https://directus.alexlebens.dev + siteMonitor: https://directus.alexlebens.dev + statusStyle: dot + - Social Media Management: + icon: sh-postiz.webp + description: Postiz + href: https://postiz.alexlebens.dev + siteMonitor: https://postiz.alexlebens.dev + statusStyle: dot + - Chat: + icon: sh-element.webp + description: Matrix + href: https://chat.alexlebens.dev + siteMonitor: https://chat.alexlebens.dev + statusStyle: dot + - Wiki: + icon: sh-outline.webp + description: Outline + href: https://wiki.alexlebens.dev + siteMonitor: https://wiki.alexlebens.dev + statusStyle: dot + - Passwords: + icon: sh-vaultwarden-light.webp + description: Vaultwarden + href: https://passwords.alexlebens.dev + siteMonitor: https://passwords.alexlebens.dev + statusStyle: dot + - Bookmarks: + icon: sh-karakeep-light.webp + description: Karakeep + href: https://karakeep.alexlebens.dev + siteMonitor: https://karakeep.alexlebens.dev + statusStyle: dot + - RSS: + icon: sh-freshrss.webp + description: FreshRSS + href: https://rss.alexlebens.dev + siteMonitor: https://rss.alexlebens.dev + statusStyle: dot + bookmarks.yaml: "" + service: + http: + controller: main + ports: + http: + port: 80 + targetPort: 3000 + protocol: HTTP + persistence: + config: + enabled: true + type: configMap + name: homepage-dev + advancedMounts: + main: + main: + - path: /app/config/bookmarks.yaml + readOnly: true + mountPropagation: None + subPath: bookmarks.yaml + - path: /app/config/docker.yaml + readOnly: true + mountPropagation: None + subPath: docker.yaml + - path: /app/config/kubernetes.yaml + readOnly: true + mountPropagation: None + subPath: kubernetes.yaml + - path: /app/config/services.yaml + readOnly: true + mountPropagation: None + subPath: services.yaml + - path: /app/config/settings.yaml + readOnly: true + mountPropagation: None + subPath: settings.yaml + - path: /app/config/widgets.yaml + readOnly: true + mountPropagation: None + subPath: widgets.yaml +cloudflared: + existingSecretName: homepage-dev-cloudflared-secret diff --git a/clusters/cl01tl/helm/homepage/Chart.yaml b/clusters/cl01tl/helm/homepage/Chart.yaml new file mode 100644 index 000000000..13b36a778 --- /dev/null +++ b/clusters/cl01tl/helm/homepage/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: homepage +version: 1.0.0 +description: Homepage +keywords: + - homepage + - dashboard +home: https://wiki.alexlebens.dev/s/a5fabd91-3d89-4e2b-9417-06111aedaeaa +sources: + - https://github.com/gethomepage/homepage + - https://github.com/gethomepage/homepage/pkgs/container/homepage + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: homepage + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/homepage.png +appVersion: v1.2.0 diff --git a/clusters/cl01tl/helm/homepage/templates/cluster-role-binding.yaml b/clusters/cl01tl/helm/homepage/templates/cluster-role-binding.yaml new file mode 100644 index 000000000..224a93bd2 --- /dev/null +++ b/clusters/cl01tl/helm/homepage/templates/cluster-role-binding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: homepage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: homepage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: homepage +subjects: + - kind: ServiceAccount + name: homepage + namespace: {{ .Release.Namespace }} diff --git a/clusters/cl01tl/helm/homepage/templates/cluster-role.yaml b/clusters/cl01tl/helm/homepage/templates/cluster-role.yaml new file mode 100644 index 000000000..3b8b2d256 --- /dev/null +++ b/clusters/cl01tl/helm/homepage/templates/cluster-role.yaml @@ -0,0 +1,50 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: homepage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: homepage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +rules: + - apiGroups: + - "" + resources: + - namespaces + - pods + - nodes + verbs: + - get + - list + - apiGroups: + - extensions + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - apiGroups: + - traefik.io + resources: + - ingressroutes + verbs: + - get + - list + - apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes + - gateways + verbs: + - get + - list + - apiGroups: + - metrics.k8s.io + resources: + - nodes + - pods + verbs: + - get + - list diff --git a/clusters/cl01tl/helm/homepage/templates/external-secret.yaml b/clusters/cl01tl/helm/homepage/templates/external-secret.yaml new file mode 100644 index 000000000..dd79ecc3e --- /dev/null +++ b/clusters/cl01tl/helm/homepage/templates/external-secret.yaml @@ -0,0 +1,105 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: homepage-keys-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: homepage-keys-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: HOMEPAGE_VAR_SYNOLOGY_USER + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /synology/auth/cl01tl + metadataPolicy: None + property: user + - secretKey: HOMEPAGE_VAR_SYNOLOGY_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /synology/auth/cl01tl + metadataPolicy: None + property: password + - secretKey: HOMEPAGE_VAR_UNIFI_USER + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /unifi/auth/cl01tl + metadataPolicy: None + property: user + - secretKey: HOMEPAGE_VAR_UNIFI_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /unifi/auth/cl01tl + metadataPolicy: None + property: password + - secretKey: HOMEPAGE_VAR_SONARR_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/sonarr4/key + metadataPolicy: None + property: key + - secretKey: HOMEPAGE_VAR_SONARR4K_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/sonarr4-4k/key + metadataPolicy: None + property: key + - secretKey: HOMEPAGE_VAR_SONARRANIME_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/sonarr4-anime/key + metadataPolicy: None + property: key + - secretKey: HOMEPAGE_VAR_RADARR_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/radarr5/key + metadataPolicy: None + property: key + - secretKey: HOMEPAGE_VAR_RADARR4K_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/radarr5-4k/key + metadataPolicy: None + property: key + - secretKey: HOMEPAGE_VAR_RADARRANIME_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/radarr5-anime/key + metadataPolicy: None + property: key + - secretKey: HOMEPAGE_VAR_RADARRSTANDUP_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/radarr5-standup/key + metadataPolicy: None + property: key + - secretKey: HOMEPAGE_VAR_LIDARR_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/lidarr2/key + metadataPolicy: None + property: key + - secretKey: HOMEPAGE_VAR_PROWLARR_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/prowlarr/key + metadataPolicy: None + property: key diff --git a/clusters/cl01tl/helm/homepage/templates/http-route.yaml b/clusters/cl01tl/helm/homepage/templates/http-route.yaml new file mode 100644 index 000000000..f3ccd33e2 --- /dev/null +++ b/clusters/cl01tl/helm/homepage/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-homepage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-homepage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - home.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: homepage + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/homepage/templates/service.yaml b/clusters/cl01tl/helm/homepage/templates/service.yaml new file mode 100644 index 000000000..43fe2e1d9 --- /dev/null +++ b/clusters/cl01tl/helm/homepage/templates/service.yaml @@ -0,0 +1,46 @@ +apiVersion: v1 +kind: Service +metadata: + name: gitea-ps10rp + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: gitea-ps10rp + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + annotations: + tailscale.com/tailnet-fqdn: gitea-ps10rp.boreal-beaufort.ts.net +spec: + externalName: placeholder + type: ExternalName + +--- +apiVersion: v1 +kind: Service +metadata: + name: home-ps10rp + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: home-ps10rp + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + annotations: + tailscale.com/tailnet-fqdn: home-ps10rp.boreal-beaufort.ts.net +spec: + externalName: placeholder + type: ExternalName + +--- +apiVersion: v1 +kind: Service +metadata: + name: garage-ui-ps10rp + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: garage-ps10rp + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + annotations: + tailscale.com/tailnet-fqdn: garage-ui-ps10rp.boreal-beaufort.ts.net +spec: + externalName: placeholder + type: ExternalName diff --git a/clusters/cl01tl/helm/homepage/values.yaml b/clusters/cl01tl/helm/homepage/values.yaml new file mode 100644 index 000000000..090c6be04 --- /dev/null +++ b/clusters/cl01tl/helm/homepage/values.yaml @@ -0,0 +1,795 @@ +homepage: + global: + nameOverride: homepage + controllers: + main: + type: deployment + annotations: + reloader.stakater.com/auto: "true" + strategy: Recreate + serviceAccount: + name: homepage + pod: + automountServiceAccountToken: true + containers: + main: + image: + repository: ghcr.io/gethomepage/homepage + tag: v1.7.0 + pullPolicy: IfNotPresent + env: + - name: HOMEPAGE_ALLOWED_HOSTS + value: home.alexlebens.net + envFrom: + - secretRef: + name: homepage-keys-secret + resources: + requests: + cpu: 10m + memory: 256Mi + serviceAccount: + homepage: + enabled: true + staticToken: true + configMaps: + config: + enabled: true + data: + docker.yaml: "" + kubernetes.yaml: | + mode: cluster + settings.yaml: | + favicon: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/logo-new-round.svg + headerStyle: clean + hideVersion: true + color: zinc + background: + image: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/background.jpg + brightness: 50 + theme: dark + disableCollapse: true + layout: + - Media: + tab: Applications + icon: mdi-multimedia-#ffffff + - Public: + tab: Applications + icon: mdi-earth-#ffffff + - Internal: + tab: Applications + icon: mdi-security-network-#ffffff + - Code: + tab: Tools + icon: mdi-code-block-braces-#ffffff + - Automation: + tab: Tools + icon: mdi-wrench-#ffffff + - Monitoring: + tab: Tools + icon: mdi-chart-line-#ffffff + - Services: + tab: Services + icon: mdi-toolbox-outline-#ffffff + - Hardware: + tab: Services + icon: mdi-server-network-#ffffff + - Storage: + tab: Services + icon: mdi-database-#ffffff + - Content: + tab: Services + icon: mdi-multimedia-#ffffff + - TV Shows: + tab: Content + icon: mdi-television-#ffffff + - Movies: + tab: Content + icon: mdi-filmstrip-#ffffff + - Music: + tab: Content + icon: mdi-music-box-multiple-#ffffff + - Books: + tab: Content + icon: mdi-book-open-variant-#ffffff + - External Services: + tab: Bookmarks + icon: mdi-cloud-#ffffff + - Other Homes: + tab: Bookmarks + icon: mdi-cloud-#ffffff + - Trackers: + tab: Bookmarks + icon: mdi-cloud-#ffffff + widgets.yaml: | + - logo: + icon: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/logo-new-round.png + - kubernetes: + cluster: + show: true + cpu: true + memory: true + showLabel: false + label: "Cluster" + nodes: + show: false + - datetime: + text_size: xl + format: + dateStyle: long + timeStyle: short + hour12: false + - openmeteo: + label: St. Paul + latitude: 44.954445 + longitude: -93.091301 + timezone: America/Chicago + units: metric + cache: 5 + format: + maximumFractionDigits: 0 + services.yaml: | + - Media: + - Plex: + icon: sh-plex.webp + description: Media server + href: https://plex.alexlebens.net + siteMonitor: http://plex.plex:32400 + statusStyle: dot + - Jellyfin: + icon: sh-jellyfin.webp + description: Media server + href: https://jellyfin.alexlebens.net + siteMonitor: http://jellyfin.jellyfin:80 + statusStyle: dot + - Media Requests: + icon: sh-overseerr.webp + description: Overseer + href: https://overseerr.alexlebens.net + siteMonitor: http://overseerr.overseerr:80 + statusStyle: dot + - Media Tracking: + icon: sh-yamtrack.webp + description: Yamtrack + href: https://yamtrack.alexlebens.net + siteMonitor: http://yamtrack.yamtrack:80 + statusStyle: dot + - Youtube Archive: + icon: sh-tube-archivist-light.webp + description: TubeAchivist + href: https://tubearchivist.alexlebens.net/login + siteMonitor: http://tubearchivist.tubearchivist:80 + statusStyle: dot + - Photos: + icon: sh-immich.webp + description: Immich + href: https://immich.alexlebens.net + siteMonitor: http://immich-main.immich:2283 + statusStyle: dot + - Pictures: + icon: sh-photoview.webp + description: Photoview + href: https://photoview.alexlebens.net + siteMonitor: http://photoview.photoview:80 + statusStyle: dot + - Podcasts and Audiobooks: + icon: sh-audiobookshelf.webp + description: Audiobookshelf + href: https://audiobookshelf.alexlebens.net + siteMonitor: http://audiobookshelf.audiobookshelf:80 + statusStyle: dot + - Books: + icon: sh-booklore.webp + description: Booklore + href: https://booklore.alexlebens.net + siteMonitor: http://booklore.booklore:80 + statusStyle: dot + - Public: + - Site: + icon: https://web-assets-3bfcb5585cbd63dc365d32a3.nyc3.cdn.digitaloceanspaces.com/alexlebens-net/logo-new-round.png + description: Profile Website + href: https://www.alexlebens.dev + siteMonitor: https://www.alexlebens.dev + statusStyle: dot + - Content Management: + icon: directus.png + description: Directus + href: https://directus.alexlebens.dev + siteMonitor: https://directus.alexlebens.dev + statusStyle: dot + - Social Media Management: + icon: sh-postiz.webp + description: Postiz + href: https://postiz.alexlebens.dev + siteMonitor: https://postiz.alexlebens.dev + statusStyle: dot + - Chat: + icon: sh-element.webp + description: Matrix + href: https://chat.alexlebens.dev + siteMonitor: https://chat.alexlebens.dev + statusStyle: dot + - Wiki: + icon: sh-outline.webp + description: Outline + href: https://wiki.alexlebens.dev + siteMonitor: https://wiki.alexlebens.dev + statusStyle: dot + - Passwords: + icon: sh-vaultwarden-light.webp + description: Vaultwarden + href: https://passwords.alexlebens.dev + siteMonitor: https://passwords.alexlebens.dev + statusStyle: dot + - Bookmarks: + icon: sh-karakeep-light.webp + description: Karakeep + href: https://karakeep.alexlebens.dev + siteMonitor: https://karakeep.alexlebens.dev + statusStyle: dot + - RSS: + icon: sh-freshrss.webp + description: FreshRSS + href: https://rss.alexlebens.dev + siteMonitor: https://rss.alexlebens.dev + statusStyle: dot + - Internal: + - Home Automation: + icon: sh-home-assistant.webp + description: Home Assistant + href: https://home-assistant.alexlebens.net + siteMonitor: http://home-assistant-main.home-assistant:80 + statusStyle: dot + - Budgeting: + icon: sh-actual-budget.webp + description: Actual + href: https://actual.alexlebens.net + siteMonitor: http://actual.actual:80 + statusStyle: dot + - AI: + icon: sh-ollama.webp + description: Ollama + href: https://ollama.alexlebens.net + siteMonitor: http://ollama-web.ollama:80 + statusStyle: dot + - AI Image: + icon: https://user-images.githubusercontent.com/36368048/196280761-1535f413-a91e-4b6a-af6a-b890f8ae204c.png + description: Stable Diffusion + href: https://stable-diffusion-pd05wd.boreal-beaufort.ts.net + siteMonitor: https://stable-diffusion-pd05wd.boreal-beaufort.ts.net + statusStyle: dot + - Search: + icon: sh-searxng.webp + description: Searxng + href: https://searxng.alexlebens.net/ + siteMonitor: http://searxng-browser.searxng:80 + statusStyle: dot + - Email: + icon: sh-roundcube.webp + description: Roundcube + href: https://mail.alexlebens.net + siteMonitor: http://roundcube.roundcube:80 + statusStyle: dot + - Wiki: + icon: sh-kiwix-light.webp + description: Kiwix + href: https://kiwix.alexlebens.net + siteMonitor: http://kiwix.kiwix:80 + statusStyle: dot + - Code: + - Code (Public): + icon: sh-gitea.webp + description: Gitea + href: https://gitea.alexlebens.dev + siteMonitor: https://gitea.alexlebens.dev + statusStyle: dot + - Code (Local): + icon: sh-gitea.webp + description: Gitea + href: https://gitea.alexlebens.net + siteMonitor: https://gitea.alexlebens.net + statusStyle: dot + - Code (ps10rp): + icon: sh-gitea.webp + description: Gitea + href: https://gitea-ps10rp.boreal-beaufort.ts.net + siteMonitor: https://gitea-ps10rp.boreal-beaufort.ts.net + statusStyle: dot + - IDE (Public): + icon: sh-visual-studio-code.webp + description: VS Code + href: https://codeserver.alexlebens.dev + siteMonitor: https://codeserver.alexlebens.dev + statusStyle: dot + - IDE (Home Assistant): + icon: sh-visual-studio-code.webp + description: Edit config for Home Assistant + href: https://home-assistant-code-server.alexlebens.net + siteMonitor: http://home-assistant-code-server.home-assistant:8443 + statusStyle: dot + - Continuous Deployment: + icon: sh-argo-cd.webp + description: ArgoCD + href: https://argocd.alexlebens.net + siteMonitor: http://argocd-server.argocd:80 + statusStyle: dot + - Docker Deployment: + icon: sh-komodo-light.webp + description: Komodo + href: https://komodo.alexlebens.net + siteMonitor: http://komodo-main.komodo:80 + statusStyle: dot + - Automation: + - Deployment Workflows: + icon: sh-argo-cd.webp + description: Argo Workflows + href: https://argo-workflows.alexlebens.net + siteMonitor: http://argo-workflows-server.argo-workflows:2746 + statusStyle: dot + - API Workflows: + icon: sh-n8n.webp + description: n8n + href: https://n8n.alexlebens.net + siteMonitor: http://n8n-main.n8n:80 + statusStyle: dot + - Jobs: + icon: https://raw.githubusercontent.com/mshade/kronic/main/static/android-chrome-192x192.png + description: Kronic + href: https://kronic.alexlebens.net + siteMonitor: http://kronic.kronic:80 + statusStyle: dot + - Uptime: + icon: sh-gatus.webp + description: Gatus + href: https://gatus.alexlebens.net + siteMonitor: http://gatus.gatus:80 + statusStyle: dot + - Tools: + icon: sh-omnitools.webp + description: OmniTools + href: https://omni-tools.alexlebens.net + siteMonitor: http://omni-tools.omni-tools:80 + statusStyle: dot + - Monitoring: + - Kubernetes: + icon: sh-headlamp.webp + description: Headlamp + href: https://headlamp.alexlebens.net + siteMonitor: http://headlamp.headlamp:80 + statusStyle: dot + - Network Monitoring: + icon: sh-cilium.webp + description: Hubble for Cilium + href: https://hubble.alexlebens.net + siteMonitor: http://hubble-ui.kube-system:80 + statusStyle: dot + - Dashboard: + icon: sh-grafana.webp + description: Grafana + href: https://grafana.alexlebens.net + siteMonitor: http://grafana-main-service.grafana-operator:3000/api/health + statusStyle: dot + - Metrics: + icon: sh-prometheus.webp + description: Prometheus + href: https://prometheus.alexlebens.net + siteMonitor: http://kube-prometheus-stack-prometheus.kube-prometheus-stack:9090 + statusStyle: dot + widget: + type: prometheus + url: http://kube-prometheus-stack-prometheus.kube-prometheus-stack:9090 + - Alerting: + icon: sh-prometheus-light.webp + description: Alertmanager + href: https://alertmanager.alexlebens.net + siteMonitor: http://kube-prometheus-stack-alertmanager.kube-prometheus-stack:9093 + statusStyle: dot + widget: + type: prometheusmetric + url: http://kube-prometheus-stack-prometheus.kube-prometheus-stack:9090 + refreshInterval: 120s + metrics: + - label: Alerts Active + query: alertmanager_alerts{state="active"} + - label: Metric Database Size + query: prometheus_tsdb_storage_blocks_bytes + format: + type: bytes + - Tautulli: + icon: sh-tautulli.webp + description: Plex Monitoring + href: https://tautulli.alexlebens.net + siteMonitor: http://tautulli.tautulli:80 + statusStyle: dot + - Jellystat: + icon: sh-jellystat.webp + description: Jellyfin Monitoring + href: https://jellystat.alexlebens.net + siteMonitor: http://jellystat.jellystat:80 + statusStyle: dot + - Services: + - Auth (Public): + icon: sh-authentik.webp + description: Authentik + href: https://auth.alexlebens.dev + siteMonitor: https://auth.alexlebens.dev + statusStyle: dot + - Auth (Local): + icon: sh-authentik.webp + description: Authentik + href: https://authentik.alexlebens.net + siteMonitor: http://authentik-server.authentik:80 + statusStyle: dot + - Email: + icon: sh-stalwart.webp + description: Stalwart + href: https://stalwart.alexlebens.net + siteMonitor: http://stalwart.stalwart:80 + statusStyle: dot + - Notifications: + icon: sh-ntfy.webp + description: ntfy + href: https://ntfy.alexlebens.net + siteMonitor: http://ntfy.ntfy:80 + statusStyle: dot + - Reverse Proxy: + icon: sh-traefik.webp + description: Traefik + href: https://traefik-cl01tl.alexlebens.net/dashboard/#/ + siteMonitor: https://traefik-cl01tl.alexlebens.net/dashboard/#/ + statusStyle: dot + widget: + type: traefik + url: https://traefik-cl01tl.alexlebens.net + - Image Cache: + icon: sh-harbor.webp + description: Harbor + href: https://harbor.alexlebens.net + siteMonitor: http://harbor-portal.harbor:80 + statusStyle: dot + - Hardware: + - Network Management (alexlebens.net): + icon: sh-ubiquiti-unifi.webp + description: Unifi + href: https://unifi.alexlebens.net + siteMonitor: https://unifi.alexlebens.net + statusStyle: dot + - Network Attached Storage: + icon: sh-synology-light.webp + description: Synology + href: https://synology.alexlebens.net + siteMonitor: https://synology.alexlebens.net + statusStyle: dot + widget: + type: diskstation + url: https://synology.alexlebens.net + username: {{ "{{HOMEPAGE_VAR_SYNOLOGY_USER}}" }} + password: {{ "{{HOMEPAGE_VAR_SYNOLOGY_PASSWORD}}" }} + volume: volume_2 + - TV Tuner: + icon: sh-hdhomerun.webp + description: HD Homerun + href: http://hdhr.alexlebens.net + siteMonitor: http://hdhr.alexlebens.net + statusStyle: dot + widget: + type: hdhomerun + url: http://hdhr.alexlebens.net + tuner: 0 + fields: ["channels", "hd"] + - KVM: + icon: sh-pikvm-light.webp + description: Pi KVM + href: https://pikvm.alexlebens.net + siteMonitor: https://pikvm.alexlebens.net + statusStyle: dot + - Server Plug: + icon: sh-shelly.webp + description: Shelly + href: http://it05sp.alexlebens.net + siteMonitor: http://it05sp.alexlebens.net + statusStyle: dot + - Storage: + - Cluster Storage: + icon: sh-ceph.webp + description: Ceph + href: https://ceph.alexlebens.net + siteMonitor: http://rook-ceph-mgr-dashboard.rook-ceph:7000 + statusStyle: dot + - Object Storage (NAS): + icon: sh-garage.webp + description: Garage + href: https://garage-webui.alexlebens.net + siteMonitor: http://garage-webui.garage:3909 + statusStyle: dot + - Object Storage (ps10rp): + icon: sh-garage.webp + description: Garage + href: https://garage-ui-ps10rp.boreal-beaufort.ts.net + siteMonitor: https://garage-ui-ps10rp.boreal-beaufort.ts.net + statusStyle: dot + - Database: + icon: sh-pgadmin-light.webp + description: PGAdmin + href: https://pgadmin.alexlebens.net + siteMonitor: http://pgadmin.pgadmin:80 + statusStyle: dot + - Database: + icon: sh-whodb.webp + description: WhoDB + href: https://whodb.alexlebens.net + siteMonitor: http://whodb.whodb:80 + statusStyle: dot + - Secrets: + icon: sh-hashicorp-vault.webp + description: Vault + href: https://vault.alexlebens.net + siteMonitor: http://vault.vault:8200 + statusStyle: dot + - Backups: + icon: sh-backrest-light.webp + description: Backrest + href: https://backrest.alexlebens.net + siteMonitor: http://backrest.backrest:80 + statusStyle: dot + - Content: + - qUI: + icon: https://raw.githubusercontent.com/autobrr/qui/8487c818886df9abb2b1456f43b54e0ba180a2bd/web/public/icons.svg + description: qbitorrent + href: https://qui.alexlebens.net + siteMonitor: http://qbittorrent-qui.qbittorrent:80 + statusStyle: dot + widget: + type: qbittorrent + url: http://qbittorrent.qbittorrent:8080 + enableLeechProgress: true + - Prowlarr: + icon: sh-prowlarr.webp + description: Indexers + href: https://prowlarr.alexlebens.net + siteMonitor: http://prowlarr.prowlarr:80 + statusStyle: dot + - Huntarr: + icon: https://raw.githubusercontent.com/plexguide/Huntarr.io/main/frontend/static/logo/128.png + description: Content upgrader + href: https://huntarr.alexlebens.net + siteMonitor: http://huntarr.huntarr:80 + statusStyle: dot + - Bazarr: + icon: sh-bazarr.webp + description: Subtitles + href: https://bazarr.alexlebens.net + siteMonitor: http://bazarr.bazarr:80 + statusStyle: dot + - Tdarr: + icon: sh-tdarr.webp + description: Media transcoding and health checks + href: https://tdarr.alexlebens.net + siteMonitor: http://tdarr-web.tdarr:8265 + statusStyle: dot + widget: + type: tdarr + url: http://tdarr-web.tdarr:8265 + - TV Shows: + - Sonarr: + icon: sh-sonarr.webp + description: TV Shows + href: https://sonarr.alexlebens.net + siteMonitor: http://sonarr.sonarr:80 + statusStyle: dot + widget: + type: sonarr + url: http://sonarr.sonarr:80 + key: {{ "{{HOMEPAGE_VAR_SONARR_KEY}}" }} + fields: ["wanted", "queued", "series"] + enableQueue: false + - Sonarr 4K: + icon: sh-sonarr.webp + description: TV Shows 4K + href: https://sonarr-4k.alexlebens.net + siteMonitor: http://sonarr-4k.sonarr-4k:80 + statusStyle: dot + widget: + type: sonarr + url: http://sonarr-4k.sonarr-4k:80 + key: {{ "{{HOMEPAGE_VAR_SONARR4K_KEY}}" }} + fields: ["wanted", "queued", "series"] + enableQueue: false + - Sonarr Anime: + icon: sh-sonarr.webp + description: Anime Shows + href: https://sonarr-anime.alexlebens.net + siteMonitor: http://sonarr-anime.sonarr-anime:80 + statusStyle: dot + widget: + type: sonarr + url: http://sonarr-anime.sonarr-anime:80 + key: {{ "{{HOMEPAGE_VAR_SONARRANIME_KEY}}" }} + fields: ["wanted", "queued", "series"] + enableQueue: false + - Movies: + - Radarr: + icon: sh-radarr.webp + description: Movies + href: https://radarr.alexlebens.net + siteMonitor: http://radarr.radarr:80 + statusStyle: dot + widget: + type: radarr + url: http://radarr.radarr:80 + key: {{ "{{HOMEPAGE_VAR_RADARR_KEY}}" }} + fields: ["wanted", "queued", "movies"] + enableQueue: false + - Radarr 4K: + icon: sh-radarr-4k.webp + description: Movies 4K + href: https://radarr-4k.alexlebens.net + siteMonitor: http://radarr-4k.radarr-4k:80 + statusStyle: dot + widget: + type: radarr + url: http://radarr-4k.radarr-4k:80 + key: {{ "{{HOMEPAGE_VAR_RADARR4K_KEY}}" }} + fields: ["wanted", "queued", "movies"] + enableQueue: false + - Radarr Anime: + icon: sh-radarr-anime.webp + description: Anime Movies + href: https://radarr-anime.alexlebens.net + siteMonitor: http://radarr-anime.radarr-anime:80 + statusStyle: dot + widget: + type: radarr + url: http://radarr-anime.radarr-anime:80 + key: {{ "{{HOMEPAGE_VAR_RADARRANIME_KEY}}" }} + fields: ["wanted", "queued", "movies"] + enableQueue: false + - Radarr Stand Up: + icon: sh-radarr-light-hybrid.webp + description: Stand Up + href: https://radarr-standup.alexlebens.net + siteMonitor: http://radarr-standup.radarr-standup:80 + statusStyle: dot + widget: + type: radarr + url: http://radarr-standup.radarr-standup:80 + key: {{ "{{HOMEPAGE_VAR_RADARRSTANDUP_KEY}}" }} + fields: ["wanted", "queued", "movies"] + enableQueue: false + - Music: + - Lidarr: + icon: sh-lidarr.webp + description: Music + href: https://lidarr.alexlebens.net + siteMonitor: http://lidarr.lidarr:80 + statusStyle: dot + widget: + type: lidarr + url: http://lidarr.lidarr:80 + key: {{ "{{HOMEPAGE_VAR_LIDARR_KEY}}" }} + fields: ["wanted", "queued", "artists"] + - LidaTube: + icon: sh-lidatube.webp + description: Searches for Music + href: https://lidatube.alexlebens.net + siteMonitor: http://lidatube.lidatube:80 + statusStyle: dot + - Soulseek: + icon: sh-slskd.webp + description: slskd + href: https://slskd.alexlebens.net + siteMonitor: http://slskd.slskd:5030 + statusStyle: dot + - Books: + - Ephemera: + icon: sh-ephemera.webp + description: Books + href: https://ephemera.alexlebens.net + siteMonitor: http://ephemera.ephemera:80 + statusStyle: dot + - Listenarr: + icon: sh-audiobookrequest.webp + description: Audiobooks + href: https://listenarr.alexlebens.net + siteMonitor: http://listenarr.listenarr:80 + statusStyle: dot + - Other Homes: + - Dev: + icon: sh-homepage.webp + description: Public Homepage + href: https://home.alexlebens.dev + siteMonitor: https://home.alexlebens.dev + statusStyle: dot + - Lebens Home: + icon: sh-homepage.webp + description: Lebens Homepage + href: https://home-ps10rp.boreal-beaufort.ts.net + siteMonitor: https://home-ps10rp.boreal-beaufort.ts.net + statusStyle: dot + bookmarks.yaml: | + - External Services: + - Github: + - abbr: GH + href: https://github.com/alexlebens + - Digital Ocean: + - abbr: DO + href: https://www.digitalocean.com/ + - AWS: + - abbr: AW + href: https://aws.amazon.com/console/ + - Cloudflare: + - abbr: CF + href: https://dash.cloudflare.com/b76e303258b84076ee01fd0f515c0768 + - Tailscale: + - abbr: TS + href: https://login.tailscale.com/admin/machines + - ProtonVPN: + - abbr: PV + href: https://account.protonvpn.com/ + - Unifi: + - abbr: UF + href: https://unifi.ui.com/ + - Pushover: + - abbr: PO + href: https://pushover.net + - ReCaptcha: + - abbr: RC + href: https://www.google.com/recaptcha/admin/site/698983587 + - Trackers: + - Torrentleech: + - abbr: TL + href: https://www.torrentleech.org + - Avistaz: + - abbr: AV + href: https://avistaz.to + - Cinemaz: + - abbr: CM + href: https://cinemaz.to + - Cathode Ray Tube: + - abbr: CRT + href: https://www.cathode-ray.tube + - Alpha Ratio: + - abbr: AL + href: https://alpharatio.cc/ + - MV Group: + - abbr: MV + href: https://forums.mvgroup.org + service: + http: + controller: main + ports: + http: + port: 80 + targetPort: 3000 + protocol: HTTP + persistence: + config: + enabled: true + type: configMap + name: homepage + advancedMounts: + main: + main: + - path: /app/config/bookmarks.yaml + readOnly: true + mountPropagation: None + subPath: bookmarks.yaml + - path: /app/config/docker.yaml + readOnly: true + mountPropagation: None + subPath: docker.yaml + - path: /app/config/kubernetes.yaml + readOnly: true + mountPropagation: None + subPath: kubernetes.yaml + - path: /app/config/services.yaml + readOnly: true + mountPropagation: None + subPath: services.yaml + - path: /app/config/settings.yaml + readOnly: true + mountPropagation: None + subPath: settings.yaml + - path: /app/config/widgets.yaml + readOnly: true + mountPropagation: None + subPath: widgets.yaml diff --git a/clusters/cl01tl/helm/huntarr/Chart.yaml b/clusters/cl01tl/helm/huntarr/Chart.yaml new file mode 100644 index 000000000..f7a5082a7 --- /dev/null +++ b/clusters/cl01tl/helm/huntarr/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: huntarr +version: 1.0.0 +description: Huntarr +keywords: + - huntarr + - servarr +home: https://wiki.alexlebens.dev/s/831ca16e-d308-4d7b-9213-f841834c1181 +sources: + - https://github.com/plexguide/Huntarr.io + - https://hub.docker.com/r/huntarr/huntarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: huntarr + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/huntarr.png +appVersion: 7.0.0 diff --git a/clusters/cl01tl/helm/huntarr/templates/http-route.yaml b/clusters/cl01tl/helm/huntarr/templates/http-route.yaml new file mode 100644 index 000000000..d2d2df1eb --- /dev/null +++ b/clusters/cl01tl/helm/huntarr/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-huntarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-huntarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - huntarr.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: huntarr + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/huntarr/values.yaml b/clusters/cl01tl/helm/huntarr/values.yaml new file mode 100644 index 000000000..b55d12871 --- /dev/null +++ b/clusters/cl01tl/helm/huntarr/values.yaml @@ -0,0 +1,39 @@ +huntarr: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/plexguide/huntarr + tag: 8.2.10 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + resources: + requests: + cpu: 100m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 9705 + protocol: HTTP + persistence: + config: + forceRename: huntarr-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + advancedMounts: + main: + main: + - path: /config + readOnly: false diff --git a/clusters/cl01tl/helm/immich/Chart.yaml b/clusters/cl01tl/helm/immich/Chart.yaml new file mode 100644 index 000000000..cf3a47ccb --- /dev/null +++ b/clusters/cl01tl/helm/immich/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +name: immich +version: 1.0.0 +description: Immich +keywords: + - immich + - photos +home: https://wiki.alexlebens.dev/s/9377ae08-2041-4b6d-bc2b-61a4f5e8faae +sources: + - https://github.com/immich-app/immich + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: immich + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/immich.png +appVersion: v2.0.1 diff --git a/clusters/cl01tl/helm/immich/templates/external-secrets.yaml b/clusters/cl01tl/helm/immich/templates/external-secrets.yaml new file mode 100644 index 000000000..e400b550b --- /dev/null +++ b/clusters/cl01tl/helm/immich/templates/external-secrets.yaml @@ -0,0 +1,88 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: immich-config-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: immich-config-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: immich.json + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/immich/config + metadataPolicy: None + property: immich.json + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: immich-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: immich-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: immich-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: immich-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/immich/templates/http-route.yaml b/clusters/cl01tl/helm/immich/templates/http-route.yaml new file mode 100644 index 000000000..342481ebb --- /dev/null +++ b/clusters/cl01tl/helm/immich/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-immich + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-immich + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - immich.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: immich-main + port: 2283 + weight: 100 diff --git a/clusters/cl01tl/helm/immich/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/immich/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..a830f81c3 --- /dev/null +++ b/clusters/cl01tl/helm/immich/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: immich-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: immich-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: immich-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/immich/templates/persistent-volume.yaml b/clusters/cl01tl/helm/immich/templates/persistent-volume.yaml new file mode 100644 index 000000000..489121a70 --- /dev/null +++ b/clusters/cl01tl/helm/immich/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: immich-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: immich-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/Immich + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/immich/templates/redis-replication.yaml b/clusters/cl01tl/helm/immich/templates/redis-replication.yaml new file mode 100644 index 000000000..c72a1a2c9 --- /dev/null +++ b/clusters/cl01tl/helm/immich/templates/redis-replication.yaml @@ -0,0 +1,32 @@ +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: redis-replication-immich + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-immich + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + clusterSize: 3 + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + kubernetesConfig: + image: quay.io/opstree/redis:v8.0.3 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 128Mi + storage: + volumeClaimTemplate: + spec: + storageClassName: ceph-block + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + redisExporter: + enabled: true + image: quay.io/opstree/redis-exporter:v1.48.0 diff --git a/clusters/cl01tl/helm/immich/templates/service-monitor.yaml b/clusters/cl01tl/helm/immich/templates/service-monitor.yaml new file mode 100644 index 000000000..7eed78e58 --- /dev/null +++ b/clusters/cl01tl/helm/immich/templates/service-monitor.yaml @@ -0,0 +1,44 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: immich + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: immich + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: immich + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: metrics-api + interval: 3m + scrapeTimeout: 1m + path: /metrics + - port: metrics-ms + interval: 3m + scrapeTimeout: 1m + path: /metrics + +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: redis-replication-immich + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-immich + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + redis-operator: "true" + env: production +spec: + selector: + matchLabels: + redis_setup_type: replication + endpoints: + - port: redis-exporter + interval: 30s + scrapeTimeout: 10s diff --git a/clusters/cl01tl/helm/immich/values.yaml b/clusters/cl01tl/helm/immich/values.yaml new file mode 100644 index 000000000..ed7d330a9 --- /dev/null +++ b/clusters/cl01tl/helm/immich/values.yaml @@ -0,0 +1,260 @@ +immich: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/immich-app/immich-server + tag: v2.3.1 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: IMMICH_TELEMETRY_INCLUDE + value: all + - name: IMMICH_CONFIG_FILE + value: /config/immich.json + - name: IMMICH_MACHINE_LEARNING_URL + value: http://immich-machine-learning.immich:3003 + - name: REDIS_HOSTNAME + value: redis-replication-immich-master + - name: DB_VECTOR_EXTENSION + value: vectorchord + - name: DB_HOSTNAME + valueFrom: + secretKeyRef: + name: immich-postgresql-17-cluster-app + key: host + - name: DB_DATABASE_NAME + valueFrom: + secretKeyRef: + name: immich-postgresql-17-cluster-app + key: dbname + - name: DB_PORT + valueFrom: + secretKeyRef: + name: immich-postgresql-17-cluster-app + key: port + - name: DB_USERNAME + valueFrom: + secretKeyRef: + name: immich-postgresql-17-cluster-app + key: user + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: immich-postgresql-17-cluster-app + key: password + probes: + liveness: + enabled: true + custom: true + spec: + httpGet: + path: /api/server/ping + port: 2283 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + readiness: + enabled: true + custom: true + spec: + httpGet: + path: /api/server/ping + port: 2283 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + startup: + enabled: true + custom: true + spec: + httpGet: + path: /api/server/ping + port: 2283 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 30 + resources: + limits: + gpu.intel.com/i915: 1 + requests: + gpu.intel.com/i915: 1 + cpu: 10m + memory: 512Mi + machine-learning: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/immich-app/immich-machine-learning + tag: v2.3.1 + pullPolicy: IfNotPresent + env: + - name: TRANSFORMERS_CACHE + value: /cache + probes: + liveness: + enabled: true + custom: true + spec: + httpGet: + path: /ping + port: 3003 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + readiness: + enabled: true + custom: true + spec: + httpGet: + path: /ping + port: 3003 + initialDelaySeconds: 0 + periodSeconds: 10 + timeoutSeconds: 1 + failureThreshold: 3 + startup: + enabled: false + resources: + limits: + gpu.intel.com/i915: 1 + requests: + gpu.intel.com/i915: 1 + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 2283 + targetPort: 2283 + protocol: TCP + metrics-api: + port: 8081 + targetPort: 8081 + protocol: TCP + metrics-ms: + port: 8082 + targetPort: 8082 + protocol: TCP + machine-learning: + controller: machine-learning + ports: + http: + port: 3003 + targetPort: 3003 + protocol: TCP + persistence: + config: + enabled: true + type: secret + name: immich-config-secret + advancedMounts: + main: + main: + - path: /config/immich.json + readOnly: true + mountPropagation: None + subPath: immich.json + cache: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 10Gi + retain: true + advancedMounts: + machine-learning: + main: + - path: /cache + readOnly: false + media: + existingClaim: immich-nfs-storage + advancedMounts: + main: + main: + - path: /usr/src/app/upload + readOnly: false +postgres-17-cluster: + mode: recovery + cluster: + image: + repository: ghcr.io/tensorchord/cloudnative-vectorchord + tag: 17.5-0.4.3 + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + postgresql: + parameters: + shared_buffers: 256MB + shared_preload_libraries: + - "vchord.so" + initdb: + postInitSQL: + - 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; + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/immich/immich-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: immich-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/immich/immich-postgresql-17-cluster + index: 2 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/immich/immich-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: immich-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/immich/immich-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: immich-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 4 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/jellyfin/Chart.yaml b/clusters/cl01tl/helm/jellyfin/Chart.yaml new file mode 100644 index 000000000..7b025e3a4 --- /dev/null +++ b/clusters/cl01tl/helm/jellyfin/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +name: jellyfin +version: 1.0.0 +description: Jellyfin +keywords: + - jellyfin + - media + - movies + - tv shows + - books + - music +home: https://wiki.alexlebens.dev/s/a58be5b0-7935-458a-b990-b45223e39d68 +sources: + - https://github.com/jellyfin/jellyfin + - https://hub.docker.com/r/jellyfin/jellyfin + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: jellyfin + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/jellyfin.png +appVersion: 10.10.7 diff --git a/clusters/cl01tl/helm/jellyfin/templates/external-secret.yaml b/clusters/cl01tl/helm/jellyfin/templates/external-secret.yaml new file mode 100644 index 000000000..1a076a796 --- /dev/null +++ b/clusters/cl01tl/helm/jellyfin/templates/external-secret.yaml @@ -0,0 +1,55 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: jellyfin-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellyfin-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/jellyfin/jellyfin-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/jellyfin/templates/http-route.yaml b/clusters/cl01tl/helm/jellyfin/templates/http-route.yaml new file mode 100644 index 000000000..c07e8820f --- /dev/null +++ b/clusters/cl01tl/helm/jellyfin/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-jellyfin + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-jellyfin + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - jellyfin.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: jellyfin + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/jellyfin/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/jellyfin/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..fdb6a5ce7 --- /dev/null +++ b/clusters/cl01tl/helm/jellyfin/templates/persistent-volume-claim.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: jellyfin-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellyfin-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: jellyfin-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: jellyfin-youtube-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellyfin-youtube-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: jellyfin-youtube-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadOnlyMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/jellyfin/templates/persistent-volume.yaml b/clusters/cl01tl/helm/jellyfin/templates/persistent-volume.yaml new file mode 100644 index 000000000..af39701d4 --- /dev/null +++ b/clusters/cl01tl/helm/jellyfin/templates/persistent-volume.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: jellyfin-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellyfin-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac + +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: jellyfin-youtube-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellyfin-youtube-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadOnlyMany + nfs: + path: /volume2/Storage/YouTube + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/jellyfin/templates/replication-source.yaml b/clusters/cl01tl/helm/jellyfin/templates/replication-source.yaml new file mode 100644 index 000000000..4f6597805 --- /dev/null +++ b/clusters/cl01tl/helm/jellyfin/templates/replication-source.yaml @@ -0,0 +1,26 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: jellyfin-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellyfin-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: jellyfin-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: jellyfin-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot + cacheCapacity: 10Gi diff --git a/clusters/cl01tl/helm/jellyfin/values.yaml b/clusters/cl01tl/helm/jellyfin/values.yaml new file mode 100644 index 000000000..e8e8fa78a --- /dev/null +++ b/clusters/cl01tl/helm/jellyfin/values.yaml @@ -0,0 +1,68 @@ +jellyfin: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/jellyfin/jellyfin + tag: 10.11.3 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: JELLYFIN_hostwebclient + value: true + - name: JELLYFIN_PublishedServerUrl + value: https://jellyfin.alexlebens.net/ + resources: + limits: + gpu.intel.com/i915: 1 + requests: + gpu.intel.com/i915: 1 + cpu: 1 + memory: 2Gi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8096 + protocol: HTTP + persistence: + config: + forceRename: jellyfin-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 100Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + cache: + type: emptyDir + advancedMounts: + main: + main: + - path: /cache + readOnly: false + media: + existingClaim: jellyfin-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false + youtube: + existingClaim: jellyfin-youtube-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/youtube + readOnly: true diff --git a/clusters/cl01tl/helm/jellystat/Chart.yaml b/clusters/cl01tl/helm/jellystat/Chart.yaml new file mode 100644 index 000000000..da910c7c8 --- /dev/null +++ b/clusters/cl01tl/helm/jellystat/Chart.yaml @@ -0,0 +1,27 @@ +apiVersion: v2 +name: jellystat +version: 1.0.0 +description: Jellystat +keywords: + - jellystat + - jellyfin +home: https://wiki.alexlebens.dev/s/d3fd2bf1-d2ab-4e94-a127-ee35f2d90142 +sources: + - https://github.com/CyferShepard/Jellystat + - https://github.com/cloudnative-pg/cloudnative-pg + - https://hub.docker.com/r/cyfershepard/jellystat + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: jellystat + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/jellystat.png +appVersion: 1.1.6 diff --git a/clusters/cl01tl/helm/jellystat/templates/external-secret.yaml b/clusters/cl01tl/helm/jellystat/templates/external-secret.yaml new file mode 100644 index 000000000..71f3821bb --- /dev/null +++ b/clusters/cl01tl/helm/jellystat/templates/external-secret.yaml @@ -0,0 +1,159 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: jellystat-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellystat-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: secret-key + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/jellystat/auth + metadataPolicy: None + property: secret-key + - secretKey: user + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/jellystat/auth + metadataPolicy: None + property: user + - secretKey: password + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/jellystat/auth + metadataPolicy: None + property: password + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: jellystat-data-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellystat-data-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/jellystat/jellystat-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: jellystat-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellystat-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: jellystat-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellystat-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/jellystat/templates/http-route.yaml b/clusters/cl01tl/helm/jellystat/templates/http-route.yaml new file mode 100644 index 000000000..c1f9b1b4d --- /dev/null +++ b/clusters/cl01tl/helm/jellystat/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-jellystat + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-jellystat + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - jellystat.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: jellystat + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/jellystat/templates/replication-source.yaml b/clusters/cl01tl/helm/jellystat/templates/replication-source.yaml new file mode 100644 index 000000000..5cee9ea73 --- /dev/null +++ b/clusters/cl01tl/helm/jellystat/templates/replication-source.yaml @@ -0,0 +1,25 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: jellystat-data-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: jellystat-data-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: jellystat-data + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: jellystat-data-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/jellystat/values.yaml b/clusters/cl01tl/helm/jellystat/values.yaml new file mode 100644 index 000000000..e0cf55d9c --- /dev/null +++ b/clusters/cl01tl/helm/jellystat/values.yaml @@ -0,0 +1,136 @@ +jellystat: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: cyfershepard/jellystat + tag: 1.1.6 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: jellystat-secret + key: secret-key + - name: JS_USER + valueFrom: + secretKeyRef: + name: jellystat-secret + key: user + - name: JS_PASSWORD + valueFrom: + secretKeyRef: + name: jellystat-secret + key: password + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: jellystat-postgresql-17-cluster-app + key: username + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: jellystat-postgresql-17-cluster-app + key: password + - name: POSTGRES_DB + valueFrom: + secretKeyRef: + name: jellystat-postgresql-17-cluster-app + key: dbname + - name: POSTGRES_IP + valueFrom: + secretKeyRef: + name: jellystat-postgresql-17-cluster-app + key: host + - name: POSTGRES_PORT + valueFrom: + secretKeyRef: + name: jellystat-postgresql-17-cluster-app + key: port + resources: + requests: + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 3000 + protocol: HTTP + persistence: + data: + forceRename: jellystat-data + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /app/backend/backup-data + readOnly: false +postgres-17-cluster: + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/jellystat/jellystat-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: jellystat-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/jellystat/jellystat-postgresql-17-cluster + index: 1 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/jellystat/jellystat-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: jellystat-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/jellystat/jellystat-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: jellystat-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 6 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/karakeep/Chart.yaml b/clusters/cl01tl/helm/karakeep/Chart.yaml new file mode 100644 index 000000000..d4fdb4501 --- /dev/null +++ b/clusters/cl01tl/helm/karakeep/Chart.yaml @@ -0,0 +1,32 @@ +apiVersion: v2 +name: karakeep +version: 1.0.0 +description: Karakeep +keywords: + - karakeep + - bookmarks +home: https://wiki.alexlebens.dev/s/f8177591-8253-4e21-82d5-a556f0aeafad +sources: + - https://github.com/karakeep-app/karakeep + - https://github.com/cloudflare/cloudflared + - https://github.com/meilisearch/meilisearch + - https://github.com/karakeep-app/karakeep/pkgs/container/karakeep + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://github.com/meilisearch/meilisearch-kubernetes/tree/main/charts/meilisearch + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: karakeep + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: meilisearch + version: 0.17.1 + repository: https://meilisearch.github.io/meilisearch-kubernetes + - name: cloudflared + alias: cloudflared + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/webp/karakeep.webp +appVersion: 0.26.0 diff --git a/clusters/cl01tl/helm/karakeep/templates/external-secret.yaml b/clusters/cl01tl/helm/karakeep/templates/external-secret.yaml new file mode 100644 index 000000000..5af4eb3fe --- /dev/null +++ b/clusters/cl01tl/helm/karakeep/templates/external-secret.yaml @@ -0,0 +1,161 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: karakeep-key-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: karakeep-key-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: key + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/karakeep/key + metadataPolicy: None + property: key + - secretKey: prometheus-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/karakeep/key + metadataPolicy: None + property: prometheus-token + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: karakeep-oidc-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: karakeep-oidc-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: AUTHENTIK_CLIENT_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/karakeep + metadataPolicy: None + property: client + - secretKey: AUTHENTIK_CLIENT_SECRET + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/karakeep + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: karakeep-meilisearch-master-key-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: karakeep-meilisearch-master-key-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: MEILI_MASTER_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/karakeep/meilisearch + metadataPolicy: None + property: MEILI_MASTER_KEY + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: karakeep-cloudflared-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: karakeep-cloudflared-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/karakeep + metadataPolicy: None + property: token + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: karakeep-data-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: karakeep-data-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/karakeep/karakeep-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/karakeep/templates/object-bucket-claim.yaml b/clusters/cl01tl/helm/karakeep/templates/object-bucket-claim.yaml new file mode 100644 index 000000000..49c161a5b --- /dev/null +++ b/clusters/cl01tl/helm/karakeep/templates/object-bucket-claim.yaml @@ -0,0 +1,11 @@ +apiVersion: objectbucket.io/v1alpha1 +kind: ObjectBucketClaim +metadata: + name: ceph-bucket-karakeep + labels: + app.kubernetes.io/name: ceph-bucket-karakeep + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + generateBucketName: bucket-karakeep + storageClassName: ceph-bucket diff --git a/clusters/cl01tl/helm/karakeep/templates/replication-source.yaml b/clusters/cl01tl/helm/karakeep/templates/replication-source.yaml new file mode 100644 index 000000000..738dff236 --- /dev/null +++ b/clusters/cl01tl/helm/karakeep/templates/replication-source.yaml @@ -0,0 +1,25 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: karakeep-data-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: karakeep-data-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: karakeep-data + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: karakeep-data-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/karakeep/templates/service-monitor.yaml b/clusters/cl01tl/helm/karakeep/templates/service-monitor.yaml new file mode 100644 index 000000000..d5a9f353c --- /dev/null +++ b/clusters/cl01tl/helm/karakeep/templates/service-monitor.yaml @@ -0,0 +1,23 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: karakeep + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: karakeep + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + endpoints: + - port: http + interval: 30s + scrapeTimeout: 15s + path: /api/metrics + authorization: + credentials: + key: prometheus-token + name: karakeep-key-secret + selector: + matchLabels: + app.kubernetes.io/name: karakeep + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/clusters/cl01tl/helm/karakeep/values.yaml b/clusters/cl01tl/helm/karakeep/values.yaml new file mode 100644 index 000000000..e99929310 --- /dev/null +++ b/clusters/cl01tl/helm/karakeep/values.yaml @@ -0,0 +1,155 @@ +karakeep: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/karakeep-app/karakeep + tag: 0.28.0 + pullPolicy: IfNotPresent + env: + - name: DATA_DIR + value: /data + - name: DB_WAL_MODE + value: true + - name: NEXTAUTH_URL + value: https://karakeep.alexlebens.dev/ + - name: NEXTAUTH_SECRET + valueFrom: + secretKeyRef: + name: karakeep-key-secret + key: key + - name: PROMETHEUS_AUTH_TOKEN + valueFrom: + secretKeyRef: + name: karakeep-key-secret + key: prometheus-token + - name: ASSET_STORE_S3_ENDPOINT + value: http://rook-ceph-rgw-ceph-objectstore.rook-ceph.svc:80 + - name: ASSET_STORE_S3_REGION + value: us-east-1 + - name: ASSET_STORE_S3_BUCKET + valueFrom: + configMapKeyRef: + name: ceph-bucket-karakeep + key: BUCKET_NAME + - name: ASSET_STORE_S3_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: ceph-bucket-karakeep + key: AWS_ACCESS_KEY_ID + - name: ASSET_STORE_S3_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: ceph-bucket-karakeep + key: AWS_SECRET_ACCESS_KEY + - name: ASSET_STORE_S3_FORCE_PATH_STYLE + value: true + - name: MEILI_ADDR + value: http://karakeep-meilisearch.karakeep:7700 + - name: MEILI_MASTER_KEY + valueFrom: + secretKeyRef: + name: karakeep-meilisearch-master-key-secret + key: MEILI_MASTER_KEY + - name: BROWSER_WEB_URL + value: http://karakeep.karakeep:9222 + - name: DISABLE_SIGNUPS + value: false + - name: OAUTH_PROVIDER_NAME + value: "Authentik" + - name: OAUTH_WELLKNOWN_URL + value: https://auth.alexlebens.dev/application/o/karakeep/.well-known/openid-configuration + - name: OAUTH_SCOPE + value: "openid email profile" + - name: OAUTH_CLIENT_ID + valueFrom: + secretKeyRef: + name: karakeep-oidc-secret + key: AUTHENTIK_CLIENT_ID + - name: OAUTH_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: karakeep-oidc-secret + key: AUTHENTIK_CLIENT_SECRET + - name: OLLAMA_BASE_URL + value: http://ollama-server-3.ollama:11434 + - name: OLLAMA_KEEP_ALIVE + value: 5m + - name: INFERENCE_TEXT_MODEL + value: gemma3:4b + - name: INFERENCE_IMAGE_MODEL + value: granite3.2-vision:2b + - name: EMBEDDING_TEXT_MODEL + value: mxbai-embed-large + - name: INFERENCE_JOB_TIMEOUT_SEC + value: 720 + resources: + requests: + cpu: 10m + memory: 256Mi + chrome: + image: + repository: gcr.io/zenika-hub/alpine-chrome + tag: 124 + pullPolicy: IfNotPresent + args: + - --no-sandbox + - --disable-gpu + - --disable-dev-shm-usage + - --remote-debugging-address=0.0.0.0 + - --remote-debugging-port=9222 + - --hide-scrollbars + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 3000 + targetPort: 3000 + protocol: HTTP + chrome: + port: 9222 + targetPort: 9222 + protocol: HTTP + persistence: + data: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 10Gi + retain: true + advancedMounts: + main: + main: + - path: /data + readOnly: false +meilisearch: + environment: + MEILI_NO_ANALYTICS: true + MEILI_ENV: production + MEILI_EXPERIMENTAL_DUMPLESS_UPGRADE: true + auth: + existingMasterKeySecret: karakeep-meilisearch-master-key-secret + service: + type: ClusterIP + port: 7700 + persistence: + enabled: true + storageClass: ceph-block + size: 10Gi + resources: + requests: + cpu: 10m + memory: 128Mi + serviceMonitor: + enabled: true +cloudflared: + existingSecretName: karakeep-cloudflared-secret diff --git a/clusters/cl01tl/helm/kiwix/Chart.yaml b/clusters/cl01tl/helm/kiwix/Chart.yaml new file mode 100644 index 000000000..26d5be4ad --- /dev/null +++ b/clusters/cl01tl/helm/kiwix/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: kiwix +version: 1.0.0 +description: Kiwix +keywords: + - kiwix + - wikipedia +home: https://wiki.alexlebens.dev/s/16eaaf92-3607-421f-bc66-cb3c39eeaea0 +sources: + - https://github.com/kiwix + - https://github.com/kiwix/kiwix-tools/pkgs/container/kiwix-serve + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: kiwix + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/kiwix-dark.png +appVersion: 3.7.0 diff --git a/clusters/cl01tl/helm/kiwix/templates/http-route.yaml b/clusters/cl01tl/helm/kiwix/templates/http-route.yaml new file mode 100644 index 000000000..fe180dc47 --- /dev/null +++ b/clusters/cl01tl/helm/kiwix/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-kiwix + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-kiwix + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - kiwix.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: kiwix + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/kiwix/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/kiwix/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..1423bcd69 --- /dev/null +++ b/clusters/cl01tl/helm/kiwix/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: kiwix-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: kiwix-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: kiwix-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/kiwix/templates/persistent-volume.yaml b/clusters/cl01tl/helm/kiwix/templates/persistent-volume.yaml new file mode 100644 index 000000000..5185019e7 --- /dev/null +++ b/clusters/cl01tl/helm/kiwix/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: kiwix-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: kiwix-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/Kiwix + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/kiwix/values.yaml b/clusters/cl01tl/helm/kiwix/values.yaml new file mode 100644 index 000000000..611733a0b --- /dev/null +++ b/clusters/cl01tl/helm/kiwix/values.yaml @@ -0,0 +1,38 @@ +kiwix: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/kiwix/kiwix-serve + tag: 3.8.0 + pullPolicy: IfNotPresent + args: + - '*.zim' + env: + - name: PORT + value: 8080 + resources: + requests: + cpu: 50m + memory: 512Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8080 + protocol: HTTP + persistence: + media: + existingClaim: kiwix-nfs-storage + advancedMounts: + main: + main: + - path: /data + readOnly: true diff --git a/clusters/cl01tl/helm/libation/Chart.yaml b/clusters/cl01tl/helm/libation/Chart.yaml new file mode 100644 index 000000000..13d95f2d4 --- /dev/null +++ b/clusters/cl01tl/helm/libation/Chart.yaml @@ -0,0 +1,22 @@ +apiVersion: v2 +name: libation +version: 1.0.0 +description: Libation +keywords: + - libation + - audiobooks + - audible +home: https://wiki.alexlebens.dev/s/63beac50-a63f-45fe-b8e5-e1691dd5e9b0 +sources: + - https://github.com/rmcrackan/Libation + - https://hub.docker.com/r/rmcrackan/libation + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: libation + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/libation.png +appVersion: 12.4.3 diff --git a/clusters/cl01tl/helm/libation/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/libation/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..bcae70a6c --- /dev/null +++ b/clusters/cl01tl/helm/libation/templates/persistent-volume-claim.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: libation-config + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: libation-config + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + storageClassName: nfs-client + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + volumeMode: Filesystem + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: libation-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: libation-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: libation-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/libation/templates/persistent-volume.yaml b/clusters/cl01tl/helm/libation/templates/persistent-volume.yaml new file mode 100644 index 000000000..123b69068 --- /dev/null +++ b/clusters/cl01tl/helm/libation/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: libation-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: libation-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/Audiobooks/ + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/libation/values.yaml b/clusters/cl01tl/helm/libation/values.yaml new file mode 100644 index 000000000..5e6dc8be9 --- /dev/null +++ b/clusters/cl01tl/helm/libation/values.yaml @@ -0,0 +1,44 @@ +libation: + controllers: + main: + type: cronjob + cronjob: + suspend: false + concurrencyPolicy: Forbid + timeZone: US/Central + schedule: "30 4 * * *" + startingDeadlineSeconds: 90 + successfulJobsHistory: 3 + failedJobsHistory: 3 + backoffLimit: 3 + parallelism: 1 + containers: + main: + image: + repository: rmcrackan/libation + tag: 12.7.4 + pullPolicy: IfNotPresent + env: + - name: SLEEP_TIME + value: "-1" + - name: LIBATION_BOOKS_DIR + value: /data + resources: + requests: + cpu: 10m + memory: 128Mi + persistence: + config: + existingClaim: libation-config + advancedMounts: + main: + main: + - path: /config + readOnly: false + data: + existingClaim: libation-nfs-storage + advancedMounts: + main: + main: + - path: /data + readOnly: false diff --git a/clusters/cl01tl/helm/lidarr/Chart.yaml b/clusters/cl01tl/helm/lidarr/Chart.yaml new file mode 100644 index 000000000..0eaeaa6c0 --- /dev/null +++ b/clusters/cl01tl/helm/lidarr/Chart.yaml @@ -0,0 +1,30 @@ +apiVersion: v2 +name: lidarr +version: 1.0.0 +description: Lidarr +keywords: + - lidarr + - servarr + - music + - metrics +home: https://wiki.alexlebens.dev/s/f7c4e892-aa3b-435f-b220-317dc53137ac +sources: + - https://github.com/Lidarr/Lidarr + - https://github.com/linuxserver/docker-lidarr + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/onedr0p/exportarr/pkgs/container/exportarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: lidarr + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/lidarr.png +appVersion: 2.13.3 diff --git a/clusters/cl01tl/helm/lidarr/templates/external-secret.yaml b/clusters/cl01tl/helm/lidarr/templates/external-secret.yaml new file mode 100644 index 000000000..28bf735e3 --- /dev/null +++ b/clusters/cl01tl/helm/lidarr/templates/external-secret.yaml @@ -0,0 +1,122 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: lidarr-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidarr-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/lidarr2/lidarr2-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: lidarr-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidarr-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: lidarr-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidarr-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/lidarr/templates/http-route.yaml b/clusters/cl01tl/helm/lidarr/templates/http-route.yaml new file mode 100644 index 000000000..506985b16 --- /dev/null +++ b/clusters/cl01tl/helm/lidarr/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-lidarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-lidarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - lidarr.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: lidarr + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/lidarr/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/lidarr/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..c1d21f84e --- /dev/null +++ b/clusters/cl01tl/helm/lidarr/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: lidarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: lidarr-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/lidarr/templates/persistent-volume.yaml b/clusters/cl01tl/helm/lidarr/templates/persistent-volume.yaml new file mode 100644 index 000000000..181d788f2 --- /dev/null +++ b/clusters/cl01tl/helm/lidarr/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: lidarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/lidarr/templates/prometheus-rule.yaml b/clusters/cl01tl/helm/lidarr/templates/prometheus-rule.yaml new file mode 100644 index 000000000..80b14f110 --- /dev/null +++ b/clusters/cl01tl/helm/lidarr/templates/prometheus-rule.yaml @@ -0,0 +1,32 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: lidarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + groups: + - name: lidarr + rules: + - alert: ExportarrAbsent + annotations: + description: Lidarr Exportarr has disappeared from Prometheus + service discovery. + summary: Exportarr is down. + expr: | + absent(up{job=~".*lidarr.*"} == 1) + for: 5m + labels: + severity: critical + - alert: LidarrDown + annotations: + description: Lidarr service is down. + summary: Lidarr is down. + expr: | + lidarr_system_status{job=~".*lidarr.*"} == 0 + for: 5m + labels: + severity: critical diff --git a/clusters/cl01tl/helm/lidarr/templates/replication-source.yaml b/clusters/cl01tl/helm/lidarr/templates/replication-source.yaml new file mode 100644 index 000000000..ef6c456fc --- /dev/null +++ b/clusters/cl01tl/helm/lidarr/templates/replication-source.yaml @@ -0,0 +1,28 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: lidarr-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidarr-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: lidarr-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: lidarr-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/lidarr/templates/service-monitor.yaml b/clusters/cl01tl/helm/lidarr/templates/service-monitor.yaml new file mode 100644 index 000000000..9011279c3 --- /dev/null +++ b/clusters/cl01tl/helm/lidarr/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: lidarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: lidarr + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: metrics + interval: 3m + scrapeTimeout: 1m + path: /metrics diff --git a/clusters/cl01tl/helm/lidarr/values.yaml b/clusters/cl01tl/helm/lidarr/values.yaml new file mode 100644 index 000000000..e66609fd5 --- /dev/null +++ b/clusters/cl01tl/helm/lidarr/values.yaml @@ -0,0 +1,151 @@ +lidarr: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: ghcr.io/linuxserver/lidarr + tag: 2.14.5@sha256:5e1235d00b5d1c1f60ca0d472e554a6611aef41aa7b5b6d88260214bf4809af0 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + resources: + requests: + cpu: 100m + memory: 256Mi + metrics: + image: + repository: ghcr.io/onedr0p/exportarr + tag: v2.3.0 + pullPolicy: IfNotPresent + args: ["lidarr"] + env: + - name: URL + value: http://localhost + - name: CONFIG + value: /config/config.xml + - name: PORT + value: 9792 + - name: ENABLE_ADDITIONAL_METRICS + value: false + - name: ENABLE_UNKNOWN_QUEUE_ITEMS + value: false + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8686 + protocol: HTTP + metrics: + port: 9792 + targetPort: 9792 + protocol: TCP + persistence: + config: + forceRename: lidarr-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 10Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + metrics: + - path: /config + readOnly: true + media: + existingClaim: lidarr-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false +postgres-17-cluster: + nameOverride: lidarr2-postgresql-17 + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + resources: + requests: + memory: 1Gi + cpu: 200m + initdb: + postInitSQL: + - CREATE DATABASE "lidarr-main" OWNER "app"; + - CREATE DATABASE "lidarr-log" OWNER "app"; + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/lidarr/lidarr2-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: lidarr-postgresql-17-cluster-backup-secret + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/lidarr2/lidarr2-postgresql-17-cluster + index: 1 + endpointCredentials: lidarr-postgresql-17-cluster-backup-secret + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/lidarr/lidarr2-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: lidarr-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/lidarr/lidarr2-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: lidarr-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 8 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/lidatube/Chart.yaml b/clusters/cl01tl/helm/lidatube/Chart.yaml new file mode 100644 index 000000000..e55aae496 --- /dev/null +++ b/clusters/cl01tl/helm/lidatube/Chart.yaml @@ -0,0 +1,22 @@ +apiVersion: v2 +name: lidatube +version: 1.0.0 +description: LidaTube +keywords: + - lidatube + - music + - yt-dlp +home: https://wiki.alexlebens.dev/s/10d95030-85be-4ced-a8d7-b4aaeca9bee6 +sources: + - https://github.com/TheWicklowWolf/LidaTube + - https://registry.hub.docker.com/r/thewicklowwolf/lidatube + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: lidatube + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/lidatube.png +appVersion: 0.2.22 diff --git a/clusters/cl01tl/helm/lidatube/templates/external-secret.yaml b/clusters/cl01tl/helm/lidatube/templates/external-secret.yaml new file mode 100644 index 000000000..83be273f2 --- /dev/null +++ b/clusters/cl01tl/helm/lidatube/templates/external-secret.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: lidatube-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidatube-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: lidarr_api_key + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/lidarr2/key + metadataPolicy: None + property: key diff --git a/clusters/cl01tl/helm/lidatube/templates/http-route.yaml b/clusters/cl01tl/helm/lidatube/templates/http-route.yaml new file mode 100644 index 000000000..508d72b7b --- /dev/null +++ b/clusters/cl01tl/helm/lidatube/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-lidatube + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-lidatube + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - lidatube.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: lidatube + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/lidatube/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/lidatube/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..ff3c8907e --- /dev/null +++ b/clusters/cl01tl/helm/lidatube/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: lidatube-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidatube-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: lidatube-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/lidatube/templates/persistent-volume.yaml b/clusters/cl01tl/helm/lidatube/templates/persistent-volume.yaml new file mode 100644 index 000000000..35422746f --- /dev/null +++ b/clusters/cl01tl/helm/lidatube/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: lidatube-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: lidatube-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/Music + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/lidatube/values.yaml b/clusters/cl01tl/helm/lidatube/values.yaml new file mode 100644 index 000000000..9e1efa5e9 --- /dev/null +++ b/clusters/cl01tl/helm/lidatube/values.yaml @@ -0,0 +1,66 @@ +lidatube: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: thewicklowwolf/lidatube + tag: 0.2.41 + pullPolicy: IfNotPresent + env: + - name: PUID + value: 1000 + - name: PGID + value: 1000 + - name: lidarr_address + value: http://lidarr.lidarr:80 + - name: lidarr_api_key + valueFrom: + secretKeyRef: + name: lidatube-secret + key: lidarr_api_key + - name: sleep_interval + value: 360 + - name: sync_schedule + value: 4 + - name: attempt_lidarr_import + value: true + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 5000 + protocol: HTTP + persistence: + config: + forceRename: lidatube-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /lidatube/config + readOnly: false + music: + existingClaim: lidatube-nfs-storage + advancedMounts: + main: + main: + - path: /lidatube/downloads + readOnly: false diff --git a/clusters/cl01tl/helm/listenarr/Chart.yaml b/clusters/cl01tl/helm/listenarr/Chart.yaml new file mode 100644 index 000000000..c6415cb3b --- /dev/null +++ b/clusters/cl01tl/helm/listenarr/Chart.yaml @@ -0,0 +1,20 @@ +apiVersion: v2 +name: listenarr +version: 1.0.0 +description: Listenarr +keywords: + - listenarr + - audiobooks +home: https://wiki.alexlebens.dev/ +sources: + - https://github.com/therobbiedavis/Listenarr + - https://hub.docker.com/r/therobbiedavis/listenarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: listenarr + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +appVersion: 0.2.35 diff --git a/clusters/cl01tl/helm/listenarr/templates/http-route.yaml b/clusters/cl01tl/helm/listenarr/templates/http-route.yaml new file mode 100644 index 000000000..73bdae8c0 --- /dev/null +++ b/clusters/cl01tl/helm/listenarr/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-listenarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-listenarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - listenarr.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: listenarr + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/listenarr/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/listenarr/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..96a4a3e48 --- /dev/null +++ b/clusters/cl01tl/helm/listenarr/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: listenarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: listenarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: listenarr-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/listenarr/templates/persistent-volume.yaml b/clusters/cl01tl/helm/listenarr/templates/persistent-volume.yaml new file mode 100644 index 000000000..a22ee2ab0 --- /dev/null +++ b/clusters/cl01tl/helm/listenarr/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: listenarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: listenarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/Audiobooks + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/listenarr/values.yaml b/clusters/cl01tl/helm/listenarr/values.yaml new file mode 100644 index 000000000..1b1a04e84 --- /dev/null +++ b/clusters/cl01tl/helm/listenarr/values.yaml @@ -0,0 +1,46 @@ +listenarr: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: therobbiedavis/listenarr + tag: canary-0.2.35 + pullPolicy: IfNotPresent + env: + - name: LISTENARR_PUBLIC_URL + value: https://listenarr.alexlebens.net + resources: + requests: + cpu: 50m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 5000 + protocol: HTTP + persistence: + config: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /app/config + readOnly: false + media: + existingClaim: listenarr-nfs-storage + advancedMounts: + main: + main: + - path: /data + readOnly: false diff --git a/clusters/cl01tl/helm/omni-tools/Chart.yaml b/clusters/cl01tl/helm/omni-tools/Chart.yaml new file mode 100644 index 000000000..cc0017779 --- /dev/null +++ b/clusters/cl01tl/helm/omni-tools/Chart.yaml @@ -0,0 +1,20 @@ +apiVersion: v2 +name: omni-tools +version: 1.0.0 +description: OmniTools +keywords: + - omni-tools +home: https://wiki.alexlebens.dev/s/8820cd36-dcf6-4ddf-8b2f-584271628a54 +sources: + - https://github.com/iib0011/omni-tools + - https://hub.docker.com/r/iib0011/omni-tools + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: omni-tools + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/omnitools.png +appVersion: 0.4.0 diff --git a/clusters/cl01tl/helm/omni-tools/templates/http-route.yaml b/clusters/cl01tl/helm/omni-tools/templates/http-route.yaml new file mode 100644 index 000000000..981539188 --- /dev/null +++ b/clusters/cl01tl/helm/omni-tools/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-omni-tools + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-omni-tools + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - omni-tools.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: omni-tools + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/omni-tools/values.yaml b/clusters/cl01tl/helm/omni-tools/values.yaml new file mode 100644 index 000000000..43daccfcd --- /dev/null +++ b/clusters/cl01tl/helm/omni-tools/values.yaml @@ -0,0 +1,25 @@ +omni-tools: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: iib0011/omni-tools + tag: 0.6.0 + pullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 512Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 80 + protocol: HTTP diff --git a/clusters/cl01tl/helm/outline/Chart.yaml b/clusters/cl01tl/helm/outline/Chart.yaml new file mode 100644 index 000000000..5063d92f8 --- /dev/null +++ b/clusters/cl01tl/helm/outline/Chart.yaml @@ -0,0 +1,34 @@ +apiVersion: v2 +name: outline +version: 1.0.0 +description: Outline +keywords: + - outline + - wiki + - documentation +home: https://wiki.alexlebens.dev/s/c530c2b9-82b7-44df-b7ef-870c8b29242f +sources: + - https://github.com/outline/outline + - https://github.com/cloudflare/cloudflared + - https://github.com/cloudnative-pg/cloudnative-pg + - https://hub.docker.com/r/outlinewiki/outline + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: outline + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: cloudflared + alias: cloudflared-outline + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/outline.png +appVersion: 0.84.0 diff --git a/clusters/cl01tl/helm/outline/templates/external-secret.yaml b/clusters/cl01tl/helm/outline/templates/external-secret.yaml new file mode 100644 index 000000000..7fa5518f1 --- /dev/null +++ b/clusters/cl01tl/helm/outline/templates/external-secret.yaml @@ -0,0 +1,148 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: outline-key-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline-key-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: secret-key + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/outline/key + metadataPolicy: None + property: secret-key + - secretKey: utils-key + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/outline/key + metadataPolicy: None + property: utils-key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: outline-oidc-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline-oidc-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: client + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/outline + metadataPolicy: None + property: client + - secretKey: secret + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/outline + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: outline-cloudflared-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline-cloudflared-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/outline + metadataPolicy: None + property: token + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: outline-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: outline-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: outline-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/outline/templates/object-bucket-claim.yaml b/clusters/cl01tl/helm/outline/templates/object-bucket-claim.yaml new file mode 100644 index 000000000..6d780520a --- /dev/null +++ b/clusters/cl01tl/helm/outline/templates/object-bucket-claim.yaml @@ -0,0 +1,30 @@ +apiVersion: objectbucket.io/v1alpha1 +kind: ObjectBucketClaim +metadata: + name: ceph-bucket-outline + labels: + app.kubernetes.io/name: ceph-bucket-outline + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + generateBucketName: bucket-outline + storageClassName: ceph-bucket + additionalConfig: + bucketPolicy: | + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "VisualEditor", + "Effect": "Allow", + "Action": [ + "s3:GetObjectAcl", + "s3:DeleteObject", + "s3:PutObject", + "s3:GetObject", + "s3:PutObjectAcl" + ], + "Resource": "arn:aws:s3:::bucket-outline-630c57e0-d475-4d78-926c-c1c082291d73/*" + } + ] + } diff --git a/clusters/cl01tl/helm/outline/templates/redis-replication.yaml b/clusters/cl01tl/helm/outline/templates/redis-replication.yaml new file mode 100644 index 000000000..af65e0566 --- /dev/null +++ b/clusters/cl01tl/helm/outline/templates/redis-replication.yaml @@ -0,0 +1,32 @@ +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: redis-replication-outline + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-outline + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + clusterSize: 3 + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + kubernetesConfig: + image: quay.io/opstree/redis:v8.0.3 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 128Mi + storage: + volumeClaimTemplate: + spec: + storageClassName: ceph-block + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + redisExporter: + enabled: true + image: quay.io/opstree/redis-exporter:v1.48.0 diff --git a/clusters/cl01tl/helm/outline/templates/service-monitor.yaml b/clusters/cl01tl/helm/outline/templates/service-monitor.yaml new file mode 100644 index 000000000..e5f767b2d --- /dev/null +++ b/clusters/cl01tl/helm/outline/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: redis-replication-outline + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-outline + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + redis-operator: "true" + env: production +spec: + selector: + matchLabels: + redis_setup_type: replication + endpoints: + - port: redis-exporter + interval: 30s + scrapeTimeout: 10s diff --git a/clusters/cl01tl/helm/outline/values.yaml b/clusters/cl01tl/helm/outline/values.yaml new file mode 100644 index 000000000..6d0f6c784 --- /dev/null +++ b/clusters/cl01tl/helm/outline/values.yaml @@ -0,0 +1,203 @@ +outline: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: outlinewiki/outline + tag: 1.1.0 + pullPolicy: IfNotPresent + env: + - name: NODE_ENV + value: production + - name: URL + value: https://wiki.alexlebens.dev + - name: PORT + value: 3000 + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: outline-key-secret + key: secret-key + - name: UTILS_SECRET + valueFrom: + secretKeyRef: + name: outline-key-secret + key: utils-key + - name: POSTGRES_USERNAME + valueFrom: + secretKeyRef: + name: outline-postgresql-17-cluster-app + key: username + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: outline-postgresql-17-cluster-app + key: password + - name: POSTGRES_DATABASE_NAME + valueFrom: + secretKeyRef: + name: outline-postgresql-17-cluster-app + key: dbname + - name: POSTGRES_DATABASE_HOST + valueFrom: + secretKeyRef: + name: outline-postgresql-17-cluster-app + key: host + - name: POSTGRES_DATABASE_PORT + valueFrom: + secretKeyRef: + name: outline-postgresql-17-cluster-app + key: port + - name: DATABASE_URL + value: postgres://$(POSTGRES_USERNAME):$(POSTGRES_PASSWORD)@$(POSTGRES_DATABASE_HOST):$(POSTGRES_DATABASE_PORT)/$(POSTGRES_DATABASE_NAME) + - name: DATABASE_URL_TEST + value: postgres://$(POSTGRES_USERNAME):$(POSTGRES_PASSWORD)@$(POSTGRES_DATABASE_HOST):$(POSTGRES_DATABASE_PORT)/$(POSTGRES_DATABASE_NAME)-test + - name: DATABASE_CONNECTION_POOL_MIN + value: "2" + - name: DATABASE_CONNECTION_POOL_MAX + value: "20" + - name: PGSSLMODE + value: disable + - name: REDIS_URL + value: redis://redis-replication-outline-master.outline:6379 + - name: FILE_STORAGE + value: s3 + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: ceph-bucket-outline + key: AWS_ACCESS_KEY_ID + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: ceph-bucket-outline + key: AWS_SECRET_ACCESS_KEY + - name: AWS_REGION + value: us-east-1 + - name: AWS_S3_UPLOAD_BUCKET_NAME + valueFrom: + configMapKeyRef: + name: ceph-bucket-outline + key: BUCKET_NAME + - name: AWS_S3_UPLOAD_BUCKET_URL + value: https://objects.alexlebens.dev + - name: AWS_S3_FORCE_PATH_STYLE + value: true + - name: AWS_S3_ACL + value: private + - name: FILE_STORAGE_UPLOAD_MAX_SIZE + value: "26214400" + - name: FORCE_HTTPS + value: false + - name: ENABLE_UPDATES + value: false + - name: WEB_CONCURRENCY + value: 1 + - name: FILE_STORAGE_IMPORT_MAX_SIZE + value: 5120000 + - name: LOG_LEVEL + value: info + - name: DEFAULT_LANGUAGE + value: en_US + - name: RATE_LIMITER_ENABLED + value: false + - name: DEVELOPMENT_UNSAFE_INLINE_CSP + value: false + - name: OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: outline-oidc-secret + key: client + - name: OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: outline-oidc-secret + key: secret + - name: OIDC_AUTH_URI + value: https://auth.alexlebens.dev/application/o/authorize/ + - name: OIDC_TOKEN_URI + value: https://auth.alexlebens.dev/application/o/token/ + - name: OIDC_USERINFO_URI + value: https://auth.alexlebens.dev/application/o/userinfo/ + - name: OIDC_USERNAME_CLAIM + value: email + - name: OIDC_DISPLAY_NAME + value: Authentik + - name: OIDC_SCOPES + value: openid profile email + resources: + requests: + cpu: 10m + memory: 512Mi + service: + main: + controller: main + ports: + http: + port: 3000 + targetPort: 3000 + protocol: HTTP +cloudflared-outline: + existingSecretName: outline-cloudflared-secret + name: cloudflared-outline +postgres-17-cluster: + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/outline/outline-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: outline-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/outline/outline-postgresql-17-cluster + index: 1 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/outline/outline-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: outline-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/outline/outline-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: outline-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 10 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/overseerr/Chart.yaml b/clusters/cl01tl/helm/overseerr/Chart.yaml new file mode 100644 index 000000000..69efd1844 --- /dev/null +++ b/clusters/cl01tl/helm/overseerr/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: overseerr +version: 1.0.0 +description: Overseerr +keywords: + - overseer + - media + - request +home: https://wiki.alexlebens.dev/s/ba89ec92-a15c-48d5-9c33-a28a0134b0f9 +sources: + - https://github.com/sct/overseerr + - https://github.com/sct/overseerr/pkgs/container/overseerr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/overseerr.png +appVersion: 1.34.0 diff --git a/clusters/cl01tl/helm/overseerr/templates/external-secret.yaml b/clusters/cl01tl/helm/overseerr/templates/external-secret.yaml new file mode 100644 index 000000000..07fd8a0d7 --- /dev/null +++ b/clusters/cl01tl/helm/overseerr/templates/external-secret.yaml @@ -0,0 +1,55 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: overseerr-main-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: overseerr-main-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/overseerr/overseerr-main" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/overseerr/templates/http-route.yaml b/clusters/cl01tl/helm/overseerr/templates/http-route.yaml new file mode 100644 index 000000000..f02422b82 --- /dev/null +++ b/clusters/cl01tl/helm/overseerr/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-overseerr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-overseerr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - overseerr.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: overseerr + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/overseerr/templates/replication-source.yaml b/clusters/cl01tl/helm/overseerr/templates/replication-source.yaml new file mode 100644 index 000000000..370af3b85 --- /dev/null +++ b/clusters/cl01tl/helm/overseerr/templates/replication-source.yaml @@ -0,0 +1,25 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: overseerr-main-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: overseerr-main-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: overseerr-main + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: overseerr-main-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/overseerr/values.yaml b/clusters/cl01tl/helm/overseerr/values.yaml new file mode 100644 index 000000000..ab54214f0 --- /dev/null +++ b/clusters/cl01tl/helm/overseerr/values.yaml @@ -0,0 +1,40 @@ +app-template: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/sct/overseerr + tag: 1.34.0 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + resources: + requests: + cpu: 10m + memory: 512Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 5055 + protocol: HTTP + persistence: + main: + forceRename: overseerr-main + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 10Gi + retain: true + advancedMounts: + main: + main: + - path: /app/config + readOnly: false diff --git a/clusters/cl01tl/helm/photoview/Chart.yaml b/clusters/cl01tl/helm/photoview/Chart.yaml new file mode 100644 index 000000000..f8a8dd360 --- /dev/null +++ b/clusters/cl01tl/helm/photoview/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +name: photoview +version: 1.0.0 +description: Photoview +keywords: + - photoview + - pictures +home: https://wiki.alexlebens.dev/s/f519a435-8388-4503-a9f9-401bdb424151 +sources: + - https://github.com/photoview/photoview + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: photoview + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/photoview.png +appVersion: 2.4.0 diff --git a/clusters/cl01tl/helm/photoview/templates/external-secrets.yaml b/clusters/cl01tl/helm/photoview/templates/external-secrets.yaml new file mode 100644 index 000000000..68c6cb04f --- /dev/null +++ b/clusters/cl01tl/helm/photoview/templates/external-secrets.yaml @@ -0,0 +1,65 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: photoview-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: photoview-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: photoview-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: photoview-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/photoview/templates/http-route.yaml b/clusters/cl01tl/helm/photoview/templates/http-route.yaml new file mode 100644 index 000000000..838a90b95 --- /dev/null +++ b/clusters/cl01tl/helm/photoview/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-photoview + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-photoview + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - photoview.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: photoview + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/photoview/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/photoview/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..3b4120483 --- /dev/null +++ b/clusters/cl01tl/helm/photoview/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: photoview-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: photoview-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: photoview-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/photoview/templates/persistent-volume.yaml b/clusters/cl01tl/helm/photoview/templates/persistent-volume.yaml new file mode 100644 index 000000000..dfdfb917f --- /dev/null +++ b/clusters/cl01tl/helm/photoview/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: photoview-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: photoview-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/Pictures + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/photoview/values.yaml b/clusters/cl01tl/helm/photoview/values.yaml new file mode 100644 index 000000000..b27700dd9 --- /dev/null +++ b/clusters/cl01tl/helm/photoview/values.yaml @@ -0,0 +1,130 @@ +photoview: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + initContainers: + init-chmod-data: + securityContext: + runAsUser: 0 + image: + repository: busybox + tag: 1.37.0 + pullPolicy: IfNotPresent + command: + - /bin/sh + - -ec + - | + /bin/chown -R 999:999 /app/cache + resources: + requests: + cpu: 100m + memory: 128Mi + containers: + main: + image: + repository: photoview/photoview + tag: 2.4.0 + pullPolicy: IfNotPresent + env: + - name: PHOTOVIEW_DATABASE_DRIVER + value: postgres + - name: PHOTOVIEW_POSTGRES_URL + valueFrom: + secretKeyRef: + name: photoview-postgresql-17-cluster-app + key: uri + - name: PHOTOVIEW_MEDIA_CACHE + value: /app/cache + resources: + requests: + cpu: 10m + memory: 512Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 80 + protocol: HTTP + persistence: + cache: + forceRename: photoview-cache + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 10Gi + retain: false + advancedMounts: + main: + init-chmod-data: + - path: /app/cache + readOnly: false + main: + - path: /app/cache + readOnly: false + media: + existingClaim: photoview-nfs-storage + advancedMounts: + main: + main: + - path: /photos + readOnly: true +postgres-17-cluster: + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/photoview/photoview-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: photoview-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/photoview/photoview-postgresql-17-cluster + index: 1 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/photoview/photoview-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: photoview-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/photoview/photoview-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: photoview-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 12 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/plex/Chart.yaml b/clusters/cl01tl/helm/plex/Chart.yaml new file mode 100644 index 000000000..984233394 --- /dev/null +++ b/clusters/cl01tl/helm/plex/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +name: plex +version: 1.0.0 +description: Plex +keywords: + - plex + - tv shows + - movies + - music + - photos + - live tv +home: https://wiki.alexlebens.dev/s/e2833eed-f991-4b00-9fa0-5d7f403a8183 +sources: + - https://www.plex.tv/ + - https://github.com/linuxserver/docker-plex + - https://github.com/linuxserver/docker-plex/pkgs/container/plex + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: plex + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/plex.png +appVersion: 1.41.6 diff --git a/clusters/cl01tl/helm/plex/templates/http-route.yaml b/clusters/cl01tl/helm/plex/templates/http-route.yaml new file mode 100644 index 000000000..0ef0cbb23 --- /dev/null +++ b/clusters/cl01tl/helm/plex/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-plex + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-plex + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - plex.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: plex + port: 32400 + weight: 100 diff --git a/clusters/cl01tl/helm/plex/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/plex/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..61a5296c2 --- /dev/null +++ b/clusters/cl01tl/helm/plex/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: plex-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: plex-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: plex-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/plex/templates/persistent-volume.yaml b/clusters/cl01tl/helm/plex/templates/persistent-volume.yaml new file mode 100644 index 000000000..cdf01b15c --- /dev/null +++ b/clusters/cl01tl/helm/plex/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: plex-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: plex-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/plex/values.yaml b/clusters/cl01tl/helm/plex/values.yaml new file mode 100644 index 000000000..532c65908 --- /dev/null +++ b/clusters/cl01tl/helm/plex/values.yaml @@ -0,0 +1,61 @@ +plex: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/linuxserver/plex + tag: 1.42.2@sha256:ab81c7313fb5dc4d1f9562e5bbd5e5877a8a3c5ca6b9f9fff3437b5096a2b123 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: VERSION + value: docker + - name: PLEX_CLAIM + value: claim-XmGK2o9x54PbCzQaqj-J + resources: + limits: + gpu.intel.com/i915: 1 + requests: + gpu.intel.com/i915: 1 + cpu: 10m + memory: 512Mi + service: + main: + controller: main + type: LoadBalancer + ports: + http: + port: 32400 + targetPort: 32400 + protocol: HTTP + persistence: + config: + forceRename: plex-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 100Gi + advancedMounts: + main: + main: + - path: /config + readOnly: false + transcode: + type: emptyDir + advancedMounts: + main: + main: + - path: /transcode + readOnly: false + media: + existingClaim: plex-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: true diff --git a/clusters/cl01tl/helm/postiz/Chart.yaml b/clusters/cl01tl/helm/postiz/Chart.yaml new file mode 100644 index 000000000..fbe1d87e3 --- /dev/null +++ b/clusters/cl01tl/helm/postiz/Chart.yaml @@ -0,0 +1,32 @@ +apiVersion: v2 +name: postiz +version: 1.0.0 +description: Postiz +keywords: + - postiz + - social-media +home: https://wiki.alexlebens.dev/s/f483a06b-860b-423c-8d51-a1ce82e0fd43 +sources: + - https://github.com/gitroomhq/postiz-app + - https://github.com/cloudflare/cloudflared + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/gitroomhq/postiz-app/pkgs/container/postiz-app + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: postiz + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: cloudflared + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/postiz.png +appVersion: v1.43.3 diff --git a/clusters/cl01tl/helm/postiz/templates/external-secret.yaml b/clusters/cl01tl/helm/postiz/templates/external-secret.yaml new file mode 100644 index 000000000..4bbfa9af3 --- /dev/null +++ b/clusters/cl01tl/helm/postiz/templates/external-secret.yaml @@ -0,0 +1,292 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: postiz-config-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-config-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: JWT_SECRET + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/postiz/config + metadataPolicy: None + property: JWT_SECRET + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: postiz-redis-config + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-redis-config + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: REDIS_URL + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/postiz/redis + metadataPolicy: None + property: REDIS_URL + - secretKey: user + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/postiz/redis + metadataPolicy: None + property: user + - secretKey: password + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/postiz/redis + metadataPolicy: None + property: password + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: postiz-oidc-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-oidc-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: client + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/postiz + metadataPolicy: None + property: client + - secretKey: secret + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/postiz + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: postiz-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/postiz/postiz-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: postiz-uploads-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-uploads-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/postiz/postiz-uploads" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: postiz-cloudflared-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-cloudflared-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/postiz + metadataPolicy: None + property: token + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: postiz-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: postiz-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/postiz/templates/http-route.yaml b/clusters/cl01tl/helm/postiz/templates/http-route.yaml new file mode 100644 index 000000000..382c76ca5 --- /dev/null +++ b/clusters/cl01tl/helm/postiz/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-postiz + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-postiz + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - postiz.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: postiz + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/postiz/templates/redis-replication.yaml b/clusters/cl01tl/helm/postiz/templates/redis-replication.yaml new file mode 100644 index 000000000..302a81ad6 --- /dev/null +++ b/clusters/cl01tl/helm/postiz/templates/redis-replication.yaml @@ -0,0 +1,35 @@ +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: redis-replication-postiz + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-postiz + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + clusterSize: 3 + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + kubernetesConfig: + image: quay.io/opstree/redis:v8.0.3 + imagePullPolicy: IfNotPresent + redisSecret: + name: postiz-redis-config + key: password + resources: + requests: + cpu: 50m + memory: 128Mi + storage: + volumeClaimTemplate: + spec: + storageClassName: ceph-block + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + redisExporter: + enabled: true + image: quay.io/opstree/redis-exporter:v1.48.0 diff --git a/clusters/cl01tl/helm/postiz/templates/replication-source.yaml b/clusters/cl01tl/helm/postiz/templates/replication-source.yaml new file mode 100644 index 000000000..69b38cdc3 --- /dev/null +++ b/clusters/cl01tl/helm/postiz/templates/replication-source.yaml @@ -0,0 +1,52 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: postiz-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: postiz-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: postiz-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot + +--- +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: postiz-uploads-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: postiz-uploads-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: postiz-uploads + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: postiz-uploads-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/postiz/templates/service-monitor.yaml b/clusters/cl01tl/helm/postiz/templates/service-monitor.yaml new file mode 100644 index 000000000..c7e86c00f --- /dev/null +++ b/clusters/cl01tl/helm/postiz/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: redis-replication-postiz + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-postiz + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + redis-operator: "true" + env: production +spec: + selector: + matchLabels: + redis_setup_type: replication + endpoints: + - port: redis-exporter + interval: 30s + scrapeTimeout: 10s diff --git a/clusters/cl01tl/helm/postiz/values.yaml b/clusters/cl01tl/helm/postiz/values.yaml new file mode 100644 index 000000000..7e2b6da94 --- /dev/null +++ b/clusters/cl01tl/helm/postiz/values.yaml @@ -0,0 +1,163 @@ +postiz: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/gitroomhq/postiz-app + tag: v2.8.3 + pullPolicy: IfNotPresent + env: + - name: MAIN_URL + value: https://postiz.alexlebens.dev + - name: FRONTEND_URL + value: https://postiz.alexlebens.dev + - name: NEXT_PUBLIC_BACKEND_URL + value: https://postiz.alexlebens.dev/api + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: postiz-config-secret + key: JWT_SECRET + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: postiz-postgresql-17-cluster-app + key: uri + - name: REDIS_URL + valueFrom: + secretKeyRef: + name: postiz-redis-config + key: REDIS_URL + - 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 + - name: NEXT_PUBLIC_POSTIZ_OAUTH_DISPLAY_NAME + value: Authentik + - name: NEXT_PUBLIC_POSTIZ_OAUTH_LOGO_URL + value: https://cdn.jsdelivr.net/gh/selfhst/icons/png/authentik.png + - name: POSTIZ_GENERIC_OAUTH + value: "true" + - name: POSTIZ_OAUTH_URL + value: https://auth.alexlebens.dev + - name: POSTIZ_OAUTH_AUTH_URL + value: https://auth.alexlebens.dev/application/o/authorize/ + - name: POSTIZ_OAUTH_TOKEN_URL + value: https://auth.alexlebens.dev/application/o/token/ + - name: POSTIZ_OAUTH_USERINFO_URL + value: https://auth.alexlebens.dev/application/o/userinfo/ + - name: POSTIZ_OAUTH_CLIENT_ID + valueFrom: + secretKeyRef: + name: postiz-oidc-secret + key: client + - name: POSTIZ_OAUTH_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: postiz-oidc-secret + key: secret + - name: POSTIZ_OAUTH_SCOPE + value: openid profile email + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 5000 + protocol: HTTP + persistence: + config: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 2Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + uploads: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 10Gi + retain: true + advancedMounts: + main: + main: + - path: /uploads + readOnly: false +cloudflared: + name: cloudflared-postiz + existingSecretName: postiz-cloudflared-secret +postgres-17-cluster: + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/postiz/postiz-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: postiz-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/postiz/postiz-postgresql-17-cluster + index: 2 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/postiz/postiz-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: postiz-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/postiz/postiz-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: postiz-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 14 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/prowlarr/Chart.yaml b/clusters/cl01tl/helm/prowlarr/Chart.yaml new file mode 100644 index 000000000..ce3c6a7cb --- /dev/null +++ b/clusters/cl01tl/helm/prowlarr/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: prowlarr +version: 1.0.0 +description: Prowlarr +keywords: + - prowlarr + - servarr + - trackers +home: https://wiki.alexlebens.dev/s/7f963158-15fd-4eb5-b3ac-8a3aeb79613a +sources: + - https://github.com/Prowlarr/Prowlarr + - https://github.com/linuxserver/docker-prowlarr + - https://github.com/linuxserver/docker-prowlarr/pkgs/container/prowlarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: prowlarr + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/prowlarr.png +appVersion: 1.35.1 diff --git a/clusters/cl01tl/helm/prowlarr/templates/external-secret.yaml b/clusters/cl01tl/helm/prowlarr/templates/external-secret.yaml new file mode 100644 index 000000000..a35545627 --- /dev/null +++ b/clusters/cl01tl/helm/prowlarr/templates/external-secret.yaml @@ -0,0 +1,55 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: prowlarr-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: prowlarr-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/prowlarr/prowlarr-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/prowlarr/templates/http-route.yaml b/clusters/cl01tl/helm/prowlarr/templates/http-route.yaml new file mode 100644 index 000000000..8e202e8b4 --- /dev/null +++ b/clusters/cl01tl/helm/prowlarr/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-prowlarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-prowlarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - prowlarr.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: prowlarr + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/prowlarr/templates/replication-source.yaml b/clusters/cl01tl/helm/prowlarr/templates/replication-source.yaml new file mode 100644 index 000000000..55af1476e --- /dev/null +++ b/clusters/cl01tl/helm/prowlarr/templates/replication-source.yaml @@ -0,0 +1,35 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: prowlarr-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: prowlarr-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: prowlarr-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: prowlarr-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 568 + runAsGroup: 568 + fsGroup: 568 + fsGroupChangePolicy: OnRootMismatch + supplementalGroups: + - 44 + - 100 + - 109 + - 65539 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/prowlarr/values.yaml b/clusters/cl01tl/helm/prowlarr/values.yaml new file mode 100644 index 000000000..0b542abde --- /dev/null +++ b/clusters/cl01tl/helm/prowlarr/values.yaml @@ -0,0 +1,51 @@ +prowlarr: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + runAsUser: 568 + runAsGroup: 568 + fsGroup: 568 + fsGroupChangePolicy: OnRootMismatch + supplementalGroups: + - 44 + - 100 + - 109 + - 65539 + containers: + main: + image: + repository: ghcr.io/linuxserver/prowlarr + tag: 2.3.0@sha256:475853535de3de8441b87c1457c30f2e695f4831228b12b6b7274e9da409d874 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + resources: + requests: + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 9696 + protocol: HTTP + persistence: + config: + forceRename: prowlarr-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false diff --git a/clusters/cl01tl/helm/radarr-4k/Chart.yaml b/clusters/cl01tl/helm/radarr-4k/Chart.yaml new file mode 100644 index 000000000..a5fe41ee7 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-4k/Chart.yaml @@ -0,0 +1,33 @@ +apiVersion: v2 +name: radarr-4k +version: 1.0.0 +description: Radarr 4K +keywords: + - radarr + - servarr + - movies + - 4k + - metrics +home: https://wiki.alexlebens.dev/s/b5687ceb-11db-49b3-9c77-bf27bc322c99 +sources: + - https://github.com/Radarr/Radarr + - https://github.com/linuxserver/docker-radarr + - https://github.com/onedr0p/exportarr + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/linuxserver/docker-radarr/pkgs/container/radarr + - https://github.com/onedr0p/exportarr/pkgs/container/exportarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: radarr-4k + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/radarr-4k.png +appVersion: 5.22.4 diff --git a/clusters/cl01tl/helm/radarr-4k/templates/external-secret.yaml b/clusters/cl01tl/helm/radarr-4k/templates/external-secret.yaml new file mode 100644 index 000000000..6890221d3 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-4k/templates/external-secret.yaml @@ -0,0 +1,122 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-4k-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-4k-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/radarr5-4k/radarr5-4k-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-4k-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-4k-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-4k-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-4k-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/radarr-4k/templates/http-route.yaml b/clusters/cl01tl/helm/radarr-4k/templates/http-route.yaml new file mode 100644 index 000000000..029939f6b --- /dev/null +++ b/clusters/cl01tl/helm/radarr-4k/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-radarr-4k + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-radarr-4k + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - radarr-4k.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: radarr-4k + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/radarr-4k/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/radarr-4k/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..b05e92529 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-4k/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: radarr-4k-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-4k-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: radarr-4k-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/radarr-4k/templates/persistent-volume.yaml b/clusters/cl01tl/helm/radarr-4k/templates/persistent-volume.yaml new file mode 100644 index 000000000..435908330 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-4k/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: radarr-4k-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-4k-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/radarr-4k/templates/prometheus-rule.yaml b/clusters/cl01tl/helm/radarr-4k/templates/prometheus-rule.yaml new file mode 100644 index 000000000..e3cab3d05 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-4k/templates/prometheus-rule.yaml @@ -0,0 +1,32 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: radarr-4k + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-4k + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + groups: + - name: radarr-4k + rules: + - alert: ExportarrAbsent + annotations: + description: Radarr 4K Exportarr has disappeared from Prometheus + service discovery. + summary: Exportarr is down. + expr: | + absent(up{job=~".*radarr-4k.*"} == 1) + for: 5m + labels: + severity: critical + - alert: Radarr4kDown + annotations: + description: Radarr 4K service is down. + summary: Radarr 4K is down. + expr: | + radarr_4k_system_status{job=~".*radarr-4k.*"} == 0 + for: 5m + labels: + severity: critical diff --git a/clusters/cl01tl/helm/radarr-4k/templates/replication-source.yaml b/clusters/cl01tl/helm/radarr-4k/templates/replication-source.yaml new file mode 100644 index 000000000..6829ca51d --- /dev/null +++ b/clusters/cl01tl/helm/radarr-4k/templates/replication-source.yaml @@ -0,0 +1,30 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: radarr-4k-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-4k-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: radarr-4k-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: radarr-4k-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/radarr-4k/templates/service-monitor.yaml b/clusters/cl01tl/helm/radarr-4k/templates/service-monitor.yaml new file mode 100644 index 000000000..57d1ab55c --- /dev/null +++ b/clusters/cl01tl/helm/radarr-4k/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: radarr-4k + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-4k + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: radarr-4k + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: metrics + interval: 3m + scrapeTimeout: 1m + path: /metrics diff --git a/clusters/cl01tl/helm/radarr-4k/values.yaml b/clusters/cl01tl/helm/radarr-4k/values.yaml new file mode 100644 index 000000000..3c598c07d --- /dev/null +++ b/clusters/cl01tl/helm/radarr-4k/values.yaml @@ -0,0 +1,151 @@ +radarr-4k: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: ghcr.io/linuxserver/radarr + tag: 6.0.4@sha256:06ac318ecb95a34c7b229568dcb4271f02cb5007bb189a0dd67a2032864187ca + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + resources: + requests: + cpu: 100m + memory: 256Mi + metrics: + image: + repository: ghcr.io/onedr0p/exportarr + tag: v2.3.0 + pullPolicy: IfNotPresent + args: ["radarr"] + env: + - name: URL + value: http://localhost + - name: CONFIG + value: /config/config.xml + - name: PORT + value: 9793 + - name: ENABLE_ADDITIONAL_METRICS + value: false + - name: ENABLE_UNKNOWN_QUEUE_ITEMS + value: false + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 7878 + protocol: HTTP + metrics: + port: 9793 + targetPort: 9793 + protocol: TCP + persistence: + config: + forceRename: radarr-4k-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 20Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + metrics: + - path: /config + readOnly: true + media: + existingClaim: radarr-4k-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false +postgres-17-cluster: + nameOverride: radarr5-4k-postgresql-17 + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + resources: + requests: + memory: 1Gi + cpu: 200m + initdb: + postInitSQL: + - CREATE DATABASE "radarr-main" OWNER "app"; + - CREATE DATABASE "radarr-log" OWNER "app"; + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/radarr5-4k/radarr5-4k-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: radarr-4k-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/radarr5-4k/radarr5-4k-postgresql-17-cluster + index: 1 + endpointCredentials: radarr-4k-postgresql-17-cluster-backup-secret + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/radarr-4k/radarr5-4k-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: radarr-4k-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/radarr-4k/radarr5-4k-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: radarr-4k-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 18 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/radarr-anime/Chart.yaml b/clusters/cl01tl/helm/radarr-anime/Chart.yaml new file mode 100644 index 000000000..ad9532c00 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-anime/Chart.yaml @@ -0,0 +1,33 @@ +apiVersion: v2 +name: radarr-anime +version: 1.0.0 +description: Radarr Anime +keywords: + - radarr + - servarr + - movies + - anime + - metrics +home: https://wiki.alexlebens.dev/s/b5687ceb-11db-49b3-9c77-bf27bc322c99 +sources: + - https://github.com/Radarr/Radarr + - https://github.com/linuxserver/docker-radarr + - https://github.com/onedr0p/exportarr + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/linuxserver/docker-radarr/pkgs/container/radarr + - https://github.com/onedr0p/exportarr/pkgs/container/exportarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: radarr-anime + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/radarr-anime.png +appVersion: 5.22.4 diff --git a/clusters/cl01tl/helm/radarr-anime/templates/external-secret.yaml b/clusters/cl01tl/helm/radarr-anime/templates/external-secret.yaml new file mode 100644 index 000000000..20beb063d --- /dev/null +++ b/clusters/cl01tl/helm/radarr-anime/templates/external-secret.yaml @@ -0,0 +1,122 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-anime-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-anime-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/radarr5-anime/radarr5-anime-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-anime-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-anime-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-anime-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-anime-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/radarr-anime/templates/http-route.yaml b/clusters/cl01tl/helm/radarr-anime/templates/http-route.yaml new file mode 100644 index 000000000..7fd42815c --- /dev/null +++ b/clusters/cl01tl/helm/radarr-anime/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-radarr-anime + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-radarr-anime + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - radarr-anime.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: radarr-anime + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/radarr-anime/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/radarr-anime/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..572bca509 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-anime/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: radarr-anime-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-anime-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: radarr-anime-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/radarr-anime/templates/persistent-volume.yaml b/clusters/cl01tl/helm/radarr-anime/templates/persistent-volume.yaml new file mode 100644 index 000000000..de760a1b9 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-anime/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: radarr-anime-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-anime-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/radarr-anime/templates/prometheus-rule.yaml b/clusters/cl01tl/helm/radarr-anime/templates/prometheus-rule.yaml new file mode 100644 index 000000000..9134bf0c5 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-anime/templates/prometheus-rule.yaml @@ -0,0 +1,32 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: radarr-anime + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-anime + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + groups: + - name: radarr-anime + rules: + - alert: ExportarrAbsent + annotations: + description: Radarr Anime Exportarr has disappeared from Prometheus + service discovery. + summary: Exportarr is down. + expr: | + absent(up{job=~".*radarr-anime.*"} == 1) + for: 5m + labels: + severity: critical + - alert: RadarrAnimeDown + annotations: + description: Radarr Anime service is down. + summary: Radarr Anime is down. + expr: | + radarr_anime_system_status{job=~".*radarr-anime.*"} == 0 + for: 5m + labels: + severity: critical diff --git a/clusters/cl01tl/helm/radarr-anime/templates/replication-source.yaml b/clusters/cl01tl/helm/radarr-anime/templates/replication-source.yaml new file mode 100644 index 000000000..8c2d38215 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-anime/templates/replication-source.yaml @@ -0,0 +1,30 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: radarr-anime-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-anime-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: radarr-anime-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: radarr-anime-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/radarr-anime/templates/service-monitor.yaml b/clusters/cl01tl/helm/radarr-anime/templates/service-monitor.yaml new file mode 100644 index 000000000..a25b96e8b --- /dev/null +++ b/clusters/cl01tl/helm/radarr-anime/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: radarr-anime + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-anime + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: radarr-anime + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: metrics + interval: 3m + scrapeTimeout: 1m + path: /metrics diff --git a/clusters/cl01tl/helm/radarr-anime/values.yaml b/clusters/cl01tl/helm/radarr-anime/values.yaml new file mode 100644 index 000000000..3914a9db3 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-anime/values.yaml @@ -0,0 +1,145 @@ +radarr-anime: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: ghcr.io/linuxserver/radarr + tag: 6.0.4@sha256:06ac318ecb95a34c7b229568dcb4271f02cb5007bb189a0dd67a2032864187ca + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + resources: + requests: + cpu: 10m + memory: 256Mi + metrics: + image: + repository: ghcr.io/onedr0p/exportarr + tag: v2.3.0 + pullPolicy: IfNotPresent + args: ["radarr"] + env: + - name: URL + value: http://localhost + - name: CONFIG + value: /config/config.xml + - name: PORT + value: 9793 + - name: ENABLE_ADDITIONAL_METRICS + value: false + - name: ENABLE_UNKNOWN_QUEUE_ITEMS + value: false + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 7878 + protocol: HTTP + metrics: + port: 9793 + targetPort: 9793 + protocol: TCP + persistence: + config: + forceRename: radarr-anime-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 20Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + metrics: + - path: /config + readOnly: true + media: + existingClaim: radarr-anime-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false +postgres-17-cluster: + nameOverride: radarr5-anime-postgresql-17 + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + initdb: + postInitSQL: + - CREATE DATABASE "radarr-main" OWNER "app"; + - CREATE DATABASE "radarr-log" OWNER "app"; + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/radarr5-anime/radarr5-anime-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: radarr-anime-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/radarr5-anime/radarr5-anime-postgresql-17-cluster + index: 1 + endpointCredentials: radarr-anime-postgresql-17-cluster-backup-secret + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/radarr-anime/radarr5-anime-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: radarr-anime-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/radarr-anime/radarr5-anime-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: radarr-anime-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 20 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/radarr-standup/Chart.yaml b/clusters/cl01tl/helm/radarr-standup/Chart.yaml new file mode 100644 index 000000000..ae95dd97d --- /dev/null +++ b/clusters/cl01tl/helm/radarr-standup/Chart.yaml @@ -0,0 +1,32 @@ +apiVersion: v2 +name: radarr-standup +version: 1.0.0 +description: Radarr Stand Up +keywords: + - radarr + - servarr + - standup + - metrics +home: https://wiki.alexlebens.dev/s/b5687ceb-11db-49b3-9c77-bf27bc322c99 +sources: + - https://github.com/Radarr/Radarr + - https://github.com/linuxserver/docker-radarr + - https://github.com/onedr0p/exportarr + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/linuxserver/docker-radarr/pkgs/container/radarr + - https://github.com/onedr0p/exportarr/pkgs/container/exportarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: radarr-standup + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/radarr.png +appVersion: 5.22.4 diff --git a/clusters/cl01tl/helm/radarr-standup/templates/external-secret.yaml b/clusters/cl01tl/helm/radarr-standup/templates/external-secret.yaml new file mode 100644 index 000000000..5f1f24a56 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-standup/templates/external-secret.yaml @@ -0,0 +1,122 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-standup-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-standup-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/radarr5-standup/radarr5-standup-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-standup-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-standup-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-standup-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-standup-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/radarr-standup/templates/http-route.yaml b/clusters/cl01tl/helm/radarr-standup/templates/http-route.yaml new file mode 100644 index 000000000..8d2a3c822 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-standup/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-radarr-standup + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-radarr-standup + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - radarr-standup.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: radarr-standup + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/radarr-standup/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/radarr-standup/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..29ad7f688 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-standup/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: radarr-standup-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-standup-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: radarr-standup-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/radarr-standup/templates/persistent-volume.yaml b/clusters/cl01tl/helm/radarr-standup/templates/persistent-volume.yaml new file mode 100644 index 000000000..63cdd5dea --- /dev/null +++ b/clusters/cl01tl/helm/radarr-standup/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: radarr-standup-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-standup-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/radarr-standup/templates/prometheus-rule.yaml b/clusters/cl01tl/helm/radarr-standup/templates/prometheus-rule.yaml new file mode 100644 index 000000000..3e33b02c4 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-standup/templates/prometheus-rule.yaml @@ -0,0 +1,32 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: radarr-standup + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-standup + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + groups: + - name: radarr-standup + rules: + - alert: ExportarrAbsent + annotations: + description: Radarr Stand Up Exportarr has disappeared from Prometheus + service discovery. + summary: Exportarr is down. + expr: | + absent(up{job=~".*radarr-standup.*"} == 1) + for: 5m + labels: + severity: critical + - alert: RadarrStandUpDown + annotations: + description: Radarr Stand Up service is down. + summary: Radarr Stand Up is down. + expr: | + radarr_standup_system_status{job=~".*radarr-standup.*"} == 0 + for: 5m + labels: + severity: critical diff --git a/clusters/cl01tl/helm/radarr-standup/templates/replication-source.yaml b/clusters/cl01tl/helm/radarr-standup/templates/replication-source.yaml new file mode 100644 index 000000000..b35406832 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-standup/templates/replication-source.yaml @@ -0,0 +1,30 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: radarr-standup-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-standup-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: radarr-standup-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: radarr-standup-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/radarr-standup/templates/service-monitor.yaml b/clusters/cl01tl/helm/radarr-standup/templates/service-monitor.yaml new file mode 100644 index 000000000..71c74be7e --- /dev/null +++ b/clusters/cl01tl/helm/radarr-standup/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: radarr-standup + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-standup + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: radarr-standup + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: metrics + interval: 3m + scrapeTimeout: 1m + path: /metrics diff --git a/clusters/cl01tl/helm/radarr-standup/values.yaml b/clusters/cl01tl/helm/radarr-standup/values.yaml new file mode 100644 index 000000000..90c032623 --- /dev/null +++ b/clusters/cl01tl/helm/radarr-standup/values.yaml @@ -0,0 +1,145 @@ +radarr-standup: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: ghcr.io/linuxserver/radarr + tag: 6.0.4@sha256:06ac318ecb95a34c7b229568dcb4271f02cb5007bb189a0dd67a2032864187ca + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + resources: + requests: + cpu: 10m + memory: 256Mi + metrics: + image: + repository: ghcr.io/onedr0p/exportarr + tag: v2.3.0 + pullPolicy: IfNotPresent + args: ["radarr"] + env: + - name: URL + value: http://localhost + - name: CONFIG + value: /config/config.xml + - name: PORT + value: 9793 + - name: ENABLE_ADDITIONAL_METRICS + value: false + - name: ENABLE_UNKNOWN_QUEUE_ITEMS + value: false + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 7878 + protocol: HTTP + metrics: + port: 9793 + targetPort: 9793 + protocol: TCP + persistence: + config: + forceRename: radarr-standup-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 20Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + metrics: + - path: /config + readOnly: true + media: + existingClaim: radarr-standup-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false +postgres-17-cluster: + nameOverride: radarr5-standup-postgresql-17 + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + initdb: + postInitSQL: + - CREATE DATABASE "radarr-main" OWNER "app"; + - CREATE DATABASE "radarr-log" OWNER "app"; + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/radarr5-standup/radarr5-standup-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: radarr-standup-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/radarr5-standup/radarr5-standup-postgresql-17-cluster + index: 1 + endpointCredentials: radarr-standup-postgresql-17-cluster-backup-secret + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/radarr-standup/radarr5-standup-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: radarr-standup-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/radarr-standup/radarr5-standup-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: radarr-standup-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 22 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/radarr/Chart.yaml b/clusters/cl01tl/helm/radarr/Chart.yaml new file mode 100644 index 000000000..fbb819be0 --- /dev/null +++ b/clusters/cl01tl/helm/radarr/Chart.yaml @@ -0,0 +1,32 @@ +apiVersion: v2 +name: radarr +version: 1.0.0 +description: Radarr +keywords: + - radarr + - servarr + - movies + - metrics +home: https://wiki.alexlebens.dev/s/b5687ceb-11db-49b3-9c77-bf27bc322c99 +sources: + - https://github.com/Radarr/Radarr + - https://github.com/linuxserver/docker-radarr + - https://github.com/onedr0p/exportarr + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/linuxserver/docker-radarr/pkgs/container/radarr + - https://github.com/onedr0p/exportarr/pkgs/container/exportarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: radarr + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/radarr.png +appVersion: 5.22.4 diff --git a/clusters/cl01tl/helm/radarr/templates/external-secret.yaml b/clusters/cl01tl/helm/radarr/templates/external-secret.yaml new file mode 100644 index 000000000..aa1f929d9 --- /dev/null +++ b/clusters/cl01tl/helm/radarr/templates/external-secret.yaml @@ -0,0 +1,122 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/radarr5/radarr5-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: radarr-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/radarr/templates/http-route.yaml b/clusters/cl01tl/helm/radarr/templates/http-route.yaml new file mode 100644 index 000000000..0dae2e263 --- /dev/null +++ b/clusters/cl01tl/helm/radarr/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-radarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-radarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - radarr.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: radarr + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/radarr/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/radarr/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..1c07245f8 --- /dev/null +++ b/clusters/cl01tl/helm/radarr/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: radarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: radarr-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/radarr/templates/persistent-volume.yaml b/clusters/cl01tl/helm/radarr/templates/persistent-volume.yaml new file mode 100644 index 000000000..131d465cc --- /dev/null +++ b/clusters/cl01tl/helm/radarr/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: radarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/radarr/templates/prometheus-rule.yaml b/clusters/cl01tl/helm/radarr/templates/prometheus-rule.yaml new file mode 100644 index 000000000..d5076ca9d --- /dev/null +++ b/clusters/cl01tl/helm/radarr/templates/prometheus-rule.yaml @@ -0,0 +1,32 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: radarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + groups: + - name: radarr + rules: + - alert: ExportarrAbsent + annotations: + description: Radarr Exportarr has disappeared from Prometheus + service discovery. + summary: Exportarr is down. + expr: | + absent(up{job=~".*radarr.*"} == 1) + for: 5m + labels: + severity: critical + - alert: RadarrDown + annotations: + description: Radarr service is down. + summary: Radarr is down. + expr: | + radarr_system_status{job=~".*radarr.*"} == 0 + for: 5m + labels: + severity: critical diff --git a/clusters/cl01tl/helm/radarr/templates/replication-source.yaml b/clusters/cl01tl/helm/radarr/templates/replication-source.yaml new file mode 100644 index 000000000..3d8f3c1f0 --- /dev/null +++ b/clusters/cl01tl/helm/radarr/templates/replication-source.yaml @@ -0,0 +1,30 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: radarr-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: radarr-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: radarr-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/radarr/templates/service-monitor.yaml b/clusters/cl01tl/helm/radarr/templates/service-monitor.yaml new file mode 100644 index 000000000..4a5d7eb09 --- /dev/null +++ b/clusters/cl01tl/helm/radarr/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: radarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: radarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: radarr + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: metrics + interval: 3m + scrapeTimeout: 1m + path: /metrics diff --git a/clusters/cl01tl/helm/radarr/values.yaml b/clusters/cl01tl/helm/radarr/values.yaml new file mode 100644 index 000000000..8d81bb8b0 --- /dev/null +++ b/clusters/cl01tl/helm/radarr/values.yaml @@ -0,0 +1,151 @@ +radarr: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: ghcr.io/linuxserver/radarr + tag: 6.0.4@sha256:06ac318ecb95a34c7b229568dcb4271f02cb5007bb189a0dd67a2032864187ca + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + resources: + requests: + cpu: 100m + memory: 256Mi + metrics: + image: + repository: ghcr.io/onedr0p/exportarr + tag: v2.3.0 + pullPolicy: IfNotPresent + args: ["radarr"] + env: + - name: URL + value: http://localhost + - name: CONFIG + value: /config/config.xml + - name: PORT + value: 9793 + - name: ENABLE_ADDITIONAL_METRICS + value: false + - name: ENABLE_UNKNOWN_QUEUE_ITEMS + value: false + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 7878 + protocol: HTTP + metrics: + port: 9793 + targetPort: 9793 + protocol: TCP + persistence: + config: + forceRename: radarr-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 20Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + metrics: + - path: /config + readOnly: true + media: + existingClaim: radarr-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false +postgres-17-cluster: + nameOverride: radarr5-postgresql-17 + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + resources: + requests: + memory: 1Gi + cpu: 200m + initdb: + postInitSQL: + - CREATE DATABASE "radarr-main" OWNER "app"; + - CREATE DATABASE "radarr-log" OWNER "app"; + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/radarr5/radarr5-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: radarr-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/radarr5/radarr5-postgresql-17-cluster + index: 2 + endpointCredentials: radarr-postgresql-17-cluster-backup-secret + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/radarr/radarr5-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: radarr-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/radarr/radarr5-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: radarr-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 16 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/roundcube/Chart.yaml b/clusters/cl01tl/helm/roundcube/Chart.yaml new file mode 100644 index 000000000..788cd1b65 --- /dev/null +++ b/clusters/cl01tl/helm/roundcube/Chart.yaml @@ -0,0 +1,27 @@ +apiVersion: v2 +name: roundcube +version: 1.0.0 +description: Roundcube +keywords: + - roundcube + - email +home: https://wiki.alexlebens.dev/s/68896660-74d8-4166-82bd-f7c282cdb08e +sources: + - https://github.com/roundcube/roundcubemail + - https://github.com/cloudnative-pg/cloudnative-pg + - https://hub.docker.com/r/roundcube/roundcubemail + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: roundcube + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/roundcube.png +appVersion: 1.6.10 diff --git a/clusters/cl01tl/helm/roundcube/templates/external-secret.yaml b/clusters/cl01tl/helm/roundcube/templates/external-secret.yaml new file mode 100644 index 000000000..23419d874 --- /dev/null +++ b/clusters/cl01tl/helm/roundcube/templates/external-secret.yaml @@ -0,0 +1,145 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: roundcube-key-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: roundcube-key-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: DES_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/roundcube/key + metadataPolicy: None + property: DES_KEY + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: roundcube-data-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: roundcube-data-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/roundcube/roundcube-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: roundcube-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: roundcube-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: roundcube-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: roundcube-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/roundcube/templates/http-route.yaml b/clusters/cl01tl/helm/roundcube/templates/http-route.yaml new file mode 100644 index 000000000..b32e8fea1 --- /dev/null +++ b/clusters/cl01tl/helm/roundcube/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-mail + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-mail + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - mail.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: roundcube + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/roundcube/templates/replication-source.yaml b/clusters/cl01tl/helm/roundcube/templates/replication-source.yaml new file mode 100644 index 000000000..a7383cd31 --- /dev/null +++ b/clusters/cl01tl/helm/roundcube/templates/replication-source.yaml @@ -0,0 +1,25 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: roundcube-data-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: roundcube-data-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: roundcube-data + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: roundcube-data-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/roundcube/values.yaml b/clusters/cl01tl/helm/roundcube/values.yaml new file mode 100644 index 000000000..68255504f --- /dev/null +++ b/clusters/cl01tl/helm/roundcube/values.yaml @@ -0,0 +1,263 @@ +roundcube: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: roundcube/roundcubemail + tag: 1.6.11-fpm-alpine + pullPolicy: IfNotPresent + env: + - name: ROUNDCUBEMAIL_DB_TYPE + value: pgsql + - name: ROUNDCUBEMAIL_DB_HOST + valueFrom: + secretKeyRef: + name: roundcube-postgresql-17-cluster-app + key: host + - name: ROUNDCUBEMAIL_DB_NAME + valueFrom: + secretKeyRef: + name: roundcube-postgresql-17-cluster-app + key: dbname + - name: ROUNDCUBEMAIL_DB_USER + valueFrom: + secretKeyRef: + name: roundcube-postgresql-17-cluster-app + key: user + - name: ROUNDCUBEMAIL_DB_PASSWORD + valueFrom: + secretKeyRef: + name: roundcube-postgresql-17-cluster-app + key: password + - name: ROUNDCUBEMAIL_DES_KEY + valueFrom: + secretKeyRef: + name: roundcube-key-secret + key: DES_KEY + - name: ROUNDCUBEMAIL_DEFAULT_HOST + value: stalwart.stalwart + - name: ROUNDCUBEMAIL_DEFAULT_PORT + value: 143 + - name: ROUNDCUBEMAIL_SMTP_SERVER + value: stalwart.stalwart + - name: ROUNDCUBEMAIL_SMTP_PORT + value: 25 + - name: ROUNDCUBEMAIL_SKIN + value: elastic + - name: ROUNDCUBEMAIL_PLUGINS + value: archive,zipdownload,newmail_notifier + resources: + requests: + cpu: 10m + memory: 256Mi + nginx: + image: + repository: nginx + tag: 1.29.3-alpine + pullPolicy: IfNotPresent + env: + - name: NGINX_HOST + value: mail.alexlebens.net + - name: NGINX_PHP_CGI + value: roundcube.roundcube:9000 + resources: + requests: + cpu: 10m + memory: 128Mi + cleandb: + type: cronjob + cronjob: + suspend: false + concurrencyPolicy: Forbid + timeZone: US/Central + schedule: 30 4 * * * + startingDeadlineSeconds: 90 + successfulJobsHistory: 3 + failedJobsHistory: 3 + backoffLimit: 3 + parallelism: 1 + containers: + backup: + image: + repository: roundcube/roundcubemail + tag: 1.6.11-fpm-alpine + pullPolicy: IfNotPresent + env: + - name: ROUNDCUBEMAIL_DB_TYPE + value: pgsql + - name: ROUNDCUBEMAIL_DB_HOST + valueFrom: + secretKeyRef: + name: roundcube-postgresql-17-cluster-app + key: host + - name: ROUNDCUBEMAIL_DB_NAME + valueFrom: + secretKeyRef: + name: roundcube-postgresql-17-cluster-app + key: dbname + - name: ROUNDCUBEMAIL_DB_USER + valueFrom: + secretKeyRef: + name: roundcube-postgresql-17-cluster-app + key: user + - name: ROUNDCUBEMAIL_DB_PASSWORD + valueFrom: + secretKeyRef: + name: roundcube-postgresql-17-cluster-app + key: password + - name: ROUNDCUBEMAIL_DES_KEY + valueFrom: + secretKeyRef: + name: roundcube-key-secret + key: DES_KEY + - name: ROUNDCUBEMAIL_DEFAULT_HOST + value: tls://stalwart.stalwart + - name: ROUNDCUBEMAIL_SMTP_SERVER + value: tls://stalwart.stalwart + - name: ROUNDCUBEMAIL_SKIN + value: elastic + - name: ROUNDCUBEMAIL_PLUGINS + value: archive,zipdownload,newmail_notifier + args: + - bin/cleandb.sh + resources: + requests: + cpu: 100m + memory: 128Mi + configMaps: + config: + enabled: true + data: + default.conf: | + server { + listen 80 default_server; + server_name _; + root /var/www/html; + + location / { + try_files $uri /index.php$is_args$args; + } + + location ~ \.php(/|$) { + try_files $uri =404; + fastcgi_pass roundcube:9000; + fastcgi_read_timeout 300; + proxy_read_timeout 300; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT $realpath_root; + internal; + } + + client_max_body_size 6m; + + error_log /var/log/nginx/error.log; + access_log /var/log/nginx/access.log; + } + service: + main: + controller: main + ports: + mail: + port: 9000 + targetPort: 9000 + protocol: HTTP + web: + port: 80 + targetPort: 80 + protocol: HTTP + persistence: + data: + forceRename: roundcube-data + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /var/www/html + readOnly: false + nginx: + - path: /var/www/html + readOnly: false + temp: + type: emptyDir + advancedMounts: + main: + main: + - path: /tmp/roundcube-temp + readOnly: false + config: + enabled: true + type: configMap + name: roundcube-config + advancedMounts: + main: + nginx: + - path: /etc/nginx/conf.d/default.conf + readOnly: true + mountPropagation: None + subPath: default.conf +postgres-17-cluster: + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/roundcube/roundcube-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: roundcube-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/roundcube/roundcube-postgresql-17-cluster + index: 2 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/roundcube/roundcube-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: roundcube-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/roundcube/roundcube-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: roundcube-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 24 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/searxng/Chart.yaml b/clusters/cl01tl/helm/searxng/Chart.yaml new file mode 100644 index 000000000..84c6145fb --- /dev/null +++ b/clusters/cl01tl/helm/searxng/Chart.yaml @@ -0,0 +1,20 @@ +apiVersion: v2 +name: searxng +version: 1.0.0 +description: Searxng +keywords: + - searxng + - search +home: https://wiki.alexlebens.dev/s/6c6da68a-8725-4439-93c8-990ce824be54 +sources: + - https://github.com/searxng/searxng + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: searxng + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/searxng.png +appVersion: 1.0.0 diff --git a/clusters/cl01tl/helm/searxng/templates/external-secret.yaml b/clusters/cl01tl/helm/searxng/templates/external-secret.yaml new file mode 100644 index 000000000..bb5ede8ad --- /dev/null +++ b/clusters/cl01tl/helm/searxng/templates/external-secret.yaml @@ -0,0 +1,85 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: searxng-api-config-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: searxng-api-config-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: settings.yml + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/searxng/api/config + metadataPolicy: None + property: settings.yml + - secretKey: limiter.toml + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/searxng/api/config + metadataPolicy: None + property: limiter.toml + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: searxng-browser-data-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: searxng-browser-data-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/searxng/searxng-browser-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/searxng/templates/http-route.yaml b/clusters/cl01tl/helm/searxng/templates/http-route.yaml new file mode 100644 index 000000000..205106b74 --- /dev/null +++ b/clusters/cl01tl/helm/searxng/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-searxng + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-searxng + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - searxng.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: searxng-browser + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/searxng/templates/redis-replication.yaml b/clusters/cl01tl/helm/searxng/templates/redis-replication.yaml new file mode 100644 index 000000000..21959b519 --- /dev/null +++ b/clusters/cl01tl/helm/searxng/templates/redis-replication.yaml @@ -0,0 +1,32 @@ +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: redis-replication-searxng + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-searxng + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + clusterSize: 3 + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + kubernetesConfig: + image: quay.io/opstree/redis:v8.0.3 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 128Mi + storage: + volumeClaimTemplate: + spec: + storageClassName: ceph-block + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + redisExporter: + enabled: true + image: quay.io/opstree/redis-exporter:v1.48.0 diff --git a/clusters/cl01tl/helm/searxng/templates/replication-source.yaml b/clusters/cl01tl/helm/searxng/templates/replication-source.yaml new file mode 100644 index 000000000..0c572c2e6 --- /dev/null +++ b/clusters/cl01tl/helm/searxng/templates/replication-source.yaml @@ -0,0 +1,25 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: searxng-browser-data-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: searxng-browser-data-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: searxng-browser-data + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: searxng-browser-data-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/searxng/templates/service-monitor.yaml b/clusters/cl01tl/helm/searxng/templates/service-monitor.yaml new file mode 100644 index 000000000..ebb5165f1 --- /dev/null +++ b/clusters/cl01tl/helm/searxng/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: redis-replication-searxng + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-searxng + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + redis-operator: "true" + env: production +spec: + selector: + matchLabels: + redis_setup_type: replication + endpoints: + - port: redis-exporter + interval: 30s + scrapeTimeout: 10s diff --git a/clusters/cl01tl/helm/searxng/values.yaml b/clusters/cl01tl/helm/searxng/values.yaml new file mode 100644 index 000000000..011e6b7b6 --- /dev/null +++ b/clusters/cl01tl/helm/searxng/values.yaml @@ -0,0 +1,113 @@ +searxng: + controllers: + api: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: searxng/searxng + tag: latest@sha256:0124d32d77e0c7360d0b85f5d91882d1837e6ceb243c82e190f5d7e9f1401334 + pullPolicy: IfNotPresent + env: + - name: SEARXNG_BASE_URL + value: http://searxng-api.searxng:8080 + - name: SEARXNG_QUERY_URL + value: http://searxng-api.searxng:8080/search?q= + - name: SEARXNG_HOSTNAME + value: searxng-api.searxng + - name: UWSGI_WORKERS + value: 4 + - name: UWSGI_THREADS + value: 4 + - name: ENABLE_RAG_WEB_SEARCH + value: true + - name: RAG_WEB_SEARCH_ENGINE + value: searxng + - name: RAG_WEB_SEARCH_RESULT_COUNT + value: 3 + - name: RAG_WEB_SEARCH_CONCURRENT_REQUESTS + value: 10 + resources: + requests: + cpu: 10m + memory: 256Mi + browser: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: searxng/searxng + tag: latest@sha256:0124d32d77e0c7360d0b85f5d91882d1837e6ceb243c82e190f5d7e9f1401334 + pullPolicy: IfNotPresent + env: + - name: SEARXNG_BASE_URL + value: https://searxng.alexlebens.net/ + - name: SEARXNG_QUERY_URL + value: https://searxng.alexlebens.net/search?q= + - name: SEARXNG_HOSTNAME + value: searxng.alexlebens.net + - name: SEARXNG_REDIS_URL + value: redis://redis-replication-searxng-master.searxng:6379/0 + - name: UWSGI_WORKERS + value: 4 + - name: UWSGI_THREADS + value: 4 + resources: + requests: + cpu: 10m + memory: 256Mi + service: + api: + controller: api + ports: + mail: + port: 8080 + targetPort: 8080 + protocol: HTTP + browser: + controller: browser + ports: + mail: + port: 80 + targetPort: 8080 + protocol: HTTP + persistence: + config: + enabled: true + type: secret + name: searxng-api-config-secret + advancedMounts: + api: + main: + - path: /etc/searxng/settings.yml + readOnly: true + mountPropagation: None + subPath: settings.yml + - path: /etc/searxng/limiter.toml + readOnly: true + mountPropagation: None + subPath: limiter.toml + api-data: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + advancedMounts: + api: + main: + - path: /etc/searxng + readOnly: false + browser-data: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + advancedMounts: + browser: + main: + - path: /etc/searxng + readOnly: false diff --git a/clusters/cl01tl/helm/site-documentation/Chart.yaml b/clusters/cl01tl/helm/site-documentation/Chart.yaml new file mode 100644 index 000000000..f4e151a34 --- /dev/null +++ b/clusters/cl01tl/helm/site-documentation/Chart.yaml @@ -0,0 +1,28 @@ +apiVersion: v2 +name: site-documentation +version: 1.0.0 +description: Site Documentation +keywords: + - site-documentation + - astro +home: https://wiki.alexlebens.dev/s/1c39adb6-e0c6-4b01-b71f-278631adf584 +sources: + - https://github.com/alexlebens/site-documentation + - https://github.com/withastro/astro + - https://github.com/cloudflare/cloudflared + - https://github.com/alexlebens/site-documentation/pkgs/container/site-documentation + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: site-documentation + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: cloudflared + alias: cloudflared-site + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 +icon: https://d21zlbwtcn424f.cloudfront.net/logo-new-round.png +appVersion: 0.8.1 diff --git a/clusters/cl01tl/helm/site-documentation/templates/external-secret.yaml b/clusters/cl01tl/helm/site-documentation/templates/external-secret.yaml new file mode 100644 index 000000000..31c8f9093 --- /dev/null +++ b/clusters/cl01tl/helm/site-documentation/templates/external-secret.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: site-documentation-cloudflared-api-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: site-documentation-cloudflared-api-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/site-documentation + metadataPolicy: None + property: token diff --git a/clusters/cl01tl/helm/site-documentation/values.yaml b/clusters/cl01tl/helm/site-documentation/values.yaml new file mode 100644 index 000000000..298ed57f1 --- /dev/null +++ b/clusters/cl01tl/helm/site-documentation/values.yaml @@ -0,0 +1,30 @@ +site-documentation: + global: + fullnameOverride: site-documentation + controllers: + main: + type: deployment + replicas: 3 + strategy: RollingUpdate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: harbor.alexlebens.net/images/site-documentation + tag: 0.0.3 + pullPolicy: IfNotPresent + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 4321 + protocol: HTTP +cloudflared-site: + name: cloudflared-site + existingSecretName: site-documentation-cloudflared-api-secret diff --git a/clusters/cl01tl/helm/site-profile/Chart.yaml b/clusters/cl01tl/helm/site-profile/Chart.yaml new file mode 100644 index 000000000..b61c8fe12 --- /dev/null +++ b/clusters/cl01tl/helm/site-profile/Chart.yaml @@ -0,0 +1,28 @@ +apiVersion: v2 +name: site-profile +version: 1.0.0 +description: Site Profile +keywords: + - site-profile + - astro +home: https://wiki.alexlebens.dev/s/1c39adb6-e0c6-4b01-b71f-278631adf584 +sources: + - https://github.com/alexlebens/site-profile + - https://github.com/withastro/astro + - https://github.com/cloudflare/cloudflared + - https://github.com/alexlebens/site-profile/pkgs/container/site-profile + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: site-profile + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: cloudflared + alias: cloudflared-site + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 +icon: https://d21zlbwtcn424f.cloudfront.net/logo-new-round.png +appVersion: 2.0.1 diff --git a/clusters/cl01tl/helm/site-profile/templates/external-secret.yaml b/clusters/cl01tl/helm/site-profile/templates/external-secret.yaml new file mode 100644 index 000000000..b81c01241 --- /dev/null +++ b/clusters/cl01tl/helm/site-profile/templates/external-secret.yaml @@ -0,0 +1,21 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: site-profile-cloudflared-api-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: site-profile-cloudflared-api-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/site-profile + metadataPolicy: None + property: token diff --git a/clusters/cl01tl/helm/site-profile/values.yaml b/clusters/cl01tl/helm/site-profile/values.yaml new file mode 100644 index 000000000..fcc887b78 --- /dev/null +++ b/clusters/cl01tl/helm/site-profile/values.yaml @@ -0,0 +1,30 @@ +site-profile: + global: + fullnameOverride: site-profile + controllers: + main: + type: deployment + replicas: 3 + strategy: RollingUpdate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: harbor.alexlebens.net/images/site-profile + tag: 2.1.0 + pullPolicy: IfNotPresent + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 4321 + protocol: HTTP +cloudflared-site: + name: cloudflared-site + existingSecretName: site-profile-cloudflared-api-secret diff --git a/clusters/cl01tl/helm/slskd/Chart.yaml b/clusters/cl01tl/helm/slskd/Chart.yaml new file mode 100644 index 000000000..233f4ea2f --- /dev/null +++ b/clusters/cl01tl/helm/slskd/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +name: slskd +version: 1.0.0 +description: slskd +keywords: + - slskd + - soularr + - lidarr + - music +home: https://wiki.alexlebens.dev/s/ea931f86-1e70-480c-8002-64380b267cd7 +sources: + - https://github.com/slskd/slskd + - https://github.com/mrusse/soularr + - https://hub.docker.com/r/slskd/slskd + - https://hub.docker.com/r/mrusse08/soularr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: slskd + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/slskd.png +appVersion: 0.22.5 diff --git a/clusters/cl01tl/helm/slskd/templates/external-secret.yaml b/clusters/cl01tl/helm/slskd/templates/external-secret.yaml new file mode 100644 index 000000000..0e35e7987 --- /dev/null +++ b/clusters/cl01tl/helm/slskd/templates/external-secret.yaml @@ -0,0 +1,67 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: slskd-config-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: slskd-config-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: slskd.yml + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/slskd/config + metadataPolicy: None + property: slskd.yml + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: soularr-config-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: soularr-config-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: config.ini + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/slskd/soularr + metadataPolicy: None + property: config.ini + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: slskd-wireguard-conf + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: slskd-wireguard-conf + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: private-key + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /protonvpn/conf/cl01tl + metadataPolicy: None + property: private-key diff --git a/clusters/cl01tl/helm/slskd/templates/http-route.yaml b/clusters/cl01tl/helm/slskd/templates/http-route.yaml new file mode 100644 index 000000000..5701ed24c --- /dev/null +++ b/clusters/cl01tl/helm/slskd/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-slskd + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-slskd + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - slskd.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: slskd + port: 5030 + weight: 100 diff --git a/clusters/cl01tl/helm/slskd/templates/namespace.yaml b/clusters/cl01tl/helm/slskd/templates/namespace.yaml new file mode 100644 index 000000000..9793bc56d --- /dev/null +++ b/clusters/cl01tl/helm/slskd/templates/namespace.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: slskd + labels: + app.kubernetes.io/name: slskd + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + pod-security.kubernetes.io/audit: privileged + pod-security.kubernetes.io/enforce: privileged + pod-security.kubernetes.io/warn: privileged diff --git a/clusters/cl01tl/helm/slskd/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/slskd/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..b44e26d30 --- /dev/null +++ b/clusters/cl01tl/helm/slskd/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: slskd-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: slskd-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: slskd-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/slskd/templates/persistent-volume.yaml b/clusters/cl01tl/helm/slskd/templates/persistent-volume.yaml new file mode 100644 index 000000000..3e234f75a --- /dev/null +++ b/clusters/cl01tl/helm/slskd/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: slskd-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: slskd-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/slskd/templates/service-monitor.yaml b/clusters/cl01tl/helm/slskd/templates/service-monitor.yaml new file mode 100644 index 000000000..caf82f4ee --- /dev/null +++ b/clusters/cl01tl/helm/slskd/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: slskd + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: slskd + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: slskd + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: http + interval: 3m + scrapeTimeout: 1m + path: /metrics diff --git a/clusters/cl01tl/helm/slskd/values.yaml b/clusters/cl01tl/helm/slskd/values.yaml new file mode 100644 index 000000000..bbd10ebe1 --- /dev/null +++ b/clusters/cl01tl/helm/slskd/values.yaml @@ -0,0 +1,153 @@ +slskd: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + initContainers: + init-sysctl: + image: + repository: busybox + tag: 1.37.0 + pullPolicy: IfNotPresent + securityContext: + privileged: True + resources: + requests: + cpu: 10m + memory: 128Mi + command: + - /bin/sh + args: + - -ec + - | + sysctl -w net.ipv4.ip_forward=1; + sysctl -w net.ipv6.conf.all.disable_ipv6=1 + containers: + main: + image: + repository: slskd/slskd + tag: 0.24.0 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + - name: SLSKD_UMASK + value: 000 + resources: + requests: + cpu: 100m + memory: 512Mi + gluetun: + image: + repository: ghcr.io/qdm12/gluetun + tag: v3.40.3@sha256:ef4a44819a60469682c7b5e69183e6401171891feaa60186652d292c59e41b30 + pullPolicy: IfNotPresent + env: + - name: VPN_SERVICE_PROVIDER + value: protonvpn + - name: VPN_TYPE + value: wireguard + - name: WIREGUARD_PRIVATE_KEY + valueFrom: + secretKeyRef: + name: slskd-wireguard-conf + key: private-key + - name: VPN_PORT_FORWARDING + value: "on" + - name: PORT_FORWARD_ONLY + value: "on" + - name: FIREWALL_OUTBOUND_SUBNETS + value: 192.168.1.0/24,10.244.0.0/16 + - name: FIREWALL_INPUT_PORTS + value: 5030,50300 + - name: DOT + value: "off" + securityContext: + privileged: true + capabilities: + add: + - NET_ADMIN + - SYS_MODULE + resources: + limits: + devic.es/tun: "1" + requests: + devic.es/tun: "1" + cpu: 10m + memory: 128Mi + soularr: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: mrusse08/soularr + tag: latest@sha256:71a0b9e5a522d76bb0ffdb6d720d681fde22417b3a5acc9ecae61c89d05d8afc + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + - name: SCRIPT_INTERVAL + value: 300 + resources: + requests: + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 5030 + targetPort: 5030 + protocol: HTTP + persistence: + slskd-config: + enabled: true + type: secret + name: slskd-config-secret + advancedMounts: + main: + main: + - path: /app/slskd.yml + readOnly: true + mountPropagation: None + subPath: slskd.yml + soularr-config: + enabled: true + type: secret + name: soularr-config-secret + advancedMounts: + soularr: + main: + - path: /data/config.ini + readOnly: true + mountPropagation: None + subPath: config.ini + data: + existingClaim: slskd-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false + soularr: + main: + - path: /mnt/store + readOnly: false diff --git a/clusters/cl01tl/helm/sonarr-4k/Chart.yaml b/clusters/cl01tl/helm/sonarr-4k/Chart.yaml new file mode 100644 index 000000000..441c8912d --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-4k/Chart.yaml @@ -0,0 +1,33 @@ +apiVersion: v2 +name: sonarr-4k +version: 1.0.0 +description: Sonarr 4K +keywords: + - sonarr + - servarr + - tv shows + - 4k + - metrics +home: https://wiki.alexlebens.dev/s/3f8f5392-2e05-4bff-a798-7faf1bb24991 +sources: + - https://github.com/Sonarr/Sonarr + - https://github.com/linuxserver/docker-sonarr + - https://github.com/onedr0p/exportarr + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/linuxserver/docker-sonarr/pkgs/container/sonarr + - https://github.com/onedr0p/exportarr/pkgs/container/exportarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: sonarr-4k + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/sonarr.png +appVersion: 4.0.14 diff --git a/clusters/cl01tl/helm/sonarr-4k/templates/external-secret.yaml b/clusters/cl01tl/helm/sonarr-4k/templates/external-secret.yaml new file mode 100644 index 000000000..423b502df --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-4k/templates/external-secret.yaml @@ -0,0 +1,122 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: sonarr-4k-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-4k-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/sonarr4-4k/sonarr4-4k-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: sonarr-4k-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-4k-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: sonarr-4k-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-4k-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/sonarr-4k/templates/http-route.yaml b/clusters/cl01tl/helm/sonarr-4k/templates/http-route.yaml new file mode 100644 index 000000000..bdfd2a4f8 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-4k/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-sonarr-4k + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-sonarr-4k + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - sonarr-4k.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: sonarr-4k + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/sonarr-4k/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/sonarr-4k/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..388857422 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-4k/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: sonarr-4k-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-4k-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: sonarr-4k-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/sonarr-4k/templates/persistent-volume.yaml b/clusters/cl01tl/helm/sonarr-4k/templates/persistent-volume.yaml new file mode 100644 index 000000000..8049c36c9 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-4k/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: sonarr-4k-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-4k-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/sonarr-4k/templates/prometheus-rule.yaml b/clusters/cl01tl/helm/sonarr-4k/templates/prometheus-rule.yaml new file mode 100644 index 000000000..407d04562 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-4k/templates/prometheus-rule.yaml @@ -0,0 +1,32 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: sonarr-4k + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-4k + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + groups: + - name: sonarr-4k + rules: + - alert: ExportarrAbsent + annotations: + description: Sonarr 4K Exportarr has disappeared from Prometheus + service discovery. + summary: Exportarr is down. + expr: | + absent(up{job=~".*sonarr-4k.*"} == 1) + for: 5m + labels: + severity: critical + - alert: Sonarr4KDown + annotations: + description: Sonarr 4K service is down. + summary: Sonarr 4K is down. + expr: | + sonarr_4k_system_status{job=~".*sonarr-4k.*"} == 0 + for: 5m + labels: + severity: critical diff --git a/clusters/cl01tl/helm/sonarr-4k/templates/replication-source.yaml b/clusters/cl01tl/helm/sonarr-4k/templates/replication-source.yaml new file mode 100644 index 000000000..998e9b558 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-4k/templates/replication-source.yaml @@ -0,0 +1,30 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: sonarr-4k-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-4k-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: sonarr-4k-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: sonarr-4k-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/sonarr-4k/templates/service-monitor.yaml b/clusters/cl01tl/helm/sonarr-4k/templates/service-monitor.yaml new file mode 100644 index 000000000..3b87474f0 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-4k/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: sonarr-4k + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-4k + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: sonarr-4k + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: metrics + interval: 3m + scrapeTimeout: 1m + path: /metrics diff --git a/clusters/cl01tl/helm/sonarr-4k/values.yaml b/clusters/cl01tl/helm/sonarr-4k/values.yaml new file mode 100644 index 000000000..56b0a7ef7 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-4k/values.yaml @@ -0,0 +1,148 @@ +sonarr-4k: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: ghcr.io/linuxserver/sonarr + tag: 4.0.16@sha256:60e5edcac39172294ad22d55d1b08c2c0a9fe658cad2f2c4d742ae017d7874de + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + resources: + requests: + cpu: 10m + memory: 256Mi + metrics: + image: + repository: ghcr.io/onedr0p/exportarr + tag: v2.3.0 + pullPolicy: IfNotPresent + args: ["sonarr"] + env: + - name: URL + value: http://localhost + - name: CONFIG + value: /config/config.xml + - name: PORT + value: 9794 + - name: ENABLE_ADDITIONAL_METRICS + value: false + - name: ENABLE_UNKNOWN_QUEUE_ITEMS + value: false + resources: + requests: + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8989 + protocol: HTTP + metrics: + port: 9794 + targetPort: 9794 + protocol: TCP + persistence: + config: + forceRename: sonarr-4k-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 20Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + metrics: + - path: /config + readOnly: true + media: + existingClaim: sonarr-4k-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false +postgres-17-cluster: + nameOverride: sonarr4-4k-postgresql-17 + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + resources: + requests: + memory: 512Mi + monitoring: + enabled: true + prometheusRule: + enabled: true + initdb: + postInitSQL: + - CREATE DATABASE "sonarr-main" OWNER "app"; + - CREATE DATABASE "sonarr-log" OWNER "app"; + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/sonarr-4k/sonarr4-4k-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: sonarr-4k-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/sonarr4-4k/sonarr4-4k-postgresql-17-cluster + index: 1 + endpointCredentials: sonarr-4k-postgresql-17-cluster-backup-secret + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/sonarr-4k/sonarr4-4k-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: sonarr-4k-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/sonarr-4k/sonarr4-4k-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: sonarr-4k-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 28 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/sonarr-anime/Chart.yaml b/clusters/cl01tl/helm/sonarr-anime/Chart.yaml new file mode 100644 index 000000000..f0a05f23e --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-anime/Chart.yaml @@ -0,0 +1,32 @@ +apiVersion: v2 +name: sonarr-anime +version: 1.0.0 +description: Sonarr Anime +keywords: + - sonarr + - servarr + - anime + - metrics +home: https://wiki.alexlebens.dev/s/3f8f5392-2e05-4bff-a798-7faf1bb24991 +sources: + - https://github.com/Sonarr/Sonarr + - https://github.com/linuxserver/docker-sonarr + - https://github.com/onedr0p/exportarr + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/linuxserver/docker-sonarr/pkgs/container/sonarr + - https://github.com/onedr0p/exportarr/pkgs/container/exportarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: sonarr-anime + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/sonarr.png +appVersion: 4.0.14 diff --git a/clusters/cl01tl/helm/sonarr-anime/templates/external-secret.yaml b/clusters/cl01tl/helm/sonarr-anime/templates/external-secret.yaml new file mode 100644 index 000000000..781cce519 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-anime/templates/external-secret.yaml @@ -0,0 +1,122 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: sonarr-anime-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-anime-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/sonarr4-anime/sonarr4-anime-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: sonarr-anime-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-anime-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: sonarr-anime-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-anime-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/sonarr-anime/templates/http-route.yaml b/clusters/cl01tl/helm/sonarr-anime/templates/http-route.yaml new file mode 100644 index 000000000..1b468f31c --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-anime/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-sonarr-anime + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-sonarr-anime + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - sonarr-anime.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: sonarr-anime + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/sonarr-anime/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/sonarr-anime/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..e0e63952a --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-anime/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: sonarr-anime-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-anime-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: sonarr-anime-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/sonarr-anime/templates/persistent-volume.yaml b/clusters/cl01tl/helm/sonarr-anime/templates/persistent-volume.yaml new file mode 100644 index 000000000..3ee8f4c63 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-anime/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: sonarr-anime-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-anime-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/sonarr-anime/templates/prometheus-rule.yaml b/clusters/cl01tl/helm/sonarr-anime/templates/prometheus-rule.yaml new file mode 100644 index 000000000..dbcc8e998 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-anime/templates/prometheus-rule.yaml @@ -0,0 +1,32 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: sonarr-anime + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-anime + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + groups: + - name: sonarr-anime + rules: + - alert: ExportarrAbsent + annotations: + description: Sonarr Anime Exportarr has disappeared from Prometheus + service discovery. + summary: Exportarr is down. + expr: | + absent(up{job=~".*sonarr-anime.*"} == 1) + for: 5m + labels: + severity: critical + - alert: SonarrAnimeDown + annotations: + description: Sonarr Anime service is down. + summary: Sonarr Anime is down. + expr: | + sonarr_anime_system_status{job=~".*sonarr-anime.*"} == 0 + for: 5m + labels: + severity: critical diff --git a/clusters/cl01tl/helm/sonarr-anime/templates/replication-source.yaml b/clusters/cl01tl/helm/sonarr-anime/templates/replication-source.yaml new file mode 100644 index 000000000..59ad2f218 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-anime/templates/replication-source.yaml @@ -0,0 +1,30 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: sonarr-anime-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-anime-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: sonarr-anime-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: sonarr-anime-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/sonarr-anime/templates/service-monitor.yaml b/clusters/cl01tl/helm/sonarr-anime/templates/service-monitor.yaml new file mode 100644 index 000000000..6e46f252a --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-anime/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: sonarr-anime + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-anime + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: sonarr-anime + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: metrics + interval: 3m + scrapeTimeout: 1m + path: /metrics diff --git a/clusters/cl01tl/helm/sonarr-anime/values.yaml b/clusters/cl01tl/helm/sonarr-anime/values.yaml new file mode 100644 index 000000000..5f4939f8e --- /dev/null +++ b/clusters/cl01tl/helm/sonarr-anime/values.yaml @@ -0,0 +1,148 @@ +sonarr-anime: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: ghcr.io/linuxserver/sonarr + tag: 4.0.16@sha256:60e5edcac39172294ad22d55d1b08c2c0a9fe658cad2f2c4d742ae017d7874de + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + resources: + requests: + cpu: 10m + memory: 256Mi + metrics: + image: + repository: ghcr.io/onedr0p/exportarr + tag: v2.3.0 + pullPolicy: IfNotPresent + args: ["sonarr"] + env: + - name: URL + value: http://localhost + - name: CONFIG + value: /config/config.xml + - name: PORT + value: 9794 + - name: ENABLE_ADDITIONAL_METRICS + value: false + - name: ENABLE_UNKNOWN_QUEUE_ITEMS + value: false + resources: + requests: + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8989 + protocol: HTTP + metrics: + port: 9794 + targetPort: 9794 + protocol: TCP + persistence: + config: + forceRename: sonarr-anime-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 20Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + metrics: + - path: /config + readOnly: true + media: + existingClaim: sonarr-anime-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false +postgres-17-cluster: + nameOverride: sonarr4-anime-postgresql-17 + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + resources: + requests: + memory: 512Mi + monitoring: + enabled: true + prometheusRule: + enabled: true + initdb: + postInitSQL: + - CREATE DATABASE "sonarr-main" OWNER "app"; + - CREATE DATABASE "sonarr-log" OWNER "app"; + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/sonarr-anime/sonarr4-anime-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: sonarr-anime-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/sonarr4-anime/sonarr4-anime-postgresql-17-cluster + index: 1 + endpointCredentials: sonarr-anime-postgresql-17-cluster-backup-secret + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/sonarr-anime/sonarr4-anime-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: sonarr-anime-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/sonarr-anime/sonarr4-anime-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: sonarr-anime-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 30 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/sonarr/Chart.yaml b/clusters/cl01tl/helm/sonarr/Chart.yaml new file mode 100644 index 000000000..21b6dd13d --- /dev/null +++ b/clusters/cl01tl/helm/sonarr/Chart.yaml @@ -0,0 +1,32 @@ +apiVersion: v2 +name: sonarr +version: 1.0.0 +description: Sonarr +keywords: + - sonarr + - servarr + - tv shows + - metrics +home: https://wiki.alexlebens.dev/s/3f8f5392-2e05-4bff-a798-7faf1bb24991 +sources: + - https://github.com/Sonarr/Sonarr + - https://github.com/linuxserver/docker-sonarr + - https://github.com/onedr0p/exportarr + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/linuxserver/docker-sonarr/pkgs/container/sonarr + - https://github.com/onedr0p/exportarr/pkgs/container/exportarr + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: sonarr + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/sonarr.png +appVersion: 4.0.14 diff --git a/clusters/cl01tl/helm/sonarr/templates/external-secret.yaml b/clusters/cl01tl/helm/sonarr/templates/external-secret.yaml new file mode 100644 index 000000000..71e637fa0 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr/templates/external-secret.yaml @@ -0,0 +1,122 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: sonarr-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/sonarr4/sonarr4-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: sonarr-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: sonarr-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/sonarr/templates/http-route.yaml b/clusters/cl01tl/helm/sonarr/templates/http-route.yaml new file mode 100644 index 000000000..dccafa675 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-sonarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-sonarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - sonarr.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: sonarr + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/sonarr/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/sonarr/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..72cf49562 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: sonarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: sonarr-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/sonarr/templates/persistent-volume.yaml b/clusters/cl01tl/helm/sonarr/templates/persistent-volume.yaml new file mode 100644 index 000000000..a23f24017 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: sonarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/sonarr/templates/prometheus-rule.yaml b/clusters/cl01tl/helm/sonarr/templates/prometheus-rule.yaml new file mode 100644 index 000000000..5459fd7c3 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr/templates/prometheus-rule.yaml @@ -0,0 +1,32 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: sonarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + groups: + - name: sonarr + rules: + - alert: ExportarrAbsent + annotations: + description: Sonarr Exportarr has disappeared from Prometheus + service discovery. + summary: Exportarr is down. + expr: | + absent(up{job=~".*sonarr.*"} == 1) + for: 5m + labels: + severity: critical + - alert: SonarrDown + annotations: + description: Sonarr service is down. + summary: Sonarr is down. + expr: | + sonarr_system_status{job=~".*sonarr.*"} == 0 + for: 5m + labels: + severity: critical diff --git a/clusters/cl01tl/helm/sonarr/templates/replication-source.yaml b/clusters/cl01tl/helm/sonarr/templates/replication-source.yaml new file mode 100644 index 000000000..3116d7605 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr/templates/replication-source.yaml @@ -0,0 +1,30 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: sonarr-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: sonarr-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: sonarr-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + moverSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/sonarr/templates/service-monitor.yaml b/clusters/cl01tl/helm/sonarr/templates/service-monitor.yaml new file mode 100644 index 000000000..612b0af5e --- /dev/null +++ b/clusters/cl01tl/helm/sonarr/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: sonarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: sonarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: sonarr + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: metrics + interval: 3m + scrapeTimeout: 1m + path: /metrics diff --git a/clusters/cl01tl/helm/sonarr/values.yaml b/clusters/cl01tl/helm/sonarr/values.yaml new file mode 100644 index 000000000..2f82a1f15 --- /dev/null +++ b/clusters/cl01tl/helm/sonarr/values.yaml @@ -0,0 +1,149 @@ +sonarr: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + pod: + securityContext: + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + containers: + main: + image: + repository: ghcr.io/linuxserver/sonarr + tag: 4.0.16@sha256:60e5edcac39172294ad22d55d1b08c2c0a9fe658cad2f2c4d742ae017d7874de + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: 1000 + - name: PGID + value: 1000 + resources: + requests: + cpu: 100m + memory: 256Mi + metrics: + image: + repository: ghcr.io/onedr0p/exportarr + tag: v2.3.0 + pullPolicy: IfNotPresent + args: ["sonarr"] + env: + - name: URL + value: http://localhost + - name: CONFIG + value: /config/config.xml + - name: PORT + value: 9794 + - name: ENABLE_ADDITIONAL_METRICS + value: false + - name: ENABLE_UNKNOWN_QUEUE_ITEMS + value: false + resources: + requests: + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8989 + protocol: HTTP + metrics: + port: 9794 + targetPort: 9794 + protocol: TCP + persistence: + config: + forceRename: sonarr-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 20Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + metrics: + - path: /config + readOnly: true + media: + existingClaim: sonarr-nfs-storage + advancedMounts: + main: + main: + - path: /mnt/store + readOnly: false +postgres-17-cluster: + nameOverride: sonarr4-postgresql-17 + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + resources: + requests: + memory: 1Gi + cpu: 200m + initdb: + postInitSQL: + - CREATE DATABASE "sonarr-main" OWNER "app"; + - CREATE DATABASE "sonarr-log" OWNER "app"; + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/sonarr/sonarr4-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: sonarr-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/sonarr4/sonarr4-postgresql-17-cluster + index: 1 + endpointCredentials: sonarr-postgresql-17-cluster-backup-secret + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/sonarr/sonarr4-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: sonarr-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/sonarr/sonarr4-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: sonarr-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 26 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/tautulli/Chart.yaml b/clusters/cl01tl/helm/tautulli/Chart.yaml new file mode 100644 index 000000000..b14d2d14b --- /dev/null +++ b/clusters/cl01tl/helm/tautulli/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: tautulli +version: 1.0.0 +description: Tautulli +keywords: + - tautulli + - plex +home: https://wiki.alexlebens.dev/s/b2f5d20a-b3c2-4e7a-b550-7b2855264408 +sources: + - https://github.com/Tautulli/Tautulli + - https://github.com/Tautulli/Tautulli/pkgs/container/tautulli + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: tautulli + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/tautulli.png +appVersion: v2.15.2 diff --git a/clusters/cl01tl/helm/tautulli/templates/external-secret.yaml b/clusters/cl01tl/helm/tautulli/templates/external-secret.yaml new file mode 100644 index 000000000..e6f3ad704 --- /dev/null +++ b/clusters/cl01tl/helm/tautulli/templates/external-secret.yaml @@ -0,0 +1,55 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: tautulli-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tautulli-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/tautulli/tautulli-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/tautulli/templates/http-route.yaml b/clusters/cl01tl/helm/tautulli/templates/http-route.yaml new file mode 100644 index 000000000..e2567b045 --- /dev/null +++ b/clusters/cl01tl/helm/tautulli/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-tautulli + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-tautulli + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - tautulli.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: tautulli + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/tautulli/templates/replication-source.yaml b/clusters/cl01tl/helm/tautulli/templates/replication-source.yaml new file mode 100644 index 000000000..00e248f38 --- /dev/null +++ b/clusters/cl01tl/helm/tautulli/templates/replication-source.yaml @@ -0,0 +1,25 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: tautulli-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tautulli-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: tautulli-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: tautulli-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/tautulli/values.yaml b/clusters/cl01tl/helm/tautulli/values.yaml new file mode 100644 index 000000000..e666f5496 --- /dev/null +++ b/clusters/cl01tl/helm/tautulli/values.yaml @@ -0,0 +1,148 @@ +tautulli: + controllers: + main: + type: deployment + annotations: + reloader.stakater.com/auto: "true" + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/tautulli/tautulli + tag: v2.16.0 + pullPolicy: IfNotPresent + env: + - name: PUID + value: 1001 + - name: GUID + value: 1001 + - name: TZ + value: US/Central + resources: + requests: + cpu: 10m + memory: 128Mi + configMaps: + scripts: + enabled: true + data: + select_tmdb_poster.py: | + #!/usr/bin/env python + # -*- coding: utf-8 -*- + + ''' + Description: Selects the default TMDB poster if no poster is selected + or the current poster is from Gracenote. + Author: /u/SwiftPanda16 + Requires: plexapi + Usage: + * Change the posters for an entire library: + python select_tmdb_poster.py --library "Movies" + + * Change the poster for a specific item: + python select_tmdb_poster.py --rating_key 1234 + + * By default locked posters are skipped. To update locked posters: + python select_tmdb_poster.py --library "Movies" --include_locked + + Tautulli script trigger: + * Notify on recently added + Tautulli script conditions: + * Filter which media to select the poster. Examples: + [ Media Type | is | movie ] + Tautulli script arguments: + * Recently Added: + --rating_key {rating_key} + ''' + + import argparse + import os + import plexapi.base + from plexapi.server import PlexServer + plexapi.base.USER_DONT_RELOAD_FOR_KEYS.add('fields') + + + # Environmental Variables + PLEX_URL = os.getenv('PLEX_URL') + PLEX_TOKEN = os.getenv('PLEX_TOKEN') + + + def select_tmdb_poster_library(library, include_locked=False): + for item in library.all(includeGuids=False): + # Only reload for fields + item.reload(**{k: 0 for k, v in item._INCLUDES.items()}) + select_tmdb_poster_item(item, include_locked=include_locked) + + + def select_tmdb_poster_item(item, include_locked=False): + if item.isLocked('thumb') and not include_locked: # PlexAPI 4.5.10 + print(f"Locked poster for {item.title}. Skipping.") + return + + posters = item.posters() + selected_poster = next((p for p in posters if p.selected), None) + + if selected_poster is None: + print(f"WARNING: No poster selected for {item.title}.") + else: + skipping = ' Skipping.' if selected_poster.provider != 'gracenote' else '' + print(f"Poster provider is '{selected_poster.provider}' for {item.title}.{skipping}") + + if posters and (selected_poster is None or selected_poster.provider == 'gracenote'): + # Fallback to first poster if no TMDB posters are available + tmdb_poster = next((p for p in posters if p.provider == 'tmdb'), posters[0]) + # Selecting the poster automatically locks it + tmdb_poster.select() + print(f"Selected {tmdb_poster.provider} poster for {item.title}.") + + + if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--rating_key', type=int) + parser.add_argument('--library') + parser.add_argument('--include_locked', action='store_true') + opts = parser.parse_args() + + plex = PlexServer(PLEX_URL, PLEX_TOKEN) + + if opts.rating_key: + item = plex.fetchItem(opts.rating_key) + select_tmdb_poster_item(item, opts.include_locked) + elif opts.library: + library = plex.library.section(opts.library) + select_tmdb_poster_library(library, opts.include_locked) + else: + print("No --rating_key or --library specified. Exiting.") + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8181 + protocol: HTTP + persistence: + config: + forceRename: tautulli-config + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /config + readOnly: false + scripts: + enabled: true + type: configMap + name: tautulli-scripts + advancedMounts: + main: + main: + - path: /config/scripts/select_tmdb_poster.py + readOnly: true + mountPropagation: None + subPath: select_tmdb_poster.py diff --git a/clusters/cl01tl/helm/tdarr/Chart.yaml b/clusters/cl01tl/helm/tdarr/Chart.yaml new file mode 100644 index 000000000..c0ec75b8b --- /dev/null +++ b/clusters/cl01tl/helm/tdarr/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: tdarr +version: 1.0.0 +description: Tdarr +keywords: + - tdarr + - video + - transcode + - healthchecks +home: https://wiki.alexlebens.dev/s/0a8c0a10-7847-4081-8a4b-5e6ac4cb1d62 +sources: + - https://github.com/HaveAGitGat/Tdarr + - https://github.com/homeylab/tdarr-exporter + - https://github.com/haveagitgat/Tdarr/pkgs/container/tdarr + - https://hub.docker.com/r/homeylab/tdarr-exporter + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://github.com/homeylab/helm-charts/tree/main/charts/tdarr-exporter +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: tdarr + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: tdarr-exporter + version: 1.1.7 + repository: https://homeylab.github.io/helm-charts/ +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/tdarr.png +appVersion: 2.40.01 diff --git a/clusters/cl01tl/helm/tdarr/templates/external-secret.yaml b/clusters/cl01tl/helm/tdarr/templates/external-secret.yaml new file mode 100644 index 000000000..a974a5f0b --- /dev/null +++ b/clusters/cl01tl/helm/tdarr/templates/external-secret.yaml @@ -0,0 +1,112 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: tdarr-config-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tdarr-config-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/tdarr/tdarr-config" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: tdarr-server-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tdarr-server-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/tdarr/tdarr-server" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key diff --git a/clusters/cl01tl/helm/tdarr/templates/http-route.yaml b/clusters/cl01tl/helm/tdarr/templates/http-route.yaml new file mode 100644 index 000000000..ec80a2e81 --- /dev/null +++ b/clusters/cl01tl/helm/tdarr/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-tdarr + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-tdarr + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - tdarr.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: tdarr-web + port: 8265 + weight: 100 diff --git a/clusters/cl01tl/helm/tdarr/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/tdarr/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..f86557f72 --- /dev/null +++ b/clusters/cl01tl/helm/tdarr/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: tdarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tdarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: tdarr-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/tdarr/templates/persistent-volume.yaml b/clusters/cl01tl/helm/tdarr/templates/persistent-volume.yaml new file mode 100644 index 000000000..c3da6a310 --- /dev/null +++ b/clusters/cl01tl/helm/tdarr/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: tdarr-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tdarr-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/tdarr/templates/replication-source.yaml b/clusters/cl01tl/helm/tdarr/templates/replication-source.yaml new file mode 100644 index 000000000..dd58cd175 --- /dev/null +++ b/clusters/cl01tl/helm/tdarr/templates/replication-source.yaml @@ -0,0 +1,52 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: tdarr-config-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tdarr-config-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: tdarr-config + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: tdarr-config-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot + +--- +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: tdarr-server-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tdarr-server-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: tdarr-server + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: tdarr-server-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/tdarr/values.yaml b/clusters/cl01tl/helm/tdarr/values.yaml new file mode 100644 index 000000000..1160e0602 --- /dev/null +++ b/clusters/cl01tl/helm/tdarr/values.yaml @@ -0,0 +1,156 @@ +tdarr: + controllers: + server: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/haveagitgat/tdarr + tag: 2.58.02 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: "1001" + - name: PGID + value: "1001" + - name: UMASK_SET + value: "002" + - name: ffmpegVersion + value: "6" + - name: internalNode + value: "false" + - name: inContainer + value: "true" + - name: nodeName + value: tdarr-server + - name: serverIP + value: 0.0.0.0 + - name: serverPort + value: "8266" + - name: webUIPort + value: "8265" + resources: + requests: + cpu: 200m + memory: 1Gi + node: + type: daemonset + revisionHistoryLimit: 3 + pod: + nodeSelector: + intel.feature.node.kubernetes.io/gpu: "true" + containers: + main: + image: + repository: ghcr.io/haveagitgat/tdarr_node + tag: 2.58.02 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: PUID + value: "1001" + - name: PGID + value: "1001" + - name: UMASK_SET + value: "002" + - name: ffmpegVersion + value: "6" + - name: inContainer + value: "true" + - name: nodeName + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: serverIP + value: tdarr-api + - name: serverPort + value: "8266" + resources: + limits: + gpu.intel.com/i915: 1 + requests: + gpu.intel.com/i915: 1 + cpu: 10m + memory: 512Mi + service: + api: + controller: server + ports: + http: + port: 8266 + targetPort: 8266 + protocol: HTTP + web: + controller: server + ports: + http: + port: 8265 + targetPort: 8265 + protocol: HTTP + persistence: + config: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 50Gi + retain: true + advancedMounts: + server: + main: + - path: /app/configs + readOnly: false + server: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 50Gi + retain: true + advancedMounts: + server: + main: + - path: /app/server + readOnly: false + server-cache: + type: emptyDir + advancedMounts: + server: + main: + - path: /tcache + readOnly: false + node-cache: + type: emptyDir + advancedMounts: + node: + main: + - path: /tcache + readOnly: false + media: + existingClaim: tdarr-nfs-storage + advancedMounts: + server: + main: + - path: /mnt/store + readOnly: true + node: + main: + - path: /mnt/store + readOnly: true +tdarr-exporter: + image: + name: homeylab/tdarr-exporter + tag: 1.4.2 + metrics: + serviceMonitor: + enabled: true + settings: + config: + url: http://tdarr-web.tdarr:8265 + verify_ssl: false + resources: + requests: + cpu: 10m + memory: 256Mi diff --git a/clusters/cl01tl/helm/tubearchivist/Chart.yaml b/clusters/cl01tl/helm/tubearchivist/Chart.yaml new file mode 100644 index 000000000..8930ea092 --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: tubearchivist +version: 1.0.0 +description: Tube Archivist +keywords: + - tubearchivist + - download + - video + - youtube +home: https://wiki.alexlebens.dev/s/9a5f89bb-3cae-43ab-b651-d39f69a05e93 +sources: + - https://github.com/tubearchivist/tubearchivist + - https://github.com/elastic/elasticsearch + - https://hub.docker.com/r/bbilly1/tubearchivist + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: tubearchivist + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/tube-archivist.png +appVersion: v0.5.2 diff --git a/clusters/cl01tl/helm/tubearchivist/templates/elasticsearch.yaml b/clusters/cl01tl/helm/tubearchivist/templates/elasticsearch.yaml new file mode 100644 index 000000000..d9d2c4b76 --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/templates/elasticsearch.yaml @@ -0,0 +1,42 @@ +apiVersion: elasticsearch.k8s.elastic.co/v1 +kind: Elasticsearch +metadata: + name: elasticsearch-tubearchivist + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: elasticsearch-tubearchivist + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + version: 8.18.0 + auth: + fileRealm: + - secretName: tubearchivist-elasticsearch-secret + nodeSets: + - name: default + count: 1 + config: + node.store.allow_mmap: false + path.repo: /usr/share/elasticsearch/data/snapshot + podTemplate: + spec: + volumes: + - name: tubearchivist-snapshot-nfs-storage + nfs: + path: /volume2/Storage/TubeArchivist + server: synologybond.alexlebens.net + containers: + - name: elasticsearch + volumeMounts: + - name: tubearchivist-snapshot-nfs-storage + mountPath: /usr/share/elasticsearch/data/snapshot + volumeClaimTemplates: + - metadata: + name: elasticsearch-data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: ceph-block diff --git a/clusters/cl01tl/helm/tubearchivist/templates/external-secret.yaml b/clusters/cl01tl/helm/tubearchivist/templates/external-secret.yaml new file mode 100644 index 000000000..bdd4d9d91 --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/templates/external-secret.yaml @@ -0,0 +1,88 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: tubearchivist-config-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tubearchivist-config-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ELASTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/tubearchivist/env + metadataPolicy: None + property: ELASTIC_PASSWORD + - secretKey: TA_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/tubearchivist/env + metadataPolicy: None + property: TA_PASSWORD + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: tubearchivist-elasticsearch-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tubearchivist-elasticsearch-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: username + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/tubearchivist/elasticsearch + metadataPolicy: None + property: username + - secretKey: password + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/tubearchivist/elasticsearch + metadataPolicy: None + property: password + - secretKey: roles + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/tubearchivist/elasticsearch + metadataPolicy: None + property: roles + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: tubearchivist-wireguard-conf + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tubearchivist-wireguard-conf + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: private-key + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /protonvpn/conf/cl01tl + metadataPolicy: None + property: private-key diff --git a/clusters/cl01tl/helm/tubearchivist/templates/http-route.yaml b/clusters/cl01tl/helm/tubearchivist/templates/http-route.yaml new file mode 100644 index 000000000..daeddaf08 --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-tubearchivist + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-tubearchivist + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - tubearchivist.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: tubearchivist + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/tubearchivist/templates/namespace.yaml b/clusters/cl01tl/helm/tubearchivist/templates/namespace.yaml new file mode 100644 index 000000000..0f2687e94 --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/templates/namespace.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: tubearchivist + labels: + app.kubernetes.io/name: tubearchivist + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + pod-security.kubernetes.io/audit: privileged + pod-security.kubernetes.io/enforce: privileged + pod-security.kubernetes.io/warn: privileged diff --git a/clusters/cl01tl/helm/tubearchivist/templates/persistent-volume-claim.yaml b/clusters/cl01tl/helm/tubearchivist/templates/persistent-volume-claim.yaml new file mode 100644 index 000000000..6c8dcc160 --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/templates/persistent-volume-claim.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: tubearchivist-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tubearchivist-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + volumeName: tubearchivist-nfs-storage + storageClassName: nfs-client + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi diff --git a/clusters/cl01tl/helm/tubearchivist/templates/persistent-volume.yaml b/clusters/cl01tl/helm/tubearchivist/templates/persistent-volume.yaml new file mode 100644 index 000000000..62bab667a --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/templates/persistent-volume.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: tubearchivist-nfs-storage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: tubearchivist-nfs-storage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + persistentVolumeReclaimPolicy: Retain + storageClassName: nfs-client + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + nfs: + path: /volume2/Storage/YouTube + server: synologybond.alexlebens.net + mountOptions: + - vers=4 + - minorversion=1 + - noac diff --git a/clusters/cl01tl/helm/tubearchivist/templates/redis-replication.yaml b/clusters/cl01tl/helm/tubearchivist/templates/redis-replication.yaml new file mode 100644 index 000000000..0be064303 --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/templates/redis-replication.yaml @@ -0,0 +1,32 @@ +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: redis-replication-tubearchivist + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-tubearchivist + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + clusterSize: 3 + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + kubernetesConfig: + image: quay.io/opstree/redis:v8.0.3 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 128Mi + storage: + volumeClaimTemplate: + spec: + storageClassName: ceph-block + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + redisExporter: + enabled: true + image: quay.io/opstree/redis-exporter:v1.48.0 diff --git a/clusters/cl01tl/helm/tubearchivist/templates/service-monitor.yaml b/clusters/cl01tl/helm/tubearchivist/templates/service-monitor.yaml new file mode 100644 index 000000000..cf9e8bb5c --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: redis-replication-tubearchivist + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-tubearchivist + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + redis-operator: "true" + env: production +spec: + selector: + matchLabels: + redis_setup_type: replication + endpoints: + - port: redis-exporter + interval: 30s + scrapeTimeout: 10s diff --git a/clusters/cl01tl/helm/tubearchivist/values.yaml b/clusters/cl01tl/helm/tubearchivist/values.yaml new file mode 100644 index 000000000..793d5a7f0 --- /dev/null +++ b/clusters/cl01tl/helm/tubearchivist/values.yaml @@ -0,0 +1,107 @@ +tubearchivist: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: bbilly1/tubearchivist + tag: v0.5.8 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: HOST_UID + value: 1000 + - name: HOST_GID + value: 1000 + - name: ES_URL + value: https://elasticsearch-tubearchivist-es-http.tubearchivist:9200 + - name: ES_DISABLE_VERIFY_SSL + value: true + - name: REDIS_CON + value: redis://redis-replication-tubearchivist-master.tubearchivist:6379 + - name: TA_HOST + value: https://tubearchivist.alexlebens.net http://tubearchivist.tubearchivist:80/ + - name: TA_PORT + value: 24000 + - name: TA_USERNAME + value: admin + envFrom: + - secretRef: + name: tubearchivist-config-secret + resources: + requests: + cpu: 10m + memory: 1Gi + gluetun: + image: + repository: ghcr.io/qdm12/gluetun + tag: v3.40.3@sha256:ef4a44819a60469682c7b5e69183e6401171891feaa60186652d292c59e41b30 + pullPolicy: IfNotPresent + env: + - name: VPN_SERVICE_PROVIDER + value: protonvpn + - name: VPN_TYPE + value: wireguard + - name: WIREGUARD_PRIVATE_KEY + valueFrom: + secretKeyRef: + name: tubearchivist-wireguard-conf + key: private-key + - name: VPN_PORT_FORWARDING + value: "on" + - name: PORT_FORWARD_ONLY + value: "on" + - name: FIREWALL_OUTBOUND_SUBNETS + value: 10.0.0.0/8 + - name: FIREWALL_INPUT_PORTS + value: 80,8000,24000 + - name: DOT + value: off + - name: DNS_KEEP_NAMESERVER + value: on + - name: DNS_PLAINTEXT_ADDRESS + value: 10.96.0.10 + securityContext: + privileged: True + capabilities: + add: + - NET_ADMIN + - SYS_MODULE + resources: + limits: + devic.es/tun: "1" + requests: + devic.es/tun: "1" + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 24000 + protocol: HTTP + persistence: + data: + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 40Gi + retain: true + advancedMounts: + main: + main: + - path: /cache + readOnly: false + youtube: + existingClaim: tubearchivist-nfs-storage + advancedMounts: + main: + main: + - path: /youtube + readOnly: false diff --git a/clusters/cl01tl/helm/vaultwarden/Chart.yaml b/clusters/cl01tl/helm/vaultwarden/Chart.yaml new file mode 100644 index 000000000..4c50b8034 --- /dev/null +++ b/clusters/cl01tl/helm/vaultwarden/Chart.yaml @@ -0,0 +1,34 @@ +apiVersion: v2 +name: vaultwarden +version: 1.0.0 +description: Vaultwarden +keywords: + - vaultwarden + - bitwarden + - password +home: https://wiki.alexlebens.dev/s/fecd00f9-ebce-43eb-b066-3721b15432e3 +sources: + - https://github.com/dani-garcia/vaultwarden + - https://github.com/cloudflare/cloudflared + - https://github.com/cloudnative-pg/cloudnative-pg + - https://hub.docker.com/r/vaultwarden/server + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/cloudflared + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: vaultwarden + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: cloudflared + alias: cloudflared + repository: oci://harbor.alexlebens.net/helm-charts + version: 1.23.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/vaultwarden.png +appVersion: 1.33.2 diff --git a/clusters/cl01tl/helm/vaultwarden/templates/external-secret.yaml b/clusters/cl01tl/helm/vaultwarden/templates/external-secret.yaml new file mode 100644 index 000000000..30d1165b4 --- /dev/null +++ b/clusters/cl01tl/helm/vaultwarden/templates/external-secret.yaml @@ -0,0 +1,145 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: vaultwarden-cloudflared-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: vaultwarden-cloudflared-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: cf-tunnel-token + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cloudflare/tunnels/vaultwarden + metadataPolicy: None + property: token + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: vaultwarden-data-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: vaultwarden-data-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + target: + template: + mergePolicy: Merge + engineVersion: v2 + data: + RESTIC_REPOSITORY: "{{ `{{ .BUCKET_ENDPOINT }}` }}/vaultwarden/vaultwarden-data" + data: + - secretKey: BUCKET_ENDPOINT + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: S3_BUCKET_ENDPOINT + - secretKey: RESTIC_PASSWORD + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: RESTIC_PASSWORD + - secretKey: AWS_DEFAULT_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/volsync/restic/config + metadataPolicy: None + property: AWS_DEFAULT_REGION + - secretKey: AWS_ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: access_key + - secretKey: AWS_SECRET_ACCESS_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/volsync-backups + metadataPolicy: None + property: secret_key + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: vaultwarden-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: vaultwarden-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: vaultwarden-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: vaultwarden-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/vaultwarden/templates/replication-source.yaml b/clusters/cl01tl/helm/vaultwarden/templates/replication-source.yaml new file mode 100644 index 000000000..a2ba4bcdd --- /dev/null +++ b/clusters/cl01tl/helm/vaultwarden/templates/replication-source.yaml @@ -0,0 +1,25 @@ +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: vaultwarden-data-backup-source + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: vaultwarden-data-backup-source + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + sourcePVC: vaultwarden-data + trigger: + schedule: 0 4 * * * + restic: + pruneIntervalDays: 7 + repository: vaultwarden-data-backup-secret + retain: + hourly: 1 + daily: 3 + weekly: 2 + monthly: 2 + yearly: 4 + copyMethod: Snapshot + storageClassName: ceph-block + volumeSnapshotClassName: ceph-blockpool-snapshot diff --git a/clusters/cl01tl/helm/vaultwarden/values.yaml b/clusters/cl01tl/helm/vaultwarden/values.yaml new file mode 100644 index 000000000..76d79709d --- /dev/null +++ b/clusters/cl01tl/helm/vaultwarden/values.yaml @@ -0,0 +1,107 @@ +vaultwarden: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: vaultwarden/server + tag: 1.34.3 + pullPolicy: IfNotPresent + env: + - name: DOMAIN + value: https://passwords.alexlebens.dev + - name: SIGNUPS_ALLOWED + value: "false" + - name: INVITATIONS_ALLOWED + value: "false" + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: vaultwarden-postgresql-17-cluster-app + key: uri + resources: + requests: + cpu: 10m + memory: 128Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 80 + protocol: HTTP + persistence: + config: + forceRename: vaultwarden-data + storageClass: ceph-block + accessMode: ReadWriteOnce + size: 5Gi + retain: true + advancedMounts: + main: + main: + - path: /data + readOnly: false +cloudflared: + existingSecretName: vaultwarden-cloudflared-secret +postgres-17-cluster: + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/vaultwarden/vaultwarden-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: vaultwarden-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/vaultwarden/vaultwarden-postgresql-17-cluster + index: 1 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/vaultwarden/vaultwarden-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: vaultwarden-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/vaultwarden/vaultwarden-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: vaultwarden-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 32 4 * * SAT" + # backupName: garage-remote diff --git a/clusters/cl01tl/helm/yamtrack/Chart.yaml b/clusters/cl01tl/helm/yamtrack/Chart.yaml new file mode 100644 index 000000000..e4f6f61a1 --- /dev/null +++ b/clusters/cl01tl/helm/yamtrack/Chart.yaml @@ -0,0 +1,28 @@ +apiVersion: v2 +name: yamtrack +version: 1.0.0 +description: Yamtrack +keywords: + - yamtrack + - media + - jellyfin +home: https://wiki.alexlebens.dev/s/74f31779-734e-42d0-852e-efd57ebdc797 +sources: + - https://github.com/FuzzyGrim/Yamtrack + - https://github.com/cloudnative-pg/cloudnative-pg + - https://github.com/FuzzyGrim/Yamtrack/pkgs/container/yamtrack + - https://github.com/bjw-s-labs/helm-charts/tree/main/charts/other/app-template + - https://gitea.alexlebens.dev/alexlebens/helm-charts/src/branch/main/charts/postgres-cluster +maintainers: + - name: alexlebens +dependencies: + - name: app-template + alias: yamtrack + repository: https://bjw-s-labs.github.io/helm-charts/ + version: 4.4.0 + - name: postgres-cluster + alias: postgres-17-cluster + version: 6.16.0 + repository: oci://harbor.alexlebens.net/helm-charts +icon: https://cdn.jsdelivr.net/gh/selfhst/icons/png/yamtrack.png +appVersion: 0.22.7 diff --git a/clusters/cl01tl/helm/yamtrack/templates/external-secret.yaml b/clusters/cl01tl/helm/yamtrack/templates/external-secret.yaml new file mode 100644 index 000000000..9ef41c193 --- /dev/null +++ b/clusters/cl01tl/helm/yamtrack/templates/external-secret.yaml @@ -0,0 +1,111 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: yamtrack-config-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: yamtrack-config-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: SECRET + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /cl01tl/yamtrack/config + metadataPolicy: None + property: SECRET + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: yamtrack-oidc-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: yamtrack-oidc-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: SOCIALACCOUNT_PROVIDERS + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /authentik/oidc/yamtrack + metadataPolicy: None + property: SOCIALACCOUNT_PROVIDERS + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: yamtrack-postgresql-17-cluster-backup-secret + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: yamtrack-postgresql-17-cluster-backup-secret + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: access + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /digital-ocean/home-infra/postgres-backups + metadataPolicy: None + property: secret + +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: yamtrack-postgresql-17-cluster-backup-secret-garage + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: yamtrack-postgresql-17-cluster-backup-secret-garage + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + secretStoreRef: + kind: ClusterSecretStore + name: vault + data: + - secretKey: ACCESS_KEY_ID + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_KEY_ID + - secretKey: ACCESS_SECRET_KEY + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_SECRET_KEY + - secretKey: ACCESS_REGION + remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /garage/home-infra/postgres-backups + metadataPolicy: None + property: ACCESS_REGION diff --git a/clusters/cl01tl/helm/yamtrack/templates/http-route.yaml b/clusters/cl01tl/helm/yamtrack/templates/http-route.yaml new file mode 100644 index 000000000..38b3fd466 --- /dev/null +++ b/clusters/cl01tl/helm/yamtrack/templates/http-route.yaml @@ -0,0 +1,28 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-yamtrack + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: http-route-yamtrack + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: traefik-gateway + namespace: traefik + hostnames: + - yamtrack.alexlebens.net + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - group: '' + kind: Service + name: yamtrack + port: 80 + weight: 100 diff --git a/clusters/cl01tl/helm/yamtrack/templates/redis-replication.yaml b/clusters/cl01tl/helm/yamtrack/templates/redis-replication.yaml new file mode 100644 index 000000000..96c57159c --- /dev/null +++ b/clusters/cl01tl/helm/yamtrack/templates/redis-replication.yaml @@ -0,0 +1,32 @@ +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: redis-replication-yamtrack + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-yamtrack + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} +spec: + clusterSize: 3 + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + kubernetesConfig: + image: quay.io/opstree/redis:v8.0.3 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 128Mi + storage: + volumeClaimTemplate: + spec: + storageClassName: ceph-block + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + redisExporter: + enabled: true + image: quay.io/opstree/redis-exporter:v1.48.0 diff --git a/clusters/cl01tl/helm/yamtrack/templates/service-monitor.yaml b/clusters/cl01tl/helm/yamtrack/templates/service-monitor.yaml new file mode 100644 index 000000000..e2538360a --- /dev/null +++ b/clusters/cl01tl/helm/yamtrack/templates/service-monitor.yaml @@ -0,0 +1,19 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: redis-replication-yamtrack + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: redis-replication-yamtrack + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ .Release.Name }} + redis-operator: "true" + env: production +spec: + selector: + matchLabels: + redis_setup_type: replication + endpoints: + - port: redis-exporter + interval: 30s + scrapeTimeout: 10s diff --git a/clusters/cl01tl/helm/yamtrack/values.yaml b/clusters/cl01tl/helm/yamtrack/values.yaml new file mode 100644 index 000000000..c3348a1b7 --- /dev/null +++ b/clusters/cl01tl/helm/yamtrack/values.yaml @@ -0,0 +1,127 @@ +yamtrack: + controllers: + main: + type: deployment + replicas: 1 + strategy: Recreate + revisionHistoryLimit: 3 + containers: + main: + image: + repository: ghcr.io/fuzzygrim/yamtrack + tag: 0.24.7 + pullPolicy: IfNotPresent + env: + - name: TZ + value: US/Central + - name: URLS + value: https://yamtrack.alexlebens.net + - name: REGISTRATION + value: false + - name: SOCIAL_PROVIDERS + value: allauth.socialaccount.providers.openid_connect + - name: SOCIALACCOUNT_PROVIDERS + valueFrom: + secretKeyRef: + name: yamtrack-oidc-secret + key: SOCIALACCOUNT_PROVIDERS + - name: SECRET + valueFrom: + secretKeyRef: + name: yamtrack-config-secret + key: SECRET + - name: REDIS_URL + value: redis://redis-replication-yamtrack-master.yamtrack:6379 + - name: DB_USER + valueFrom: + secretKeyRef: + name: yamtrack-postgresql-17-cluster-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: yamtrack-postgresql-17-cluster-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: yamtrack-postgresql-17-cluster-app + key: dbname + - name: DB_HOST + valueFrom: + secretKeyRef: + name: yamtrack-postgresql-17-cluster-app + key: host + - name: DB_PORT + valueFrom: + secretKeyRef: + name: yamtrack-postgresql-17-cluster-app + key: port + resources: + requests: + cpu: 10m + memory: 256Mi + service: + main: + controller: main + ports: + http: + port: 80 + targetPort: 8000 + protocol: HTTP +postgres-17-cluster: + mode: recovery + cluster: + storage: + storageClass: local-path + walStorage: + storageClass: local-path + monitoring: + enabled: true + prometheusRule: + enabled: true + recovery: + method: objectStore + objectStore: + destinationPath: s3://postgres-backups/cl01tl/yamtrack/yamtrack-postgresql-17-cluster + endpointURL: http://garage-main.garage:3900 + index: 1 + endpointCredentials: yamtrack-postgresql-17-cluster-backup-secret-garage + backup: + objectStore: + - name: external + destinationPath: s3://postgres-backups-ce540ddf106d186bbddca68a/cl01tl/yamtrack/yamtrack-postgresql-17-cluster + index: 2 + retentionPolicy: "30d" + isWALArchiver: false + - name: garage-local + destinationPath: s3://postgres-backups/cl01tl/yamtrack/yamtrack-postgresql-17-cluster + index: 1 + endpointURL: http://garage-main.garage:3900 + endpointCredentials: yamtrack-postgresql-17-cluster-backup-secret-garage + endpointCredentialsIncludeRegion: true + retentionPolicy: "3d" + isWALArchiver: true + # - name: garage-remote + # destinationPath: s3://postgres-backups/cl01tl/yamtrack/yamtrack-postgresql-17-cluster + # index: 1 + # endpointURL: https://garage-ps10rp.boreal-beaufort.ts.net:3900 + # endpointCredentials: yamtrack-postgresql-17-cluster-backup-secret-garage + # retentionPolicy: "30d" + # data: + # compression: bzip2 + # jobs: 2 + scheduledBackups: + - name: daily-backup + suspend: false + schedule: "0 0 0 * * *" + backupName: external + - name: live-backup + suspend: false + immediate: true + schedule: "0 0 0 * * *" + backupName: garage-local + # - name: weekly-backup + # suspend: false + # schedule: "0 34 4 * * SAT" + # backupName: garage-remote