Port Mosquitto and ntfy to ringtail k3s, retire Apple Silicon Detector (#216)

## Summary
- Delete `ansible/roles/frigate_detector/` and remove from indri playbook — the Apple Silicon Detector is retired
- Move Mosquitto (MQTT) ArgoCD app from indri minikube to ringtail k3s
- Move ntfy ArgoCD app from indri minikube to ringtail k3s
- Update Frigate docs to reflect detector removal and planned RTX 4080 migration
- Manifests are reused as-is (same `argocd/manifests/mosquitto/` and `argocd/manifests/ntfy/`), just pointed at ringtail

## Deployment

After merge:
1. Sync indri ArgoCD `apps` app with prune to remove old mosquitto/ntfy apps:
   ```
   argocd app sync apps --prune
   ```
2. Sync new ringtail apps:
   ```
   argocd app sync mosquitto-ringtail
   argocd app sync ntfy-ringtail
   ```
3. Manually clean up the detector LaunchAgent on indri:
   ```
   ssh indri 'launchctl unload ~/Library/LaunchAgents/mcquack.eblume.frigate-detector.plist'
   ssh indri 'rm ~/Library/LaunchAgents/mcquack.eblume.frigate-detector.plist'
   ```

## Notes
- Frigate on indri will lose MQTT/ntfy connectivity — this is expected (user confirmed no downtime concerns)
- ntfy Tailscale Ingress hostname `ntfy` will transfer from indri ProxyGroup to ringtail ProxyGroup
- Caddy on indri proxies `ntfy.ops.eblu.me` → `ntfy.tail8d86e.ts.net`, so no Caddy changes needed
- Frigate + frigate-notify will be ported to ringtail in a follow-up PR

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/216
This commit is contained in:
Erich Blume 2026-02-19 11:22:44 -08:00
commit 16a4a9a616
11 changed files with 35 additions and 123 deletions

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- {{ ansible_managed }} -->
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>mcquack.eblume.frigate-detector</string>
<key>ProgramArguments</key>
<array>
<string>{{ frigate_detector_uv_binary }}</string>
<string>run</string>
<string>--python</string>
<string>{{ frigate_detector_python }}</string>
<string>--with</string>
<string>numpy==1.26.*</string>
<string>--with</string>
<string>opencv-python-headless==4.11.0.*</string>
<string>--with</string>
<string>opencv-contrib-python==4.11.0.*</string>
<string>--with</string>
<string>onnxruntime==1.22.*</string>
<string>--with</string>
<string>pyzmq==26.2.*</string>
<string>--with</string>
<string>pydantic==2.10.*</string>
<string>detector/zmq_onnx_client.py</string>
<string>--model</string>
<string>{{ frigate_detector_model }}</string>
<string>--endpoint</string>
<string>{{ frigate_detector_endpoint }}</string>
</array>
<key>WorkingDirectory</key>
<string>{{ frigate_detector_dir }}</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>{{ frigate_detector_log_dir }}/mcquack.frigate-detector.out.log</string>
<key>StandardErrorPath</key>
<string>{{ frigate_detector_log_dir }}/mcquack.frigate-detector.err.log</string>
</dict>
</plist>