From bc57edc1a4733375bc42d1f6765e23a821cf5e70 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Thu, 19 Feb 2026 10:54:22 -0800 Subject: [PATCH 1/4] Port Mosquitto and ntfy to ringtail k3s, retire Apple Silicon Detector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move MQTT broker and push notification services from indri minikube to ringtail k3s cluster. Delete the frigate_detector ansible role — detection will use ringtail's RTX 4080 when Frigate is ported. Manual cleanup needed on indri: ssh indri 'launchctl unload ~/Library/LaunchAgents/mcquack.eblume.frigate-detector.plist' ssh indri 'rm ~/Library/LaunchAgents/mcquack.eblume.frigate-detector.plist' Co-Authored-By: Claude Opus 4.6 --- ansible/playbooks/indri.yml | 2 - .../roles/frigate_detector/defaults/main.yml | 8 --- .../roles/frigate_detector/handlers/main.yml | 6 -- ansible/roles/frigate_detector/tasks/main.yml | 55 ------------------- .../mcquack.eblume.frigate-detector.plist.j2 | 43 --------------- ...mosquitto.yaml => mosquitto-ringtail.yaml} | 4 +- argocd/apps/{ntfy.yaml => ntfy-ringtail.yaml} | 4 +- .../feature-port-mqtt-ntfy-ringtail.infra.md | 1 + docs/reference/services/frigate.md | 8 +-- 9 files changed, 8 insertions(+), 123 deletions(-) delete mode 100644 ansible/roles/frigate_detector/defaults/main.yml delete mode 100644 ansible/roles/frigate_detector/handlers/main.yml delete mode 100644 ansible/roles/frigate_detector/tasks/main.yml delete mode 100644 ansible/roles/frigate_detector/templates/mcquack.eblume.frigate-detector.plist.j2 rename argocd/apps/{mosquitto.yaml => mosquitto-ringtail.yaml} (81%) rename argocd/apps/{ntfy.yaml => ntfy-ringtail.yaml} (82%) create mode 100644 docs/changelog.d/feature-port-mqtt-ntfy-ringtail.infra.md diff --git a/ansible/playbooks/indri.yml b/ansible/playbooks/indri.yml index f1c7d11..3042366 100644 --- a/ansible/playbooks/indri.yml +++ b/ansible/playbooks/indri.yml @@ -175,5 +175,3 @@ tags: jellyfin_metrics - role: caddy tags: caddy - - role: frigate_detector - tags: frigate_detector diff --git a/ansible/roles/frigate_detector/defaults/main.yml b/ansible/roles/frigate_detector/defaults/main.yml deleted file mode 100644 index 71af21d..0000000 --- a/ansible/roles/frigate_detector/defaults/main.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -frigate_detector_repo: https://forge.ops.eblu.me/eblume/apple-silicon-detector.git -frigate_detector_dir: "{{ ansible_env.HOME }}/code/3rd/apple-silicon-detector" -frigate_detector_endpoint: "tcp://*:5555" -frigate_detector_model: AUTO -frigate_detector_log_dir: "{{ ansible_env.HOME }}/Library/Logs" -frigate_detector_uv_binary: "{{ ansible_env.HOME }}/.local/share/mise/installs/uv/latest/uv-aarch64-apple-darwin/uv" -frigate_detector_python: "3.12" diff --git a/ansible/roles/frigate_detector/handlers/main.yml b/ansible/roles/frigate_detector/handlers/main.yml deleted file mode 100644 index 850c66c..0000000 --- a/ansible/roles/frigate_detector/handlers/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: Restart frigate-detector - ansible.builtin.shell: | - launchctl unload ~/Library/LaunchAgents/mcquack.eblume.frigate-detector.plist 2>/dev/null || true - launchctl load ~/Library/LaunchAgents/mcquack.eblume.frigate-detector.plist - changed_when: true diff --git a/ansible/roles/frigate_detector/tasks/main.yml b/ansible/roles/frigate_detector/tasks/main.yml deleted file mode 100644 index 07b5ffc..0000000 --- a/ansible/roles/frigate_detector/tasks/main.yml +++ /dev/null @@ -1,55 +0,0 @@ ---- -# Apple Silicon ZMQ detector for Frigate -# Runs natively on macOS, using CoreML / Neural Engine for ~15ms inference. -# Communicates with Frigate via ZMQ over TCP. -# Dependencies managed inline by uv — no venv or make install needed. -# -# ONE-TIME SETUP (before running ansible): -# -# 1. Clone the repo (use localhost:3001 - hairpinning doesn't work): -# ssh indri 'git clone http://localhost:3001/eblume/apple-silicon-detector.git ~/code/3rd/apple-silicon-detector' -# -# 2. Run ansible to deploy LaunchAgent: -# mise run provision-indri -- --tags frigate_detector - -- name: Verify apple-silicon-detector repo exists - ansible.builtin.stat: - path: "{{ frigate_detector_dir }}/detector/zmq_onnx_client.py" - register: frigate_detector_stat - -- name: Fail if apple-silicon-detector not found - ansible.builtin.fail: - msg: | - apple-silicon-detector not found at {{ frigate_detector_dir }}. - Please clone first: - ssh indri 'git clone {{ frigate_detector_repo }} {{ frigate_detector_dir }}' - when: not frigate_detector_stat.stat.exists - -- name: Verify uv binary exists - ansible.builtin.stat: - path: "{{ frigate_detector_uv_binary }}" - register: frigate_detector_uv_stat - -- name: Fail if uv not found - ansible.builtin.fail: - msg: "uv not found at {{ frigate_detector_uv_binary }}. Install via mise: mise use uv@latest" - when: not frigate_detector_uv_stat.stat.exists - -- name: Deploy frigate-detector LaunchAgent plist - ansible.builtin.template: - src: mcquack.eblume.frigate-detector.plist.j2 - dest: ~/Library/LaunchAgents/mcquack.eblume.frigate-detector.plist - mode: '0644' - notify: Restart frigate-detector - -- name: Check if frigate-detector LaunchAgent is loaded - ansible.builtin.command: launchctl list mcquack.eblume.frigate-detector - register: frigate_detector_launchctl_check - changed_when: false - failed_when: false - -- name: Load frigate-detector LaunchAgent if not loaded - ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.frigate-detector.plist - when: frigate_detector_launchctl_check.rc != 0 - changed_when: true - failed_when: false diff --git a/ansible/roles/frigate_detector/templates/mcquack.eblume.frigate-detector.plist.j2 b/ansible/roles/frigate_detector/templates/mcquack.eblume.frigate-detector.plist.j2 deleted file mode 100644 index 87921ac..0000000 --- a/ansible/roles/frigate_detector/templates/mcquack.eblume.frigate-detector.plist.j2 +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Label - mcquack.eblume.frigate-detector - ProgramArguments - - {{ frigate_detector_uv_binary }} - run - --python - {{ frigate_detector_python }} - --with - numpy==1.26.* - --with - opencv-python-headless==4.11.0.* - --with - opencv-contrib-python==4.11.0.* - --with - onnxruntime==1.22.* - --with - pyzmq==26.2.* - --with - pydantic==2.10.* - detector/zmq_onnx_client.py - --model - {{ frigate_detector_model }} - --endpoint - {{ frigate_detector_endpoint }} - - WorkingDirectory - {{ frigate_detector_dir }} - RunAtLoad - - KeepAlive - - StandardOutPath - {{ frigate_detector_log_dir }}/mcquack.frigate-detector.out.log - StandardErrorPath - {{ frigate_detector_log_dir }}/mcquack.frigate-detector.err.log - - diff --git a/argocd/apps/mosquitto.yaml b/argocd/apps/mosquitto-ringtail.yaml similarity index 81% rename from argocd/apps/mosquitto.yaml rename to argocd/apps/mosquitto-ringtail.yaml index 976dd5c..e5fc92f 100644 --- a/argocd/apps/mosquitto.yaml +++ b/argocd/apps/mosquitto-ringtail.yaml @@ -2,7 +2,7 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: - name: mosquitto + name: mosquitto-ringtail namespace: argocd spec: project: default @@ -11,7 +11,7 @@ spec: targetRevision: main path: argocd/manifests/mosquitto destination: - server: https://kubernetes.default.svc + server: https://ringtail.tail8d86e.ts.net:6443 namespace: mqtt syncPolicy: syncOptions: diff --git a/argocd/apps/ntfy.yaml b/argocd/apps/ntfy-ringtail.yaml similarity index 82% rename from argocd/apps/ntfy.yaml rename to argocd/apps/ntfy-ringtail.yaml index 8846b7f..65b10f7 100644 --- a/argocd/apps/ntfy.yaml +++ b/argocd/apps/ntfy-ringtail.yaml @@ -2,7 +2,7 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: - name: ntfy + name: ntfy-ringtail namespace: argocd spec: project: default @@ -11,7 +11,7 @@ spec: targetRevision: main path: argocd/manifests/ntfy destination: - server: https://kubernetes.default.svc + server: https://ringtail.tail8d86e.ts.net:6443 namespace: ntfy syncPolicy: syncOptions: diff --git a/docs/changelog.d/feature-port-mqtt-ntfy-ringtail.infra.md b/docs/changelog.d/feature-port-mqtt-ntfy-ringtail.infra.md new file mode 100644 index 0000000..f58dac9 --- /dev/null +++ b/docs/changelog.d/feature-port-mqtt-ntfy-ringtail.infra.md @@ -0,0 +1 @@ +Port Mosquitto (MQTT) and ntfy to ringtail k3s; retire Apple Silicon Detector from indri. diff --git a/docs/reference/services/frigate.md b/docs/reference/services/frigate.md index edd93af..0e661fe 100644 --- a/docs/reference/services/frigate.md +++ b/docs/reference/services/frigate.md @@ -27,12 +27,10 @@ Open-source network video recorder (NVR) with object detection. Runs cloud-free ReoLink Camera (GableCam) │ RTSP ▼ -Frigate pod (minikube) +Frigate pod (ringtail k3s) ├── go2rtc — RTSP restream proxy ├── FFmpeg — stream decoding - ├── ZMQ detector ──tcp://host.minikube.internal:5555──→ apple-silicon-detector - │ ├── CoreML / Neural Engine - │ └── LaunchAgent (mcquack.eblume.frigate-detector) + ├── detector — GPU-accelerated (RTX 4080, pending migration) ├── /media/frigate — NFS recordings (sifaka) └── /db — SQLite (local PVC) │ @@ -49,7 +47,7 @@ Camera credentials are stored in 1Password and synced via [[external-secrets]] t ## Detection -Object detection uses the [apple-silicon-detector](https://github.com/frigate-nvr/apple-silicon-detector) with a YOLOv9-m model (`yolo-generic`, 320x320), running natively on [[indri]] as a LaunchAgent (`mcquack.eblume.frigate-detector`). It communicates with Frigate via ZMQ over TCP (`tcp://host.minikube.internal:5555`), using CoreML with partial Neural Engine acceleration (~100-170ms inference). Model ONNX files are stored on the NFS volume at `/media/frigate/models/`. +Object detection will use GPU-accelerated inference on [[ringtail]]'s RTX 4080 (migration pending). The previous Apple Silicon Detector on [[indri]] has been retired. Two zones are configured: `driveway_entrance` (triggers review alerts for person/car) and `driveway` (triggers review detections). -- 2.50.1 (Apple Git-155) From 2d7a353751649fcbc7e1c076aa82b47b852f6e24 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Thu, 19 Feb 2026 11:01:55 -0800 Subject: [PATCH 2/4] Add nix container build for ntfy Uses nixpkgs ntfy-sh package instead of the multi-stage Dockerfile build. After merge, release with: mise run container-tag-and-release ntfy v1.1.0 Then update argocd/manifests/ntfy/deployment.yaml image to the -nix tag. Co-Authored-By: Claude Opus 4.6 --- containers/ntfy/default.nix | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 containers/ntfy/default.nix diff --git a/containers/ntfy/default.nix b/containers/ntfy/default.nix new file mode 100644 index 0000000..47a43ab --- /dev/null +++ b/containers/ntfy/default.nix @@ -0,0 +1,27 @@ +# Nix-built ntfy push notification server +# Replaces the multi-stage Dockerfile (Node + Go + Alpine) with nixpkgs ntfy-sh +# Built with dockerTools.buildLayeredImage for efficient layer caching +{ pkgs ? import { } }: + +pkgs.dockerTools.buildLayeredImage { + name = "blumeops/ntfy"; + tag = "latest"; + + contents = [ + pkgs.ntfy-sh + pkgs.cacert + pkgs.tzdata + ]; + + config = { + Entrypoint = [ "${pkgs.ntfy-sh}/bin/ntfy" ]; + Env = [ + "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" + "TZDIR=${pkgs.tzdata}/share/zoneinfo" + ]; + ExposedPorts = { + "80/tcp" = { }; + }; + User = "65534"; + }; +} -- 2.50.1 (Apple Git-155) From 3c5cb897f3b21626f295dded2cab8652882866a7 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Thu, 19 Feb 2026 11:07:53 -0800 Subject: [PATCH 3/4] Update ntfy deployment to use nix-built container image Co-Authored-By: Claude Opus 4.6 --- argocd/manifests/ntfy/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/argocd/manifests/ntfy/deployment.yaml b/argocd/manifests/ntfy/deployment.yaml index 7bff658..8515950 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:v1.0.0 + image: registry.ops.eblu.me/blumeops/ntfy:v1.1.0-nix args: ["serve", "--config", "/etc/ntfy/server.yml"] ports: - containerPort: 80 -- 2.50.1 (Apple Git-155) From add910c9236b3b79625883a5f852e39680dbeb49 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Thu, 19 Feb 2026 11:14:06 -0800 Subject: [PATCH 4/4] Rename ArgoCD apps to mqtt and ntfy (drop -ringtail suffix) Co-Authored-By: Claude Opus 4.6 --- argocd/apps/{mosquitto-ringtail.yaml => mqtt.yaml} | 2 +- argocd/apps/{ntfy-ringtail.yaml => ntfy.yaml} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename argocd/apps/{mosquitto-ringtail.yaml => mqtt.yaml} (93%) rename argocd/apps/{ntfy-ringtail.yaml => ntfy.yaml} (94%) diff --git a/argocd/apps/mosquitto-ringtail.yaml b/argocd/apps/mqtt.yaml similarity index 93% rename from argocd/apps/mosquitto-ringtail.yaml rename to argocd/apps/mqtt.yaml index e5fc92f..61959aa 100644 --- a/argocd/apps/mosquitto-ringtail.yaml +++ b/argocd/apps/mqtt.yaml @@ -2,7 +2,7 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: - name: mosquitto-ringtail + name: mqtt namespace: argocd spec: project: default diff --git a/argocd/apps/ntfy-ringtail.yaml b/argocd/apps/ntfy.yaml similarity index 94% rename from argocd/apps/ntfy-ringtail.yaml rename to argocd/apps/ntfy.yaml index 65b10f7..13927bc 100644 --- a/argocd/apps/ntfy-ringtail.yaml +++ b/argocd/apps/ntfy.yaml @@ -2,7 +2,7 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: - name: ntfy-ringtail + name: ntfy namespace: argocd spec: project: default -- 2.50.1 (Apple Git-155)