From 34925cb94be49d7b5fb9f06d98b145fa5bb07daf Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Tue, 24 Feb 2026 14:23:45 -0800 Subject: [PATCH] Add kustomize images: transformer and configMapGenerator across services Move hardcoded image tags to kustomization.yaml images: sections (22 services) and replace hand-written ConfigMap manifests with configMapGenerator (12 services). Image tags are now centralized in kustomization.yaml, and generated ConfigMaps include content hashes that trigger automatic pod rollouts on config changes. New kustomization.yaml files for forgejo-runner and nvidia-device-plugin switch ArgoCD from directory mode to kustomize mode. Skipped: argocd (remote upstream), databases, external-secrets, grafana-config (cross-kustomization dashboards), immich (Helm), authentik blueprints (special YAML tags). Co-Authored-By: Claude Opus 4.6 --- argocd/manifests/alloy-k8s/config.alloy | 169 +++++++++++++++++ argocd/manifests/alloy-k8s/configmap.yaml | 176 ------------------ argocd/manifests/alloy-k8s/daemonset.yaml | 2 +- argocd/manifests/alloy-k8s/kustomization.yaml | 13 +- .../manifests/authentik/deployment-redis.yaml | 2 +- .../authentik/deployment-server.yaml | 2 +- .../authentik/deployment-worker.yaml | 2 +- argocd/manifests/authentik/kustomization.yaml | 5 + argocd/manifests/cv/deployment.yaml | 2 +- argocd/manifests/cv/kustomization.yaml | 3 + argocd/manifests/devpi/kustomization.yaml | 4 + argocd/manifests/devpi/statefulset.yaml | 2 +- argocd/manifests/docs/deployment.yaml | 2 +- argocd/manifests/docs/kustomization.yaml | 3 + argocd/manifests/forgejo-runner/config.yaml | 19 ++ .../manifests/forgejo-runner/configmap.yaml | 30 --- argocd/manifests/forgejo-runner/daemon.json | 3 + .../manifests/forgejo-runner/deployment.yaml | 4 +- .../forgejo-runner/kustomization.yaml | 21 +++ .../manifests/frigate/configmap-notify.yaml | 42 ----- argocd/manifests/frigate/configmap.yaml | 90 --------- .../manifests/frigate/deployment-notify.yaml | 2 +- argocd/manifests/frigate/deployment.yaml | 4 +- argocd/manifests/frigate/frigate-config.yml | 83 +++++++++ .../frigate/frigate-notify-config.yml | 35 ++++ argocd/manifests/frigate/kustomization.yaml | 18 +- argocd/manifests/grafana/configmap.yaml | 100 ---------- argocd/manifests/grafana/datasources.yaml | 34 ++++ argocd/manifests/grafana/deployment.yaml | 6 +- argocd/manifests/grafana/grafana.ini | 32 ++++ argocd/manifests/grafana/kustomization.yaml | 18 +- argocd/manifests/grafana/provider.yaml | 11 ++ argocd/manifests/homepage/bookmarks.yaml | 16 ++ argocd/manifests/homepage/configmap.yaml | 155 --------------- argocd/manifests/homepage/deployment.yaml | 2 +- argocd/manifests/homepage/docker.yaml | 0 argocd/manifests/homepage/kubernetes.yaml | 1 + argocd/manifests/homepage/kustomization.yaml | 15 +- argocd/manifests/homepage/services.yaml | 76 ++++++++ argocd/manifests/homepage/settings.yaml | 17 ++ argocd/manifests/homepage/widgets.yaml | 26 +++ .../kiwix/configmap-sync-script.yaml | 68 ------- .../kiwix/configmap-zim-torrents.yaml | 69 ------- .../manifests/kiwix/cronjob-zim-watcher.yaml | 2 +- argocd/manifests/kiwix/deployment.yaml | 4 +- argocd/manifests/kiwix/kustomization.yaml | 18 +- argocd/manifests/kiwix/sync-zim-torrents.sh | 60 ++++++ argocd/manifests/kiwix/torrents.txt | 61 ++++++ .../kube-state-metrics/deployment.yaml | 2 +- .../kube-state-metrics/kustomization.yaml | 3 + argocd/manifests/loki/configmap.yaml | 58 ------ argocd/manifests/loki/kustomization.yaml | 10 +- argocd/manifests/loki/loki-config.yaml | 51 +++++ argocd/manifests/loki/statefulset.yaml | 2 +- argocd/manifests/miniflux/deployment.yaml | 2 +- argocd/manifests/miniflux/kustomization.yaml | 4 + argocd/manifests/mosquitto/configmap.yaml | 10 - argocd/manifests/mosquitto/deployment.yaml | 2 +- argocd/manifests/mosquitto/kustomization.yaml | 8 +- argocd/manifests/mosquitto/mosquitto.conf | 3 + argocd/manifests/navidrome/deployment.yaml | 2 +- argocd/manifests/navidrome/kustomization.yaml | 3 + argocd/manifests/ntfy/configmap.yaml | 13 -- argocd/manifests/ntfy/deployment.yaml | 2 +- argocd/manifests/ntfy/kustomization.yaml | 8 +- argocd/manifests/ntfy/server.yml | 6 + .../nvidia-device-plugin/daemonset.yaml | 2 +- .../nvidia-device-plugin/kustomization.yaml | 12 ++ argocd/manifests/prometheus/configmap.yaml | 53 ------ .../manifests/prometheus/kustomization.yaml | 10 +- argocd/manifests/prometheus/prometheus.yml | 46 +++++ argocd/manifests/prometheus/statefulset.yaml | 2 +- .../kustomization.yaml | 4 + .../tailscale-operator-base/operator.yaml | 2 +- argocd/manifests/teslamate/deployment.yaml | 2 +- argocd/manifests/teslamate/kustomization.yaml | 4 + argocd/manifests/torrent/deployment.yaml | 2 +- argocd/manifests/torrent/kustomization.yaml | 3 + ...ure-kustomize-images-configmapgen.infra.md | 1 + 79 files changed, 956 insertions(+), 905 deletions(-) create mode 100644 argocd/manifests/alloy-k8s/config.alloy delete mode 100644 argocd/manifests/alloy-k8s/configmap.yaml create mode 100644 argocd/manifests/forgejo-runner/config.yaml delete mode 100644 argocd/manifests/forgejo-runner/configmap.yaml create mode 100644 argocd/manifests/forgejo-runner/daemon.json create mode 100644 argocd/manifests/forgejo-runner/kustomization.yaml delete mode 100644 argocd/manifests/frigate/configmap-notify.yaml delete mode 100644 argocd/manifests/frigate/configmap.yaml create mode 100644 argocd/manifests/frigate/frigate-config.yml create mode 100644 argocd/manifests/frigate/frigate-notify-config.yml delete mode 100644 argocd/manifests/grafana/configmap.yaml create mode 100644 argocd/manifests/grafana/datasources.yaml create mode 100644 argocd/manifests/grafana/grafana.ini create mode 100644 argocd/manifests/grafana/provider.yaml create mode 100644 argocd/manifests/homepage/bookmarks.yaml delete mode 100644 argocd/manifests/homepage/configmap.yaml create mode 100644 argocd/manifests/homepage/docker.yaml create mode 100644 argocd/manifests/homepage/kubernetes.yaml create mode 100644 argocd/manifests/homepage/services.yaml create mode 100644 argocd/manifests/homepage/settings.yaml create mode 100644 argocd/manifests/homepage/widgets.yaml delete mode 100644 argocd/manifests/kiwix/configmap-sync-script.yaml delete mode 100644 argocd/manifests/kiwix/configmap-zim-torrents.yaml create mode 100644 argocd/manifests/kiwix/sync-zim-torrents.sh create mode 100644 argocd/manifests/kiwix/torrents.txt delete mode 100644 argocd/manifests/loki/configmap.yaml create mode 100644 argocd/manifests/loki/loki-config.yaml delete mode 100644 argocd/manifests/mosquitto/configmap.yaml create mode 100644 argocd/manifests/mosquitto/mosquitto.conf delete mode 100644 argocd/manifests/ntfy/configmap.yaml create mode 100644 argocd/manifests/ntfy/server.yml create mode 100644 argocd/manifests/nvidia-device-plugin/kustomization.yaml delete mode 100644 argocd/manifests/prometheus/configmap.yaml create mode 100644 argocd/manifests/prometheus/prometheus.yml create mode 100644 docs/changelog.d/feature-kustomize-images-configmapgen.infra.md diff --git a/argocd/manifests/alloy-k8s/config.alloy b/argocd/manifests/alloy-k8s/config.alloy new file mode 100644 index 0000000..582a692 --- /dev/null +++ b/argocd/manifests/alloy-k8s/config.alloy @@ -0,0 +1,169 @@ +// Alloy k8s configuration - collects pod logs from all namespaces + +// ============== K8S POD LOG DISCOVERY ============== + +// Discover all pods in the cluster +discovery.kubernetes "pods" { + role = "pod" +} + +// Relabel to extract useful metadata +discovery.relabel "pods" { + targets = discovery.kubernetes.pods.targets + + // Keep only running pods + rule { + source_labels = ["__meta_kubernetes_pod_phase"] + regex = "Pending|Succeeded|Failed|Unknown" + action = "drop" + } + + // Set namespace label + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" + } + + // Set pod name label + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" + } + + // Set container name label + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" + } + + // Set app label from pod labels + rule { + source_labels = ["__meta_kubernetes_pod_label_app"] + target_label = "app" + } + + // Fallback: use app.kubernetes.io/name if no app label + rule { + source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"] + target_label = "app" + regex = "(.+)" + action = "replace" + } + + // Set node name + rule { + source_labels = ["__meta_kubernetes_pod_node_name"] + target_label = "node" + } + + // Build the log path for the pod container + rule { + source_labels = ["__meta_kubernetes_pod_uid", "__meta_kubernetes_pod_container_name"] + target_label = "__path__" + separator = "/" + replacement = "/var/log/pods/*$1/$2/*.log" + } +} + +// Tail pod logs +loki.source.kubernetes "pods" { + targets = discovery.relabel.pods.output + forward_to = [loki.process.pods.receiver] +} + +// Process logs - parse JSON if present, add labels +loki.process "pods" { + forward_to = [loki.write.loki.receiver] + + // Drop noisy deprecation warning from minikube storage-provisioner + // See: https://github.com/kubernetes/minikube/issues/21009 + stage.drop { + source = "" + expression = "v1 Endpoints is deprecated" + } + + // Try to parse JSON logs (e.g., structured app logs) + // Handle both "msg" (common) and "message" (zot) field names + stage.json { + expressions = { + level = "level", + msg = "msg", + message = "message", + time = "time", + caller = "caller", + repository = "repository", + } + } + + // Drop JSON parsing error labels (non-JSON logs are fine, just won't have extracted fields) + stage.label_drop { + values = ["__error__", "__error_details__"] + } + + // Extract labels from parsed JSON data + stage.labels { + values = { + level = "", + caller = "", + repository = "", + } + } +} + +// Write logs to Loki +loki.write "loki" { + endpoint { + url = "http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push" + } +} + +// ============== SERVICE HEALTH PROBES ============== + +// Blackbox-style HTTP probes for k8s services +prometheus.exporter.blackbox "services" { + config = "{ modules: { http_2xx: { prober: http, timeout: 5s } } }" + + target { + name = "miniflux" + address = "http://miniflux.miniflux.svc.cluster.local:8080/healthcheck" + module = "http_2xx" + } + + target { + name = "kiwix" + address = "http://kiwix.kiwix.svc.cluster.local:80/" + module = "http_2xx" + } + + target { + name = "transmission" + address = "http://transmission.torrent.svc.cluster.local:9091/transmission/web/" + module = "http_2xx" + } + + target { + name = "devpi" + address = "http://devpi.devpi.svc.cluster.local:3141/+api" + module = "http_2xx" + } + + target { + name = "argocd" + address = "http://argocd-server.argocd.svc.cluster.local:80/healthz" + module = "http_2xx" + } +} + +// Scrape blackbox probe results +prometheus.scrape "blackbox" { + targets = prometheus.exporter.blackbox.services.targets + scrape_interval = "30s" + forward_to = [prometheus.remote_write.prometheus.receiver] +} + +// Push metrics to Prometheus +prometheus.remote_write "prometheus" { + endpoint { + url = "http://prometheus.monitoring.svc.cluster.local:9090/api/v1/write" + } +} diff --git a/argocd/manifests/alloy-k8s/configmap.yaml b/argocd/manifests/alloy-k8s/configmap.yaml deleted file mode 100644 index b0e6643..0000000 --- a/argocd/manifests/alloy-k8s/configmap.yaml +++ /dev/null @@ -1,176 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: alloy-config - namespace: alloy -data: - config.alloy: | - // Alloy k8s configuration - collects pod logs from all namespaces - - // ============== K8S POD LOG DISCOVERY ============== - - // Discover all pods in the cluster - discovery.kubernetes "pods" { - role = "pod" - } - - // Relabel to extract useful metadata - discovery.relabel "pods" { - targets = discovery.kubernetes.pods.targets - - // Keep only running pods - rule { - source_labels = ["__meta_kubernetes_pod_phase"] - regex = "Pending|Succeeded|Failed|Unknown" - action = "drop" - } - - // Set namespace label - rule { - source_labels = ["__meta_kubernetes_namespace"] - target_label = "namespace" - } - - // Set pod name label - rule { - source_labels = ["__meta_kubernetes_pod_name"] - target_label = "pod" - } - - // Set container name label - rule { - source_labels = ["__meta_kubernetes_pod_container_name"] - target_label = "container" - } - - // Set app label from pod labels - rule { - source_labels = ["__meta_kubernetes_pod_label_app"] - target_label = "app" - } - - // Fallback: use app.kubernetes.io/name if no app label - rule { - source_labels = ["__meta_kubernetes_pod_label_app_kubernetes_io_name"] - target_label = "app" - regex = "(.+)" - action = "replace" - } - - // Set node name - rule { - source_labels = ["__meta_kubernetes_pod_node_name"] - target_label = "node" - } - - // Build the log path for the pod container - rule { - source_labels = ["__meta_kubernetes_pod_uid", "__meta_kubernetes_pod_container_name"] - target_label = "__path__" - separator = "/" - replacement = "/var/log/pods/*$1/$2/*.log" - } - } - - // Tail pod logs - loki.source.kubernetes "pods" { - targets = discovery.relabel.pods.output - forward_to = [loki.process.pods.receiver] - } - - // Process logs - parse JSON if present, add labels - loki.process "pods" { - forward_to = [loki.write.loki.receiver] - - // Drop noisy deprecation warning from minikube storage-provisioner - // See: https://github.com/kubernetes/minikube/issues/21009 - stage.drop { - source = "" - expression = "v1 Endpoints is deprecated" - } - - // Try to parse JSON logs (e.g., structured app logs) - // Handle both "msg" (common) and "message" (zot) field names - stage.json { - expressions = { - level = "level", - msg = "msg", - message = "message", - time = "time", - caller = "caller", - repository = "repository", - } - } - - // Drop JSON parsing error labels (non-JSON logs are fine, just won't have extracted fields) - stage.label_drop { - values = ["__error__", "__error_details__"] - } - - // Extract labels from parsed JSON data - stage.labels { - values = { - level = "", - caller = "", - repository = "", - } - } - } - - // Write logs to Loki - loki.write "loki" { - endpoint { - url = "http://loki.monitoring.svc.cluster.local:3100/loki/api/v1/push" - } - } - - // ============== SERVICE HEALTH PROBES ============== - - // Blackbox-style HTTP probes for k8s services - prometheus.exporter.blackbox "services" { - config = "{ modules: { http_2xx: { prober: http, timeout: 5s } } }" - - target { - name = "miniflux" - address = "http://miniflux.miniflux.svc.cluster.local:8080/healthcheck" - module = "http_2xx" - } - - target { - name = "kiwix" - address = "http://kiwix.kiwix.svc.cluster.local:80/" - module = "http_2xx" - } - - target { - name = "transmission" - address = "http://transmission.torrent.svc.cluster.local:9091/transmission/web/" - module = "http_2xx" - } - - target { - name = "devpi" - address = "http://devpi.devpi.svc.cluster.local:3141/+api" - module = "http_2xx" - } - - target { - name = "argocd" - address = "http://argocd-server.argocd.svc.cluster.local:80/healthz" - module = "http_2xx" - } - } - - // Scrape blackbox probe results - prometheus.scrape "blackbox" { - targets = prometheus.exporter.blackbox.services.targets - scrape_interval = "30s" - forward_to = [prometheus.remote_write.prometheus.receiver] - } - - // Push metrics to Prometheus - prometheus.remote_write "prometheus" { - endpoint { - url = "http://prometheus.monitoring.svc.cluster.local:9090/api/v1/write" - } - } diff --git a/argocd/manifests/alloy-k8s/daemonset.yaml b/argocd/manifests/alloy-k8s/daemonset.yaml index b78633a..89cb930 100644 --- a/argocd/manifests/alloy-k8s/daemonset.yaml +++ b/argocd/manifests/alloy-k8s/daemonset.yaml @@ -19,7 +19,7 @@ spec: fsGroup: 473 # alloy user group containers: - name: alloy - image: grafana/alloy:v1.13.1 + image: grafana/alloy args: - run - --server.http.listen-addr=0.0.0.0:12345 diff --git a/argocd/manifests/alloy-k8s/kustomization.yaml b/argocd/manifests/alloy-k8s/kustomization.yaml index 17cd3c4..1d43d8f 100644 --- a/argocd/manifests/alloy-k8s/kustomization.yaml +++ b/argocd/manifests/alloy-k8s/kustomization.yaml @@ -1,7 +1,18 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization + +namespace: alloy + resources: - namespace.yaml - rbac.yaml - - configmap.yaml - daemonset.yaml + +images: + - name: grafana/alloy + newTag: v1.13.1 + +configMapGenerator: + - name: alloy-config + files: + - config.alloy diff --git a/argocd/manifests/authentik/deployment-redis.yaml b/argocd/manifests/authentik/deployment-redis.yaml index 03c5873..e70ac98 100644 --- a/argocd/manifests/authentik/deployment-redis.yaml +++ b/argocd/manifests/authentik/deployment-redis.yaml @@ -18,7 +18,7 @@ spec: spec: containers: - name: redis - image: docker.io/library/redis:7-alpine + image: docker.io/library/redis ports: - name: redis containerPort: 6379 diff --git a/argocd/manifests/authentik/deployment-server.yaml b/argocd/manifests/authentik/deployment-server.yaml index 085e16b..c3fdb52 100644 --- a/argocd/manifests/authentik/deployment-server.yaml +++ b/argocd/manifests/authentik/deployment-server.yaml @@ -18,7 +18,7 @@ spec: spec: containers: - name: server - image: registry.ops.eblu.me/blumeops/authentik:v2025.10.1-a72a0d8-nix + image: registry.ops.eblu.me/blumeops/authentik args: ["server"] ports: - name: http diff --git a/argocd/manifests/authentik/deployment-worker.yaml b/argocd/manifests/authentik/deployment-worker.yaml index 9bcc9fd..14becb6 100644 --- a/argocd/manifests/authentik/deployment-worker.yaml +++ b/argocd/manifests/authentik/deployment-worker.yaml @@ -18,7 +18,7 @@ spec: spec: containers: - name: worker - image: registry.ops.eblu.me/blumeops/authentik:v2025.10.1-a72a0d8-nix + image: registry.ops.eblu.me/blumeops/authentik args: ["worker"] env: - name: AUTHENTIK_SECRET_KEY diff --git a/argocd/manifests/authentik/kustomization.yaml b/argocd/manifests/authentik/kustomization.yaml index f639eba..9075142 100644 --- a/argocd/manifests/authentik/kustomization.yaml +++ b/argocd/manifests/authentik/kustomization.yaml @@ -11,3 +11,8 @@ resources: - service.yaml - service-redis.yaml - ingress-tailscale.yaml +images: + - name: registry.ops.eblu.me/blumeops/authentik + newTag: v2025.10.1-a72a0d8-nix + - name: docker.io/library/redis + newTag: 7-alpine diff --git a/argocd/manifests/cv/deployment.yaml b/argocd/manifests/cv/deployment.yaml index 656e932..57c850b 100644 --- a/argocd/manifests/cv/deployment.yaml +++ b/argocd/manifests/cv/deployment.yaml @@ -16,7 +16,7 @@ spec: spec: containers: - name: cv - image: registry.ops.eblu.me/blumeops/cv:v1.0.3-ffa8727 + image: registry.ops.eblu.me/blumeops/cv ports: - containerPort: 80 name: http diff --git a/argocd/manifests/cv/kustomization.yaml b/argocd/manifests/cv/kustomization.yaml index 43c806c..9ba628f 100644 --- a/argocd/manifests/cv/kustomization.yaml +++ b/argocd/manifests/cv/kustomization.yaml @@ -6,3 +6,6 @@ resources: - deployment.yaml - service.yaml - ingress-tailscale.yaml +images: + - name: registry.ops.eblu.me/blumeops/cv + newTag: v1.0.3-ffa8727 diff --git a/argocd/manifests/devpi/kustomization.yaml b/argocd/manifests/devpi/kustomization.yaml index ef6566c..1943401 100644 --- a/argocd/manifests/devpi/kustomization.yaml +++ b/argocd/manifests/devpi/kustomization.yaml @@ -8,3 +8,7 @@ resources: - service.yaml - ingress-tailscale.yaml - external-secret.yaml + +images: + - name: registry.ops.eblu.me/blumeops/devpi + newTag: v6.19.1-ffa8727 diff --git a/argocd/manifests/devpi/statefulset.yaml b/argocd/manifests/devpi/statefulset.yaml index 23ff8a5..7bb5db0 100644 --- a/argocd/manifests/devpi/statefulset.yaml +++ b/argocd/manifests/devpi/statefulset.yaml @@ -18,7 +18,7 @@ spec: fsGroup: 1000 containers: - name: devpi - image: registry.ops.eblu.me/blumeops/devpi:v6.19.1-ffa8727 + image: registry.ops.eblu.me/blumeops/devpi env: - name: DEVPI_ROOT_PASSWORD valueFrom: diff --git a/argocd/manifests/docs/deployment.yaml b/argocd/manifests/docs/deployment.yaml index cb3b87b..1e1b825 100644 --- a/argocd/manifests/docs/deployment.yaml +++ b/argocd/manifests/docs/deployment.yaml @@ -16,7 +16,7 @@ spec: spec: containers: - name: docs - image: registry.ops.eblu.me/blumeops/quartz:v1.28.2-ffa8727 + image: registry.ops.eblu.me/blumeops/quartz ports: - containerPort: 80 name: http diff --git a/argocd/manifests/docs/kustomization.yaml b/argocd/manifests/docs/kustomization.yaml index ef01217..492c8a3 100644 --- a/argocd/manifests/docs/kustomization.yaml +++ b/argocd/manifests/docs/kustomization.yaml @@ -6,3 +6,6 @@ resources: - deployment.yaml - service.yaml - ingress-tailscale.yaml +images: + - name: registry.ops.eblu.me/blumeops/quartz + newTag: v1.28.2-ffa8727 diff --git a/argocd/manifests/forgejo-runner/config.yaml b/argocd/manifests/forgejo-runner/config.yaml new file mode 100644 index 0000000..c92d616 --- /dev/null +++ b/argocd/manifests/forgejo-runner/config.yaml @@ -0,0 +1,19 @@ +# Reviewed against v12.7.0 defaults (2026-02-22) +log: + level: info + +runner: + file: /data/.runner + capacity: 2 + timeout: 3h + shutdown_timeout: 3h + # Env vars injected into all job containers + envs: + DOCKER_HOST: tcp://127.0.0.1:2375 + TZ: America/Los_Angeles + +container: + # Job execution image is set via RUNNER_LABELS in deployment.yaml + network: "host" + # Connect to DinD sidecar via TCP (not socket) + docker_host: tcp://127.0.0.1:2375 diff --git a/argocd/manifests/forgejo-runner/configmap.yaml b/argocd/manifests/forgejo-runner/configmap.yaml deleted file mode 100644 index 3b0df5b..0000000 --- a/argocd/manifests/forgejo-runner/configmap.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: forgejo-runner-config - namespace: forgejo-runner -data: - config.yaml: | - # Reviewed against v12.7.0 defaults (2026-02-22) - log: - level: info - - runner: - file: /data/.runner - capacity: 2 - timeout: 3h - shutdown_timeout: 3h - # Env vars injected into all job containers - envs: - DOCKER_HOST: tcp://127.0.0.1:2375 - TZ: America/Los_Angeles - - container: - # Job execution image is set via RUNNER_LABELS in deployment.yaml - network: "host" - # Connect to DinD sidecar via TCP (not socket) - docker_host: tcp://127.0.0.1:2375 - daemon.json: | - { - "registry-mirrors": ["http://host.minikube.internal:5050"] - } diff --git a/argocd/manifests/forgejo-runner/daemon.json b/argocd/manifests/forgejo-runner/daemon.json new file mode 100644 index 0000000..637acdc --- /dev/null +++ b/argocd/manifests/forgejo-runner/daemon.json @@ -0,0 +1,3 @@ +{ + "registry-mirrors": ["http://host.minikube.internal:5050"] +} diff --git a/argocd/manifests/forgejo-runner/deployment.yaml b/argocd/manifests/forgejo-runner/deployment.yaml index b4d5b88..4f67672 100644 --- a/argocd/manifests/forgejo-runner/deployment.yaml +++ b/argocd/manifests/forgejo-runner/deployment.yaml @@ -18,7 +18,7 @@ spec: containers: # Forgejo runner daemon - name: runner - image: code.forgejo.org/forgejo/runner:12.7.0 + image: code.forgejo.org/forgejo/runner env: - name: TZ value: America/Los_Angeles @@ -68,7 +68,7 @@ spec: # Docker-in-Docker sidecar - name: dind - image: docker:27-dind + image: docker securityContext: privileged: true env: diff --git a/argocd/manifests/forgejo-runner/kustomization.yaml b/argocd/manifests/forgejo-runner/kustomization.yaml new file mode 100644 index 0000000..67527de --- /dev/null +++ b/argocd/manifests/forgejo-runner/kustomization.yaml @@ -0,0 +1,21 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: forgejo-runner + +resources: + - namespace.yaml + - external-secret.yaml + - deployment.yaml + +images: + - name: code.forgejo.org/forgejo/runner + newTag: "12.7.0" + - name: docker + newTag: 27-dind + +configMapGenerator: + - name: forgejo-runner-config + files: + - config.yaml + - daemon.json diff --git a/argocd/manifests/frigate/configmap-notify.yaml b/argocd/manifests/frigate/configmap-notify.yaml deleted file mode 100644 index b638849..0000000 --- a/argocd/manifests/frigate/configmap-notify.yaml +++ /dev/null @@ -1,42 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: frigate-notify-config - namespace: frigate -data: - config.yml: | - frigate: - server: http://frigate:5000 - public_url: https://nvr.ops.eblu.me - - webapi: - enabled: true - interval: 15 - - mqtt: - enabled: false - - alerts: - general: - title: "Frigate Alert" - nosnap: drop - snap_hires: true - notify_once: true - - zones: - unzoned: drop - allow: - - driveway_entrance - - driveway - - labels: - allow: - - person - - car - - ntfy: - enabled: true - server: http://ntfy.ntfy.svc.cluster.local:80 - topic: frigate-alerts - headers: - - X-Actions: "view, Open Event, {{.Extra.PublicURL}}/review?id={{.ID}}, clear=true; view, Open Camera, {{.Extra.PublicURL}}/#/cameras/{{.Camera}}" diff --git a/argocd/manifests/frigate/configmap.yaml b/argocd/manifests/frigate/configmap.yaml deleted file mode 100644 index 16bd4d8..0000000 --- a/argocd/manifests/frigate/configmap.yaml +++ /dev/null @@ -1,90 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: frigate-config - namespace: frigate -data: - config.yml: | - mqtt: - host: mosquitto.mqtt.svc.cluster.local - port: 1883 - - go2rtc: - streams: - # GableCam IP is reserved in UX7 DHCP config - gablecam: - - "rtsp://{FRIGATE_CAMERA_USER}:{FRIGATE_CAMERA_PASSWORD}@192.168.1.159:554/h264Preview_01_main" - gablecam_sub: - - "rtsp://{FRIGATE_CAMERA_USER}:{FRIGATE_CAMERA_PASSWORD}@192.168.1.159:554/h264Preview_01_sub" - - cameras: - gablecam: - enabled: true - ffmpeg: - inputs: - - path: rtsp://127.0.0.1:8554/gablecam - input_args: preset-rtsp-restream - roles: [record] - - path: rtsp://127.0.0.1:8554/gablecam_sub - input_args: preset-rtsp-restream - roles: [detect] - detect: - enabled: true - stationary: - max_frames: - default: 1500 - motion: - mask: - - 0.401,0.026,0.4,0.078,0.587,0.072,0.585,0.02 - - 0.881,0.422,0.789,0.245,0.595,0.054,0.531,0,0.634,0,0.824,0.192,0.892,0.307 - zones: - driveway_entrance: - coordinates: 0.841,0.37,0.735,0.344,0.681,0.2,0.78,0.259 - objects: [car, dog, person] - inertia: 3 - loitering_time: 0 - driveway: - coordinates: 0.767,0.25,0.58,0.2,0.218,0.25,0.128,0.296,0.003,0.565,0.001,0.992,0.826,0.992,0.897,0.665,0.869,0.608,0.788,0.354 - review: - alerts: - labels: [person, car] - required_zones: - - driveway_entrance - - driveway - detections: - required_zones: - - driveway - - driveway_entrance - objects: - track: [person, car, dog, cat, bird] - - detectors: - onnx: - type: onnx - - model: - model_type: yolo-generic - width: 640 - height: 640 - input_tensor: nchw - input_dtype: float - path: /media/frigate/models/yolov9-c-640.onnx - labelmap_path: /labelmap/coco-80.txt - - record: - enabled: true - continuous: - days: 3 - alerts: - retain: - days: 30 - mode: active_objects - detections: - retain: - days: 14 - mode: motion - - snapshots: - enabled: true - retain: - default: 14 diff --git a/argocd/manifests/frigate/deployment-notify.yaml b/argocd/manifests/frigate/deployment-notify.yaml index 751cdf5..a6e1361 100644 --- a/argocd/manifests/frigate/deployment-notify.yaml +++ b/argocd/manifests/frigate/deployment-notify.yaml @@ -16,7 +16,7 @@ spec: spec: containers: - name: frigate-notify - image: ghcr.io/0x2142/frigate-notify:v0.5.4 + image: ghcr.io/0x2142/frigate-notify env: - name: TZ value: America/Los_Angeles diff --git a/argocd/manifests/frigate/deployment.yaml b/argocd/manifests/frigate/deployment.yaml index 1460bb3..77ac007 100644 --- a/argocd/manifests/frigate/deployment.yaml +++ b/argocd/manifests/frigate/deployment.yaml @@ -19,7 +19,7 @@ spec: runtimeClassName: nvidia initContainers: - name: copy-config - image: busybox:1.37 + image: busybox command: ["cp", "/config-ro/config.yml", "/config/config.yml"] volumeMounts: - name: config-ro @@ -28,7 +28,7 @@ spec: mountPath: /config containers: - name: frigate - image: ghcr.io/blakeblackshear/frigate:0.17.0-rc2-tensorrt + image: ghcr.io/blakeblackshear/frigate ports: - containerPort: 5000 name: http diff --git a/argocd/manifests/frigate/frigate-config.yml b/argocd/manifests/frigate/frigate-config.yml new file mode 100644 index 0000000..8f6bff4 --- /dev/null +++ b/argocd/manifests/frigate/frigate-config.yml @@ -0,0 +1,83 @@ +mqtt: + host: mosquitto.mqtt.svc.cluster.local + port: 1883 + +go2rtc: + streams: + # GableCam IP is reserved in UX7 DHCP config + gablecam: + - "rtsp://{FRIGATE_CAMERA_USER}:{FRIGATE_CAMERA_PASSWORD}@192.168.1.159:554/h264Preview_01_main" + gablecam_sub: + - "rtsp://{FRIGATE_CAMERA_USER}:{FRIGATE_CAMERA_PASSWORD}@192.168.1.159:554/h264Preview_01_sub" + +cameras: + gablecam: + enabled: true + ffmpeg: + inputs: + - path: rtsp://127.0.0.1:8554/gablecam + input_args: preset-rtsp-restream + roles: [record] + - path: rtsp://127.0.0.1:8554/gablecam_sub + input_args: preset-rtsp-restream + roles: [detect] + detect: + enabled: true + stationary: + max_frames: + default: 1500 + motion: + mask: + - 0.401,0.026,0.4,0.078,0.587,0.072,0.585,0.02 + - 0.881,0.422,0.789,0.245,0.595,0.054,0.531,0,0.634,0,0.824,0.192,0.892,0.307 + zones: + driveway_entrance: + coordinates: 0.841,0.37,0.735,0.344,0.681,0.2,0.78,0.259 + objects: [car, dog, person] + inertia: 3 + loitering_time: 0 + driveway: + coordinates: 0.767,0.25,0.58,0.2,0.218,0.25,0.128,0.296,0.003,0.565,0.001,0.992,0.826,0.992,0.897,0.665,0.869,0.608,0.788,0.354 + review: + alerts: + labels: [person, car] + required_zones: + - driveway_entrance + - driveway + detections: + required_zones: + - driveway + - driveway_entrance + objects: + track: [person, car, dog, cat, bird] + +detectors: + onnx: + type: onnx + +model: + model_type: yolo-generic + width: 640 + height: 640 + input_tensor: nchw + input_dtype: float + path: /media/frigate/models/yolov9-c-640.onnx + labelmap_path: /labelmap/coco-80.txt + +record: + enabled: true + continuous: + days: 3 + alerts: + retain: + days: 30 + mode: active_objects + detections: + retain: + days: 14 + mode: motion + +snapshots: + enabled: true + retain: + default: 14 diff --git a/argocd/manifests/frigate/frigate-notify-config.yml b/argocd/manifests/frigate/frigate-notify-config.yml new file mode 100644 index 0000000..69072df --- /dev/null +++ b/argocd/manifests/frigate/frigate-notify-config.yml @@ -0,0 +1,35 @@ +frigate: + server: http://frigate:5000 + public_url: https://nvr.ops.eblu.me + + webapi: + enabled: true + interval: 15 + + mqtt: + enabled: false + +alerts: + general: + title: "Frigate Alert" + nosnap: drop + snap_hires: true + notify_once: true + + zones: + unzoned: drop + allow: + - driveway_entrance + - driveway + + labels: + allow: + - person + - car + + ntfy: + enabled: true + server: http://ntfy.ntfy.svc.cluster.local:80 + topic: frigate-alerts + headers: + - X-Actions: "view, Open Event, {{.Extra.PublicURL}}/review?id={{.ID}}, clear=true; view, Open Camera, {{.Extra.PublicURL}}/#/cameras/{{.Camera}}" diff --git a/argocd/manifests/frigate/kustomization.yaml b/argocd/manifests/frigate/kustomization.yaml index 0610eca..ac6079c 100644 --- a/argocd/manifests/frigate/kustomization.yaml +++ b/argocd/manifests/frigate/kustomization.yaml @@ -4,8 +4,6 @@ kind: Kustomization namespace: frigate resources: - external-secret.yaml - - configmap.yaml - - configmap-notify.yaml - pv-nfs.yaml - pvc-recordings.yaml - pvc-database.yaml @@ -13,3 +11,19 @@ resources: - deployment-notify.yaml - service.yaml - ingress-tailscale.yaml + +images: + - name: busybox + newTag: "1.37" + - name: ghcr.io/blakeblackshear/frigate + newTag: 0.17.0-rc2-tensorrt + - name: ghcr.io/0x2142/frigate-notify + newTag: v0.5.4 + +configMapGenerator: + - name: frigate-config + files: + - config.yml=frigate-config.yml + - name: frigate-notify-config + files: + - config.yml=frigate-notify-config.yml diff --git a/argocd/manifests/grafana/configmap.yaml b/argocd/manifests/grafana/configmap.yaml deleted file mode 100644 index 48baebb..0000000 --- a/argocd/manifests/grafana/configmap.yaml +++ /dev/null @@ -1,100 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: grafana - namespace: monitoring - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana -data: - grafana.ini: | - [analytics] - check_for_updates = false - reporting_enabled = false - - [auth.generic_oauth] - allow_sign_up = true - api_url = https://authentik.ops.eblu.me/application/o/userinfo/ - auth_url = https://authentik.ops.eblu.me/application/o/authorize/ - auto_login = false - client_id = grafana - client_secret = $__env{GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET} - enabled = true - name = Authentik - role_attribute_path = contains(groups[*], 'admins') && 'Admin' || 'Viewer' - skip_org_role_sync = false - scopes = openid profile email - token_url = https://authentik.ops.eblu.me/application/o/token/ - - [log] - mode = console - - [paths] - data = /var/lib/grafana/ - logs = /var/log/grafana - plugins = /var/lib/grafana/plugins - provisioning = /etc/grafana/provisioning - - [security] - allow_embedding = false - - [server] - root_url = https://grafana.ops.eblu.me - - datasources.yaml: | - apiVersion: 1 - datasources: - - access: proxy - editable: false - isDefault: true - name: Prometheus - orgId: 1 - type: prometheus - uid: prometheus - url: http://prometheus.monitoring.svc.cluster.local:9090 - - access: proxy - editable: false - name: Loki - orgId: 1 - type: loki - uid: loki - url: http://loki.monitoring.svc.cluster.local:3100 - - access: proxy - database: teslamate - editable: false - jsonData: - database: teslamate - connMaxLifetime: 14400 - maxIdleConns: 2 - maxOpenConns: 5 - sslmode: disable - name: TeslaMate - orgId: 1 - secureJsonData: - password: $TESLAMATE_DB_PASSWORD - type: postgres - uid: TeslaMate - url: blumeops-pg-rw.databases.svc.cluster.local:5432 - user: teslamate ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: grafana-config-dashboards - namespace: monitoring - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana -data: - provider.yaml: | - apiVersion: 1 - providers: - - name: 'sidecarProvider' - orgId: 1 - type: file - disableDeletion: false - allowUiUpdates: false - updateIntervalSeconds: 30 - options: - foldersFromFilesStructure: true - path: /tmp/dashboards diff --git a/argocd/manifests/grafana/datasources.yaml b/argocd/manifests/grafana/datasources.yaml new file mode 100644 index 0000000..864fcb1 --- /dev/null +++ b/argocd/manifests/grafana/datasources.yaml @@ -0,0 +1,34 @@ +apiVersion: 1 +datasources: +- access: proxy + editable: false + isDefault: true + name: Prometheus + orgId: 1 + type: prometheus + uid: prometheus + url: http://prometheus.monitoring.svc.cluster.local:9090 +- access: proxy + editable: false + name: Loki + orgId: 1 + type: loki + uid: loki + url: http://loki.monitoring.svc.cluster.local:3100 +- access: proxy + database: teslamate + editable: false + jsonData: + database: teslamate + connMaxLifetime: 14400 + maxIdleConns: 2 + maxOpenConns: 5 + sslmode: disable + name: TeslaMate + orgId: 1 + secureJsonData: + password: $TESLAMATE_DB_PASSWORD + type: postgres + uid: TeslaMate + url: blumeops-pg-rw.databases.svc.cluster.local:5432 + user: teslamate diff --git a/argocd/manifests/grafana/deployment.yaml b/argocd/manifests/grafana/deployment.yaml index a027d01..69b7eb9 100644 --- a/argocd/manifests/grafana/deployment.yaml +++ b/argocd/manifests/grafana/deployment.yaml @@ -32,7 +32,7 @@ spec: runAsUser: 472 initContainers: - name: init-chown-data - image: docker.io/library/busybox:1.31.1 + image: docker.io/library/busybox imagePullPolicy: IfNotPresent command: ["chown", "-R", "472:472", "/var/lib/grafana"] securityContext: @@ -48,7 +48,7 @@ spec: containers: # Dashboard sidecar - watches ConfigMaps with grafana_dashboard=1 - name: grafana-sc-dashboard - image: quay.io/kiwigrid/k8s-sidecar:1.28.0 + image: quay.io/kiwigrid/k8s-sidecar imagePullPolicy: IfNotPresent env: - name: METHOD @@ -88,7 +88,7 @@ spec: mountPath: /tmp/dashboards # Grafana - name: grafana - image: registry.ops.eblu.me/blumeops/grafana:v12.3.3-d05d2fb + image: registry.ops.eblu.me/blumeops/grafana imagePullPolicy: IfNotPresent env: - name: POD_IP diff --git a/argocd/manifests/grafana/grafana.ini b/argocd/manifests/grafana/grafana.ini new file mode 100644 index 0000000..61cdd7e --- /dev/null +++ b/argocd/manifests/grafana/grafana.ini @@ -0,0 +1,32 @@ +[analytics] +check_for_updates = false +reporting_enabled = false + +[auth.generic_oauth] +allow_sign_up = true +api_url = https://authentik.ops.eblu.me/application/o/userinfo/ +auth_url = https://authentik.ops.eblu.me/application/o/authorize/ +auto_login = false +client_id = grafana +client_secret = $__env{GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET} +enabled = true +name = Authentik +role_attribute_path = contains(groups[*], 'admins') && 'Admin' || 'Viewer' +skip_org_role_sync = false +scopes = openid profile email +token_url = https://authentik.ops.eblu.me/application/o/token/ + +[log] +mode = console + +[paths] +data = /var/lib/grafana/ +logs = /var/log/grafana +plugins = /var/lib/grafana/plugins +provisioning = /etc/grafana/provisioning + +[security] +allow_embedding = false + +[server] +root_url = https://grafana.ops.eblu.me diff --git a/argocd/manifests/grafana/kustomization.yaml b/argocd/manifests/grafana/kustomization.yaml index 2707d42..f8c823e 100644 --- a/argocd/manifests/grafana/kustomization.yaml +++ b/argocd/manifests/grafana/kustomization.yaml @@ -5,8 +5,24 @@ namespace: monitoring resources: - serviceaccount.yaml - - configmap.yaml - pvc.yaml - deployment.yaml - service.yaml - rbac.yaml + +images: + - name: docker.io/library/busybox + newTag: 1.31.1 + - name: quay.io/kiwigrid/k8s-sidecar + newTag: 1.28.0 + - name: registry.ops.eblu.me/blumeops/grafana + newTag: v12.3.3-d05d2fb + +configMapGenerator: + - name: grafana + files: + - grafana.ini + - datasources.yaml + - name: grafana-config-dashboards + files: + - provider.yaml diff --git a/argocd/manifests/grafana/provider.yaml b/argocd/manifests/grafana/provider.yaml new file mode 100644 index 0000000..a35d172 --- /dev/null +++ b/argocd/manifests/grafana/provider.yaml @@ -0,0 +1,11 @@ +apiVersion: 1 +providers: + - name: 'sidecarProvider' + orgId: 1 + type: file + disableDeletion: false + allowUiUpdates: false + updateIntervalSeconds: 30 + options: + foldersFromFilesStructure: true + path: /tmp/dashboards diff --git a/argocd/manifests/homepage/bookmarks.yaml b/argocd/manifests/homepage/bookmarks.yaml new file mode 100644 index 0000000..854ff7b --- /dev/null +++ b/argocd/manifests/homepage/bookmarks.yaml @@ -0,0 +1,16 @@ +- Admin: + - Tailscale Admin: + - href: https://login.tailscale.com/admin + icon: tailscale + - 1Password: + - href: https://my.1password.com + icon: 1password + - Pulumi: + - href: https://app.pulumi.com/eblume/blumeops-tailnet + icon: si-pulumi + - ArgoCD: + - href: https://argocd.ops.eblu.me + icon: argo-cd + - UniFi: + - href: https://unifi.ui.com + icon: ubiquiti diff --git a/argocd/manifests/homepage/configmap.yaml b/argocd/manifests/homepage/configmap.yaml deleted file mode 100644 index 858b479..0000000 --- a/argocd/manifests/homepage/configmap.yaml +++ /dev/null @@ -1,155 +0,0 @@ -# Homepage configuration files -# Extracted from former Helm values.yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: homepage-config - namespace: homepage -data: - bookmarks.yaml: | - - Admin: - - Tailscale Admin: - - href: https://login.tailscale.com/admin - icon: tailscale - - 1Password: - - href: https://my.1password.com - icon: 1password - - Pulumi: - - href: https://app.pulumi.com/eblume/blumeops-tailnet - icon: si-pulumi - - ArgoCD: - - href: https://argocd.ops.eblu.me - icon: argo-cd - - UniFi: - - href: https://unifi.ui.com - icon: ubiquiti - - services.yaml: | - - Host Services: - - Forgejo: - href: https://forge.ops.eblu.me - icon: forgejo - description: Git forge - widget: - type: gitea - url: https://forge.ops.eblu.me - key: "{{HOMEPAGE_VAR_FORGEJO_API_KEY}}" - - Registry: - href: https://registry.ops.eblu.me - icon: zot-registry - description: Container registry - - Sifaka NAS: - href: https://nas.ops.eblu.me - icon: synology - description: NAS dashboard - widget: - type: prometheusmetric - url: https://prometheus.ops.eblu.me - metrics: - - label: Used - query: node_filesystem_size_bytes{mountpoint="/Volumes/backups"} - node_filesystem_avail_bytes{mountpoint="/Volumes/backups"} - format: - type: bytes - - label: Total - query: node_filesystem_size_bytes{mountpoint="/Volumes/backups"} - format: - type: bytes - - Borgmatic: - href: https://grafana.ops.eblu.me/d/borgmatic - icon: borgmatic - description: Backup system - widget: - type: prometheusmetric - url: https://prometheus.ops.eblu.me - metrics: - - label: Last backup - query: time() - borgmatic_last_archive_timestamp - format: - type: duration - - label: Archive size - query: borgmatic_repo_deduplicated_size_bytes - format: - type: bytes - - Jellyfin: - href: https://jellyfin.ops.eblu.me - icon: jellyfin - description: Media server - widget: - type: jellyfin - url: https://jellyfin.ops.eblu.me - key: "{{HOMEPAGE_VAR_JELLYFIN_API_KEY}}" - enableBlocks: true - enableNowPlaying: true - # TODO: Add Caddy widget when admin API is enabled (currently admin off) - # - Caddy: - # href: https://indri.tail8d86e.ts.net - # icon: caddy - # description: Reverse proxy - # widget: - # type: caddy - # url: http://indri.tail8d86e.ts.net:2019 - - Infrastructure: - - Authentik: - href: https://authentik.ops.eblu.me - icon: authentik - description: Identity provider - - NVR: - href: https://nvr.ops.eblu.me - icon: frigate.png - description: Network video recorder - - Ntfy: - href: https://ntfy.ops.eblu.me - icon: ntfy.png - description: Push notifications - - widgets.yaml: | - - greeting: - text_size: xl - text: Welcome to Blue Mops - - datetime: - text_size: lg - format: - dateStyle: long - timeStyle: short - hour12: true - - openweathermap: - label: Camano - latitude: 48.18235 - longitude: -122.52590 - units: imperial - provider: openweathermap - apiKey: "{{HOMEPAGE_VAR_OPENWEATHERMAP_API_KEY}}" - cache: 15 - # TODO: Add UniFi widget when controller is set up - # - unifi_console: - # url: https://192.168.1.1 - # username: homepage - # password: "{{HOMEPAGE_VAR_UNIFI_PASSWORD}}" - # TODO: Add Glances widget when Glances is deployed - # - glances: - # url: http://indri.tail8d86e.ts.net:61208 - # metric: cpu - - kubernetes.yaml: | - mode: cluster - - docker.yaml: "" - - settings.yaml: | - title: BlumeOps - headerStyle: boxed - quicklaunch: - searchDescriptions: true - showSearchSuggestions: true - provider: custom - url: https://kagi.com/search?q= - suggestionUrl: https://kagisuggest.com/api/autosuggest?q= - layout: - Host Services: - style: column - Content: - style: column - Infrastructure: - style: column - Services: - style: column diff --git a/argocd/manifests/homepage/deployment.yaml b/argocd/manifests/homepage/deployment.yaml index f349399..203e06d 100644 --- a/argocd/manifests/homepage/deployment.yaml +++ b/argocd/manifests/homepage/deployment.yaml @@ -20,7 +20,7 @@ spec: fsGroup: 1000 containers: - name: homepage - image: registry.ops.eblu.me/blumeops/homepage:v1.10.1-a72a0d8 + image: registry.ops.eblu.me/blumeops/homepage securityContext: runAsNonRoot: true allowPrivilegeEscalation: false diff --git a/argocd/manifests/homepage/docker.yaml b/argocd/manifests/homepage/docker.yaml new file mode 100644 index 0000000..e69de29 diff --git a/argocd/manifests/homepage/kubernetes.yaml b/argocd/manifests/homepage/kubernetes.yaml new file mode 100644 index 0000000..0f259a0 --- /dev/null +++ b/argocd/manifests/homepage/kubernetes.yaml @@ -0,0 +1 @@ +mode: cluster diff --git a/argocd/manifests/homepage/kustomization.yaml b/argocd/manifests/homepage/kustomization.yaml index eb0d217..e66796a 100644 --- a/argocd/manifests/homepage/kustomization.yaml +++ b/argocd/manifests/homepage/kustomization.yaml @@ -5,7 +5,6 @@ resources: - serviceaccount.yaml - clusterrole.yaml - clusterrolebinding.yaml - - configmap.yaml - deployment.yaml - service.yaml - ingress-tailscale.yaml @@ -15,3 +14,17 @@ resources: - external-secret-grafana.yaml - external-secret-miniflux.yaml - external-secret-navidrome.yaml + +images: + - name: registry.ops.eblu.me/blumeops/homepage + newTag: v1.10.1-a72a0d8 + +configMapGenerator: + - name: homepage-config + files: + - bookmarks.yaml + - services.yaml + - widgets.yaml + - kubernetes.yaml + - docker.yaml + - settings.yaml diff --git a/argocd/manifests/homepage/services.yaml b/argocd/manifests/homepage/services.yaml new file mode 100644 index 0000000..0f35e9c --- /dev/null +++ b/argocd/manifests/homepage/services.yaml @@ -0,0 +1,76 @@ +- Host Services: + - Forgejo: + href: https://forge.ops.eblu.me + icon: forgejo + description: Git forge + widget: + type: gitea + url: https://forge.ops.eblu.me + key: "{{HOMEPAGE_VAR_FORGEJO_API_KEY}}" + - Registry: + href: https://registry.ops.eblu.me + icon: zot-registry + description: Container registry + - Sifaka NAS: + href: https://nas.ops.eblu.me + icon: synology + description: NAS dashboard + widget: + type: prometheusmetric + url: https://prometheus.ops.eblu.me + metrics: + - label: Used + query: node_filesystem_size_bytes{mountpoint="/Volumes/backups"} - node_filesystem_avail_bytes{mountpoint="/Volumes/backups"} + format: + type: bytes + - label: Total + query: node_filesystem_size_bytes{mountpoint="/Volumes/backups"} + format: + type: bytes + - Borgmatic: + href: https://grafana.ops.eblu.me/d/borgmatic + icon: borgmatic + description: Backup system + widget: + type: prometheusmetric + url: https://prometheus.ops.eblu.me + metrics: + - label: Last backup + query: time() - borgmatic_last_archive_timestamp + format: + type: duration + - label: Archive size + query: borgmatic_repo_deduplicated_size_bytes + format: + type: bytes + - Jellyfin: + href: https://jellyfin.ops.eblu.me + icon: jellyfin + description: Media server + widget: + type: jellyfin + url: https://jellyfin.ops.eblu.me + key: "{{HOMEPAGE_VAR_JELLYFIN_API_KEY}}" + enableBlocks: true + enableNowPlaying: true + # TODO: Add Caddy widget when admin API is enabled (currently admin off) + # - Caddy: + # href: https://indri.tail8d86e.ts.net + # icon: caddy + # description: Reverse proxy + # widget: + # type: caddy + # url: http://indri.tail8d86e.ts.net:2019 +- Infrastructure: + - Authentik: + href: https://authentik.ops.eblu.me + icon: authentik + description: Identity provider + - NVR: + href: https://nvr.ops.eblu.me + icon: frigate.png + description: Network video recorder + - Ntfy: + href: https://ntfy.ops.eblu.me + icon: ntfy.png + description: Push notifications diff --git a/argocd/manifests/homepage/settings.yaml b/argocd/manifests/homepage/settings.yaml new file mode 100644 index 0000000..f8c06fc --- /dev/null +++ b/argocd/manifests/homepage/settings.yaml @@ -0,0 +1,17 @@ +title: BlumeOps +headerStyle: boxed +quicklaunch: + searchDescriptions: true + showSearchSuggestions: true + provider: custom + url: https://kagi.com/search?q= + suggestionUrl: https://kagisuggest.com/api/autosuggest?q= +layout: + Host Services: + style: column + Content: + style: column + Infrastructure: + style: column + Services: + style: column diff --git a/argocd/manifests/homepage/widgets.yaml b/argocd/manifests/homepage/widgets.yaml new file mode 100644 index 0000000..097d806 --- /dev/null +++ b/argocd/manifests/homepage/widgets.yaml @@ -0,0 +1,26 @@ +- greeting: + text_size: xl + text: Welcome to Blue Mops +- datetime: + text_size: lg + format: + dateStyle: long + timeStyle: short + hour12: true +- openweathermap: + label: Camano + latitude: 48.18235 + longitude: -122.52590 + units: imperial + provider: openweathermap + apiKey: "{{HOMEPAGE_VAR_OPENWEATHERMAP_API_KEY}}" + cache: 15 +# TODO: Add UniFi widget when controller is set up +# - unifi_console: +# url: https://192.168.1.1 +# username: homepage +# password: "{{HOMEPAGE_VAR_UNIFI_PASSWORD}}" +# TODO: Add Glances widget when Glances is deployed +# - glances: +# url: http://indri.tail8d86e.ts.net:61208 +# metric: cpu diff --git a/argocd/manifests/kiwix/configmap-sync-script.yaml b/argocd/manifests/kiwix/configmap-sync-script.yaml deleted file mode 100644 index 5be8cae..0000000 --- a/argocd/manifests/kiwix/configmap-sync-script.yaml +++ /dev/null @@ -1,68 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: zim-torrent-sync-script - namespace: kiwix -data: - sync-zim-torrents.sh: | - #!/bin/bash - # Sync ZIM torrents from kiwix ConfigMap to Transmission - # Runs as a sidecar in the kiwix deployment - set -euo pipefail - - TORRENT_LIST="${TORRENT_LIST:-/config/torrents.txt}" - TRANSMISSION_HOST="${TRANSMISSION_HOST:-transmission.torrent.svc.cluster.local}" - TRANSMISSION_PORT="${TRANSMISSION_PORT:-9091}" - - echo "Syncing ZIM torrents to transmission at ${TRANSMISSION_HOST}:${TRANSMISSION_PORT}" - - # Wait for transmission to be ready - # Transmission RPC returns 409 on first request (to provide session ID), which is fine - echo "Waiting for Transmission RPC..." - max_attempts=30 - attempt=0 - until curl -s -o /dev/null -w "%{http_code}" "http://${TRANSMISSION_HOST}:${TRANSMISSION_PORT}/transmission/rpc" | grep -qE "^(200|409)$"; do - attempt=$((attempt + 1)) - if [[ $attempt -ge $max_attempts ]]; then - echo "Transmission not ready after ${max_attempts} attempts, will retry next cycle" - exit 0 # Don't fail, just skip this sync - fi - sleep 10 - done - echo "Transmission is ready" - - # Get current torrents from transmission - # transmission-remote returns header + data + footer, extract just torrent names - current=$(transmission-remote "${TRANSMISSION_HOST}:${TRANSMISSION_PORT}" -l 2>/dev/null | \ - tail -n +2 | head -n -1 | awk '{print $NF}' || true) - - added=0 - skipped=0 - - while IFS= read -r url || [[ -n "$url" ]]; do - # Skip empty lines and comments - [[ -z "$url" || "$url" =~ ^[[:space:]]*# ]] && continue - # Trim whitespace - url=$(echo "$url" | xargs) - [[ -z "$url" ]] && continue - - # Extract base name from URL (remove .torrent extension) - basename=$(basename "$url" .torrent) - # Also try without .zim in case transmission reports it differently - basename_no_zim="${basename%.zim}" - - # Check if already in transmission - if echo "$current" | grep -qF "$basename_no_zim"; then - ((skipped++)) || true - else - if transmission-remote "${TRANSMISSION_HOST}:${TRANSMISSION_PORT}" -a "$url" 2>/dev/null; then - echo "Added: $basename" - ((added++)) || true - else - echo "Warning: Failed to add $url" >&2 - fi - fi - done < "$TORRENT_LIST" - - echo "Sync complete: $added added, $skipped already present" diff --git a/argocd/manifests/kiwix/configmap-zim-torrents.yaml b/argocd/manifests/kiwix/configmap-zim-torrents.yaml deleted file mode 100644 index c862f21..0000000 --- a/argocd/manifests/kiwix/configmap-zim-torrents.yaml +++ /dev/null @@ -1,69 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kiwix-zim-torrents - namespace: kiwix -data: - torrents.txt: | - # Declarative ZIM archive torrent URLs - # These are synced to transmission automatically by the kiwix sidecar - # Format: one URL per line, comments start with # - # - # Users can also add ZIM torrents manually via torrent.tail8d86e.ts.net - # and kiwix will pick them up automatically. - - # Wikipedia - Top 1M English articles (43G) - https://download.kiwix.org/zim/wikipedia/wikipedia_en_top1m_maxi_2025-09.zim.torrent - - # Project Gutenberg - Public domain books (72G) - https://download.kiwix.org/zim/gutenberg/gutenberg_en_all_2023-08.zim.torrent - - # iFixit - Repair guides (3.3G) - https://download.kiwix.org/zim/ifixit/ifixit_en_all_2025-12.zim.torrent - - # Stack Exchange - https://download.kiwix.org/zim/stack_exchange/superuser.com_en_all_2025-12.zim.torrent - https://download.kiwix.org/zim/stack_exchange/math.stackexchange.com_en_all_2025-12.zim.torrent - - # LibreTexts - Open educational resources - https://download.kiwix.org/zim/libretexts/libretexts.org_en_bio_2025-01.zim.torrent - https://download.kiwix.org/zim/libretexts/libretexts.org_en_chem_2025-01.zim.torrent - https://download.kiwix.org/zim/libretexts/libretexts.org_en_eng_2025-01.zim.torrent - https://download.kiwix.org/zim/libretexts/libretexts.org_en_math_2025-01.zim.torrent - https://download.kiwix.org/zim/libretexts/libretexts.org_en_phys_2025-01.zim.torrent - https://download.kiwix.org/zim/libretexts/libretexts.org_en_human_2025-01.zim.torrent - - # DevDocs - Programming documentation - https://download.kiwix.org/zim/devdocs/devdocs_en_bash_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_c_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_click_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_cmake_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_cpp_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_css_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_django-rest-framework_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_django_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_docker_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_duckdb_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_fish_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_gcc_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_git_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_go_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_godot_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_hammerspoon_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_homebrew_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_javascript_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_kubectl_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_kubernetes_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_latex_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_lua_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_markdown_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_nginx_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_nix_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_postgresql_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_python_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_redis_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_sqlite_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_typescript_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_werkzeug_2026-01.zim.torrent - https://download.kiwix.org/zim/devdocs/devdocs_en_zig_2026-01.zim.torrent diff --git a/argocd/manifests/kiwix/cronjob-zim-watcher.yaml b/argocd/manifests/kiwix/cronjob-zim-watcher.yaml index fc8e76a..e6fc7ac 100644 --- a/argocd/manifests/kiwix/cronjob-zim-watcher.yaml +++ b/argocd/manifests/kiwix/cronjob-zim-watcher.yaml @@ -15,7 +15,7 @@ spec: serviceAccountName: zim-watcher containers: - name: watcher - image: registry.ops.eblu.me/blumeops/kubectl:v1.34.4-a72a0d8 + image: registry.ops.eblu.me/blumeops/kubectl command: ["/bin/bash", "-c"] args: - | diff --git a/argocd/manifests/kiwix/deployment.yaml b/argocd/manifests/kiwix/deployment.yaml index 0b51914..bf97f1c 100644 --- a/argocd/manifests/kiwix/deployment.yaml +++ b/argocd/manifests/kiwix/deployment.yaml @@ -20,7 +20,7 @@ spec: containers: # Main kiwix-serve container - name: kiwix-serve - image: registry.ops.eblu.me/blumeops/kiwix-serve:v3.8.1-ffa8727 + image: registry.ops.eblu.me/blumeops/kiwix-serve args: - "/bin/sh" - "-c" @@ -53,7 +53,7 @@ spec: # Sidecar: Syncs declarative ZIM torrents to transmission - name: torrent-sync - image: registry.ops.eblu.me/blumeops/transmission:v4.0.6-r4-ffa8727 + image: registry.ops.eblu.me/blumeops/transmission command: ["/bin/bash", "-c"] args: - | diff --git a/argocd/manifests/kiwix/kustomization.yaml b/argocd/manifests/kiwix/kustomization.yaml index d5e563d..0be5f03 100644 --- a/argocd/manifests/kiwix/kustomization.yaml +++ b/argocd/manifests/kiwix/kustomization.yaml @@ -3,9 +3,23 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: kiwix resources: - - configmap-zim-torrents.yaml - - configmap-sync-script.yaml - deployment.yaml - service.yaml - ingress-tailscale.yaml - cronjob-zim-watcher.yaml + +images: + - name: registry.ops.eblu.me/blumeops/kiwix-serve + newTag: v3.8.1-ffa8727 + - name: registry.ops.eblu.me/blumeops/transmission + newTag: v4.0.6-r4-ffa8727 + - name: registry.ops.eblu.me/blumeops/kubectl + newTag: v1.34.4-a72a0d8 + +configMapGenerator: + - name: kiwix-zim-torrents + files: + - torrents.txt + - name: zim-torrent-sync-script + files: + - sync-zim-torrents.sh diff --git a/argocd/manifests/kiwix/sync-zim-torrents.sh b/argocd/manifests/kiwix/sync-zim-torrents.sh new file mode 100644 index 0000000..df3e2b1 --- /dev/null +++ b/argocd/manifests/kiwix/sync-zim-torrents.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# Sync ZIM torrents from kiwix ConfigMap to Transmission +# Runs as a sidecar in the kiwix deployment +set -euo pipefail + +TORRENT_LIST="${TORRENT_LIST:-/config/torrents.txt}" +TRANSMISSION_HOST="${TRANSMISSION_HOST:-transmission.torrent.svc.cluster.local}" +TRANSMISSION_PORT="${TRANSMISSION_PORT:-9091}" + +echo "Syncing ZIM torrents to transmission at ${TRANSMISSION_HOST}:${TRANSMISSION_PORT}" + +# Wait for transmission to be ready +# Transmission RPC returns 409 on first request (to provide session ID), which is fine +echo "Waiting for Transmission RPC..." +max_attempts=30 +attempt=0 +until curl -s -o /dev/null -w "%{http_code}" "http://${TRANSMISSION_HOST}:${TRANSMISSION_PORT}/transmission/rpc" | grep -qE "^(200|409)$"; do + attempt=$((attempt + 1)) + if [[ $attempt -ge $max_attempts ]]; then + echo "Transmission not ready after ${max_attempts} attempts, will retry next cycle" + exit 0 # Don't fail, just skip this sync + fi + sleep 10 +done +echo "Transmission is ready" + +# Get current torrents from transmission +# transmission-remote returns header + data + footer, extract just torrent names +current=$(transmission-remote "${TRANSMISSION_HOST}:${TRANSMISSION_PORT}" -l 2>/dev/null | \ + tail -n +2 | head -n -1 | awk '{print $NF}' || true) + +added=0 +skipped=0 + +while IFS= read -r url || [[ -n "$url" ]]; do + # Skip empty lines and comments + [[ -z "$url" || "$url" =~ ^[[:space:]]*# ]] && continue + # Trim whitespace + url=$(echo "$url" | xargs) + [[ -z "$url" ]] && continue + + # Extract base name from URL (remove .torrent extension) + basename=$(basename "$url" .torrent) + # Also try without .zim in case transmission reports it differently + basename_no_zim="${basename%.zim}" + + # Check if already in transmission + if echo "$current" | grep -qF "$basename_no_zim"; then + ((skipped++)) || true + else + if transmission-remote "${TRANSMISSION_HOST}:${TRANSMISSION_PORT}" -a "$url" 2>/dev/null; then + echo "Added: $basename" + ((added++)) || true + else + echo "Warning: Failed to add $url" >&2 + fi + fi +done < "$TORRENT_LIST" + +echo "Sync complete: $added added, $skipped already present" diff --git a/argocd/manifests/kiwix/torrents.txt b/argocd/manifests/kiwix/torrents.txt new file mode 100644 index 0000000..a7282a9 --- /dev/null +++ b/argocd/manifests/kiwix/torrents.txt @@ -0,0 +1,61 @@ +# Declarative ZIM archive torrent URLs +# These are synced to transmission automatically by the kiwix sidecar +# Format: one URL per line, comments start with # +# +# Users can also add ZIM torrents manually via torrent.tail8d86e.ts.net +# and kiwix will pick them up automatically. + +# Wikipedia - Top 1M English articles (43G) +https://download.kiwix.org/zim/wikipedia/wikipedia_en_top1m_maxi_2025-09.zim.torrent + +# Project Gutenberg - Public domain books (72G) +https://download.kiwix.org/zim/gutenberg/gutenberg_en_all_2023-08.zim.torrent + +# iFixit - Repair guides (3.3G) +https://download.kiwix.org/zim/ifixit/ifixit_en_all_2025-12.zim.torrent + +# Stack Exchange +https://download.kiwix.org/zim/stack_exchange/superuser.com_en_all_2025-12.zim.torrent +https://download.kiwix.org/zim/stack_exchange/math.stackexchange.com_en_all_2025-12.zim.torrent + +# LibreTexts - Open educational resources +https://download.kiwix.org/zim/libretexts/libretexts.org_en_bio_2025-01.zim.torrent +https://download.kiwix.org/zim/libretexts/libretexts.org_en_chem_2025-01.zim.torrent +https://download.kiwix.org/zim/libretexts/libretexts.org_en_eng_2025-01.zim.torrent +https://download.kiwix.org/zim/libretexts/libretexts.org_en_math_2025-01.zim.torrent +https://download.kiwix.org/zim/libretexts/libretexts.org_en_phys_2025-01.zim.torrent +https://download.kiwix.org/zim/libretexts/libretexts.org_en_human_2025-01.zim.torrent + +# DevDocs - Programming documentation +https://download.kiwix.org/zim/devdocs/devdocs_en_bash_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_c_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_click_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_cmake_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_cpp_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_css_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_django-rest-framework_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_django_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_docker_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_duckdb_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_fish_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_gcc_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_git_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_go_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_godot_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_hammerspoon_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_homebrew_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_javascript_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_kubectl_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_kubernetes_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_latex_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_lua_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_markdown_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_nginx_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_nix_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_postgresql_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_python_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_redis_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_sqlite_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_typescript_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_werkzeug_2026-01.zim.torrent +https://download.kiwix.org/zim/devdocs/devdocs_en_zig_2026-01.zim.torrent diff --git a/argocd/manifests/kube-state-metrics/deployment.yaml b/argocd/manifests/kube-state-metrics/deployment.yaml index 2ba12ba..cba8cac 100644 --- a/argocd/manifests/kube-state-metrics/deployment.yaml +++ b/argocd/manifests/kube-state-metrics/deployment.yaml @@ -18,7 +18,7 @@ spec: serviceAccountName: kube-state-metrics containers: - name: kube-state-metrics - image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.18.0 + image: registry.k8s.io/kube-state-metrics/kube-state-metrics ports: - containerPort: 8080 name: http-metrics diff --git a/argocd/manifests/kube-state-metrics/kustomization.yaml b/argocd/manifests/kube-state-metrics/kustomization.yaml index bc60c0b..005cba8 100644 --- a/argocd/manifests/kube-state-metrics/kustomization.yaml +++ b/argocd/manifests/kube-state-metrics/kustomization.yaml @@ -4,3 +4,6 @@ resources: - rbac.yaml - deployment.yaml - service.yaml +images: + - name: registry.k8s.io/kube-state-metrics/kube-state-metrics + newTag: v2.18.0 diff --git a/argocd/manifests/loki/configmap.yaml b/argocd/manifests/loki/configmap.yaml deleted file mode 100644 index 19c516b..0000000 --- a/argocd/manifests/loki/configmap.yaml +++ /dev/null @@ -1,58 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: loki-config - namespace: monitoring -data: - loki-config.yaml: | - auth_enabled: false - - server: - http_listen_port: 3100 - http_listen_address: 0.0.0.0 - grpc_listen_port: 9096 - - common: - instance_addr: 127.0.0.1 - path_prefix: /loki - storage: - filesystem: - chunks_directory: /loki/chunks - rules_directory: /loki/rules - replication_factor: 1 - ring: - kvstore: - store: inmemory - - query_range: - results_cache: - cache: - embedded_cache: - enabled: true - max_size_mb: 100 - - schema_config: - configs: - - from: 2024-01-01 - store: tsdb - object_store: filesystem - schema: v13 - index: - prefix: index_ - period: 24h - - storage_config: - tsdb_shipper: - active_index_directory: /loki/tsdb-index - cache_location: /loki/tsdb-cache - - limits_config: - retention_period: 744h # 31 days - - compactor: - working_directory: /loki/compactor - compaction_interval: 10m - retention_enabled: true - retention_delete_delay: 2h - retention_delete_worker_count: 150 - delete_request_store: filesystem diff --git a/argocd/manifests/loki/kustomization.yaml b/argocd/manifests/loki/kustomization.yaml index 1c65acb..c305868 100644 --- a/argocd/manifests/loki/kustomization.yaml +++ b/argocd/manifests/loki/kustomization.yaml @@ -4,7 +4,15 @@ kind: Kustomization namespace: monitoring resources: - - configmap.yaml - statefulset.yaml - service.yaml - ingress-tailscale.yaml + +images: + - name: grafana/loki + newTag: "3.6.5" + +configMapGenerator: + - name: loki-config + files: + - loki-config.yaml diff --git a/argocd/manifests/loki/loki-config.yaml b/argocd/manifests/loki/loki-config.yaml new file mode 100644 index 0000000..5210f1b --- /dev/null +++ b/argocd/manifests/loki/loki-config.yaml @@ -0,0 +1,51 @@ +auth_enabled: false + +server: + http_listen_port: 3100 + http_listen_address: 0.0.0.0 + grpc_listen_port: 9096 + +common: + instance_addr: 127.0.0.1 + path_prefix: /loki + storage: + filesystem: + chunks_directory: /loki/chunks + rules_directory: /loki/rules + replication_factor: 1 + ring: + kvstore: + store: inmemory + +query_range: + results_cache: + cache: + embedded_cache: + enabled: true + max_size_mb: 100 + +schema_config: + configs: + - from: 2024-01-01 + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: index_ + period: 24h + +storage_config: + tsdb_shipper: + active_index_directory: /loki/tsdb-index + cache_location: /loki/tsdb-cache + +limits_config: + retention_period: 744h # 31 days + +compactor: + working_directory: /loki/compactor + compaction_interval: 10m + retention_enabled: true + retention_delete_delay: 2h + retention_delete_worker_count: 150 + delete_request_store: filesystem diff --git a/argocd/manifests/loki/statefulset.yaml b/argocd/manifests/loki/statefulset.yaml index d3a75a7..5683eab 100644 --- a/argocd/manifests/loki/statefulset.yaml +++ b/argocd/manifests/loki/statefulset.yaml @@ -20,7 +20,7 @@ spec: runAsUser: 10001 containers: - name: loki - image: grafana/loki:3.6.5 + image: grafana/loki args: - -config.file=/etc/loki/loki-config.yaml ports: diff --git a/argocd/manifests/miniflux/deployment.yaml b/argocd/manifests/miniflux/deployment.yaml index 668471e..e139de3 100644 --- a/argocd/manifests/miniflux/deployment.yaml +++ b/argocd/manifests/miniflux/deployment.yaml @@ -15,7 +15,7 @@ spec: spec: containers: - name: miniflux - image: registry.ops.eblu.me/blumeops/miniflux:v2.2.17-a72a0d8 + image: registry.ops.eblu.me/blumeops/miniflux ports: - containerPort: 8080 env: diff --git a/argocd/manifests/miniflux/kustomization.yaml b/argocd/manifests/miniflux/kustomization.yaml index 80927eb..992c8ae 100644 --- a/argocd/manifests/miniflux/kustomization.yaml +++ b/argocd/manifests/miniflux/kustomization.yaml @@ -7,3 +7,7 @@ resources: - deployment.yaml - service.yaml - ingress-tailscale.yaml + +images: + - name: registry.ops.eblu.me/blumeops/miniflux + newTag: v2.2.17-a72a0d8 diff --git a/argocd/manifests/mosquitto/configmap.yaml b/argocd/manifests/mosquitto/configmap.yaml deleted file mode 100644 index c0cd870..0000000 --- a/argocd/manifests/mosquitto/configmap.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: mosquitto-config - namespace: mqtt -data: - mosquitto.conf: | - listener 1883 - allow_anonymous true - persistence false diff --git a/argocd/manifests/mosquitto/deployment.yaml b/argocd/manifests/mosquitto/deployment.yaml index 55abf96..b58d926 100644 --- a/argocd/manifests/mosquitto/deployment.yaml +++ b/argocd/manifests/mosquitto/deployment.yaml @@ -16,7 +16,7 @@ spec: spec: containers: - name: mosquitto - image: eclipse-mosquitto:2.0.22 + image: eclipse-mosquitto ports: - containerPort: 1883 name: mqtt diff --git a/argocd/manifests/mosquitto/kustomization.yaml b/argocd/manifests/mosquitto/kustomization.yaml index 5a9cfa1..e468120 100644 --- a/argocd/manifests/mosquitto/kustomization.yaml +++ b/argocd/manifests/mosquitto/kustomization.yaml @@ -3,6 +3,12 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: mqtt resources: - - configmap.yaml - deployment.yaml - service.yaml +images: + - name: eclipse-mosquitto + newTag: "2.0.22" +configMapGenerator: + - name: mosquitto-config + files: + - mosquitto.conf diff --git a/argocd/manifests/mosquitto/mosquitto.conf b/argocd/manifests/mosquitto/mosquitto.conf new file mode 100644 index 0000000..0e3b61e --- /dev/null +++ b/argocd/manifests/mosquitto/mosquitto.conf @@ -0,0 +1,3 @@ +listener 1883 +allow_anonymous true +persistence false diff --git a/argocd/manifests/navidrome/deployment.yaml b/argocd/manifests/navidrome/deployment.yaml index 28eaf2d..5da3948 100644 --- a/argocd/manifests/navidrome/deployment.yaml +++ b/argocd/manifests/navidrome/deployment.yaml @@ -20,7 +20,7 @@ spec: fsGroup: 1000 containers: - name: navidrome - image: registry.ops.eblu.me/blumeops/navidrome:v0.60.3-a72a0d8 + image: registry.ops.eblu.me/blumeops/navidrome securityContext: runAsNonRoot: true allowPrivilegeEscalation: false diff --git a/argocd/manifests/navidrome/kustomization.yaml b/argocd/manifests/navidrome/kustomization.yaml index bf62c5b..b625c82 100644 --- a/argocd/manifests/navidrome/kustomization.yaml +++ b/argocd/manifests/navidrome/kustomization.yaml @@ -9,3 +9,6 @@ resources: - deployment.yaml - service.yaml - ingress-tailscale.yaml +images: + - name: registry.ops.eblu.me/blumeops/navidrome + newTag: v0.60.3-a72a0d8 diff --git a/argocd/manifests/ntfy/configmap.yaml b/argocd/manifests/ntfy/configmap.yaml deleted file mode 100644 index 584eba1..0000000 --- a/argocd/manifests/ntfy/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: ntfy-config - namespace: ntfy -data: - server.yml: | - base-url: https://ntfy.ops.eblu.me - upstream-base-url: https://ntfy.sh - attachment-cache-dir: /var/cache/ntfy/attachments - attachment-total-size-limit: 1G - attachment-file-size-limit: 10M - attachment-expiry-duration: 24h diff --git a/argocd/manifests/ntfy/deployment.yaml b/argocd/manifests/ntfy/deployment.yaml index d471394..2a58604 100644 --- a/argocd/manifests/ntfy/deployment.yaml +++ b/argocd/manifests/ntfy/deployment.yaml @@ -16,7 +16,7 @@ spec: spec: containers: - name: ntfy - image: registry.ops.eblu.me/blumeops/ntfy:v2.17.0-ffa8727-nix + image: registry.ops.eblu.me/blumeops/ntfy args: ["serve", "--config", "/etc/ntfy/server.yml"] ports: - containerPort: 80 diff --git a/argocd/manifests/ntfy/kustomization.yaml b/argocd/manifests/ntfy/kustomization.yaml index 851171f..a4852ac 100644 --- a/argocd/manifests/ntfy/kustomization.yaml +++ b/argocd/manifests/ntfy/kustomization.yaml @@ -3,7 +3,13 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: ntfy resources: - - configmap.yaml - deployment.yaml - service.yaml - ingress-tailscale.yaml +images: + - name: registry.ops.eblu.me/blumeops/ntfy + newTag: v2.17.0-ffa8727-nix +configMapGenerator: + - name: ntfy-config + files: + - server.yml diff --git a/argocd/manifests/ntfy/server.yml b/argocd/manifests/ntfy/server.yml new file mode 100644 index 0000000..0f53b0c --- /dev/null +++ b/argocd/manifests/ntfy/server.yml @@ -0,0 +1,6 @@ +base-url: https://ntfy.ops.eblu.me +upstream-base-url: https://ntfy.sh +attachment-cache-dir: /var/cache/ntfy/attachments +attachment-total-size-limit: 1G +attachment-file-size-limit: 10M +attachment-expiry-duration: 24h diff --git a/argocd/manifests/nvidia-device-plugin/daemonset.yaml b/argocd/manifests/nvidia-device-plugin/daemonset.yaml index 479d6e9..4c57a76 100644 --- a/argocd/manifests/nvidia-device-plugin/daemonset.yaml +++ b/argocd/manifests/nvidia-device-plugin/daemonset.yaml @@ -22,7 +22,7 @@ spec: priorityClassName: system-node-critical containers: - name: nvidia-device-plugin - image: nvcr.io/nvidia/k8s-device-plugin:v0.18.2 + image: nvcr.io/nvidia/k8s-device-plugin args: - --device-id-strategy=index env: diff --git a/argocd/manifests/nvidia-device-plugin/kustomization.yaml b/argocd/manifests/nvidia-device-plugin/kustomization.yaml new file mode 100644 index 0000000..4ffe2d9 --- /dev/null +++ b/argocd/manifests/nvidia-device-plugin/kustomization.yaml @@ -0,0 +1,12 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: nvidia-device-plugin + +resources: + - daemonset.yaml + - runtime-class.yaml + +images: + - name: nvcr.io/nvidia/k8s-device-plugin + newTag: v0.18.2 diff --git a/argocd/manifests/prometheus/configmap.yaml b/argocd/manifests/prometheus/configmap.yaml deleted file mode 100644 index 09baf83..0000000 --- a/argocd/manifests/prometheus/configmap.yaml +++ /dev/null @@ -1,53 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: prometheus-config - namespace: monitoring -data: - prometheus.yml: | - global: - scrape_interval: 15s - evaluation_interval: 15s - - # Indri system metrics are pushed via Alloy remote_write - # K8s services are scraped directly - - scrape_configs: - # Sifaka NAS exporters (via Caddy L4 TCP proxy on indri) - - job_name: "node-exporter-sifaka" - static_configs: - - targets: ["nas.ops.eblu.me:9100"] - - - job_name: "smartctl-sifaka" - scrape_interval: 60s - static_configs: - - targets: ["nas.ops.eblu.me:9633"] - - # CNPG PostgreSQL metrics (k8s internal) - - job_name: "cnpg-postgres" - static_configs: - - targets: ["blumeops-pg-metrics-tailscale.databases.svc.cluster.local:9187"] - labels: - instance: "blumeops-pg" - - # Prometheus self-monitoring - - job_name: "prometheus" - static_configs: - - targets: ["localhost:9090"] - - # Loki metrics - - job_name: "loki" - static_configs: - - targets: ["loki.monitoring.svc.cluster.local:3100"] - - # Kubernetes state metrics (pods, deployments, resource usage, etc.) - - job_name: "kube-state-metrics" - static_configs: - - targets: ["kube-state-metrics.monitoring.svc.cluster.local:8080"] - - # Frigate NVR metrics (via Caddy on indri — Frigate runs on ringtail) - - job_name: "frigate" - scheme: https - static_configs: - - targets: ["nvr.ops.eblu.me"] - metrics_path: /api/metrics diff --git a/argocd/manifests/prometheus/kustomization.yaml b/argocd/manifests/prometheus/kustomization.yaml index 1c65acb..de9fdd2 100644 --- a/argocd/manifests/prometheus/kustomization.yaml +++ b/argocd/manifests/prometheus/kustomization.yaml @@ -4,7 +4,15 @@ kind: Kustomization namespace: monitoring resources: - - configmap.yaml - statefulset.yaml - service.yaml - ingress-tailscale.yaml + +images: + - name: registry.ops.eblu.me/blumeops/prometheus + newTag: v3.9.1-2ba5d8a + +configMapGenerator: + - name: prometheus-config + files: + - prometheus.yml diff --git a/argocd/manifests/prometheus/prometheus.yml b/argocd/manifests/prometheus/prometheus.yml new file mode 100644 index 0000000..09d1f4f --- /dev/null +++ b/argocd/manifests/prometheus/prometheus.yml @@ -0,0 +1,46 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +# Indri system metrics are pushed via Alloy remote_write +# K8s services are scraped directly + +scrape_configs: + # Sifaka NAS exporters (via Caddy L4 TCP proxy on indri) + - job_name: "node-exporter-sifaka" + static_configs: + - targets: ["nas.ops.eblu.me:9100"] + + - job_name: "smartctl-sifaka" + scrape_interval: 60s + static_configs: + - targets: ["nas.ops.eblu.me:9633"] + + # CNPG PostgreSQL metrics (k8s internal) + - job_name: "cnpg-postgres" + static_configs: + - targets: ["blumeops-pg-metrics-tailscale.databases.svc.cluster.local:9187"] + labels: + instance: "blumeops-pg" + + # Prometheus self-monitoring + - job_name: "prometheus" + static_configs: + - targets: ["localhost:9090"] + + # Loki metrics + - job_name: "loki" + static_configs: + - targets: ["loki.monitoring.svc.cluster.local:3100"] + + # Kubernetes state metrics (pods, deployments, resource usage, etc.) + - job_name: "kube-state-metrics" + static_configs: + - targets: ["kube-state-metrics.monitoring.svc.cluster.local:8080"] + + # Frigate NVR metrics (via Caddy on indri — Frigate runs on ringtail) + - job_name: "frigate" + scheme: https + static_configs: + - targets: ["nvr.ops.eblu.me"] + metrics_path: /api/metrics diff --git a/argocd/manifests/prometheus/statefulset.yaml b/argocd/manifests/prometheus/statefulset.yaml index ce2d810..24953e0 100644 --- a/argocd/manifests/prometheus/statefulset.yaml +++ b/argocd/manifests/prometheus/statefulset.yaml @@ -20,7 +20,7 @@ spec: runAsUser: 65534 containers: - name: prometheus - image: registry.ops.eblu.me/blumeops/prometheus:v3.9.1-2ba5d8a + image: registry.ops.eblu.me/blumeops/prometheus args: - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.path=/prometheus diff --git a/argocd/manifests/tailscale-operator-base/kustomization.yaml b/argocd/manifests/tailscale-operator-base/kustomization.yaml index 980b8e3..82ff89e 100644 --- a/argocd/manifests/tailscale-operator-base/kustomization.yaml +++ b/argocd/manifests/tailscale-operator-base/kustomization.yaml @@ -8,3 +8,7 @@ resources: - operator.yaml - proxyclass.yaml - dnsconfig.yaml + +images: + - name: docker.io/tailscale/k8s-operator + newTag: v1.94.2 diff --git a/argocd/manifests/tailscale-operator-base/operator.yaml b/argocd/manifests/tailscale-operator-base/operator.yaml index ad28d40..adfa1c2 100644 --- a/argocd/manifests/tailscale-operator-base/operator.yaml +++ b/argocd/manifests/tailscale-operator-base/operator.yaml @@ -5362,7 +5362,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.uid - image: docker.io/tailscale/k8s-operator:v1.94.2 + image: docker.io/tailscale/k8s-operator imagePullPolicy: Always name: operator volumeMounts: diff --git a/argocd/manifests/teslamate/deployment.yaml b/argocd/manifests/teslamate/deployment.yaml index b6757c4..c590185 100644 --- a/argocd/manifests/teslamate/deployment.yaml +++ b/argocd/manifests/teslamate/deployment.yaml @@ -15,7 +15,7 @@ spec: spec: containers: - name: teslamate - image: registry.ops.eblu.me/blumeops/teslamate:v2.2.0-ffa8727 + image: registry.ops.eblu.me/blumeops/teslamate ports: - containerPort: 4000 env: diff --git a/argocd/manifests/teslamate/kustomization.yaml b/argocd/manifests/teslamate/kustomization.yaml index 3be2de4..3ea707c 100644 --- a/argocd/manifests/teslamate/kustomization.yaml +++ b/argocd/manifests/teslamate/kustomization.yaml @@ -9,3 +9,7 @@ resources: - ingress-tailscale.yaml - external-secret-db.yaml - external-secret-encryption-key.yaml + +images: + - name: registry.ops.eblu.me/blumeops/teslamate + newTag: v2.2.0-ffa8727 diff --git a/argocd/manifests/torrent/deployment.yaml b/argocd/manifests/torrent/deployment.yaml index 90ac128..bf1e8b1 100644 --- a/argocd/manifests/torrent/deployment.yaml +++ b/argocd/manifests/torrent/deployment.yaml @@ -16,7 +16,7 @@ spec: spec: containers: - name: transmission - image: registry.ops.eblu.me/blumeops/transmission:v4.0.6-r4-ffa8727 + image: registry.ops.eblu.me/blumeops/transmission env: - name: PUID value: "1000" diff --git a/argocd/manifests/torrent/kustomization.yaml b/argocd/manifests/torrent/kustomization.yaml index 57c6197..2bd029f 100644 --- a/argocd/manifests/torrent/kustomization.yaml +++ b/argocd/manifests/torrent/kustomization.yaml @@ -8,3 +8,6 @@ resources: - deployment.yaml - service.yaml - ingress-tailscale.yaml +images: + - name: registry.ops.eblu.me/blumeops/transmission + newTag: v4.0.6-r4-ffa8727 diff --git a/docs/changelog.d/feature-kustomize-images-configmapgen.infra.md b/docs/changelog.d/feature-kustomize-images-configmapgen.infra.md new file mode 100644 index 0000000..18eeab2 --- /dev/null +++ b/docs/changelog.d/feature-kustomize-images-configmapgen.infra.md @@ -0,0 +1 @@ +Move image tags to kustomize `images:` transformer across 22 services and replace hand-written ConfigMaps with `configMapGenerator:` in 12 services, enabling content-hash-based automatic rollouts on config changes.