blumeops/argocd/manifests/argocd
Erich Blume 04c7f3c45a Deploy Frigate NVR stack with Mosquitto, Ntfy, and frigate-notify (#190)
## Summary

Deploy a cloud-free NVR stack for the GableCam (ReoLink Elite Floodlight at 192.168.1.159):

- **Mosquitto** — shared MQTT broker in `mqtt` namespace (cluster-internal, no auth)
- **Ntfy** — self-hosted push notifications in `ntfy` namespace, exposed at `ntfy.tail8d86e.ts.net` / `ntfy.ops.eblu.me`
- **Frigate** — NVR with GableCam via HTTP-FLV, ONNX CPU detection, NFS recordings on sifaka, exposed at `nvr.tail8d86e.ts.net` / `nvr.ops.eblu.me`
- **frigate-notify** — bridges Frigate detection events (person, car, dog, cat) to Ntfy alerts via MQTT

Also includes:
- Prometheus scrape target for Frigate metrics
- Grafana dashboard for Frigate (status, inference speed, FPS, CPU/memory, storage)
- Caddy reverse proxy entries for `nvr.ops.eblu.me` and `ntfy.ops.eblu.me`

## Prerequisites

- [ ] Create NFS share `frigate` on sifaka (`/volume1/frigate`, RW for indri)
- [ ] Create 1Password item "Reolink Floodlight Camera" in `blumeops` vault with `username` and `password` fields

## Deployment (after merge)

```bash
argocd app sync apps
argocd app sync mosquitto
argocd app sync ntfy
argocd app sync frigate
argocd app sync grafana-config
argocd app sync prometheus
mise run provision-indri -- --tags caddy
mise run services-check
```

## Verification

- [ ] Mosquitto pod running, accepting connections on 1883
- [ ] Ntfy web UI accessible at `ntfy.ops.eblu.me`
- [ ] Frigate web UI at `nvr.ops.eblu.me` showing GableCam live feed
- [ ] Object detection working (ONNX, person/car/dog/cat)
- [ ] Recordings appearing in NFS share on sifaka
- [ ] frigate-notify sending detection alerts to Ntfy
- [ ] Prometheus scraping Frigate metrics
- [ ] Grafana dashboard showing Frigate data

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/190
2026-02-14 21:27:44 -08:00
..
argocd-cm-patch.yaml Auto-deploy docs from build workflow (#93) 2026-02-03 16:58:03 -08:00
argocd-cmd-params-cm.yaml K8s Migration Phase 1: Infrastructure Setup (#29) 2026-01-19 09:49:52 -08:00
argocd-rbac-cm-patch.yaml Auto-deploy docs from build workflow (#93) 2026-02-03 16:58:03 -08:00
argocd-ssh-known-hosts-cm.yaml Add Immich photo management + migrate forge URLs (#62) 2026-01-26 11:20:11 -08:00
external-secret-repo-forge.yaml Fix argocd SSH key format for 1Password Connect 2026-01-28 20:31:16 -08:00
ingress-tailscale.yaml Deploy Frigate NVR stack with Mosquitto, Ntfy, and frigate-notify (#190) 2026-02-14 21:27:44 -08:00
kustomization.yaml Move ArgoCD to Misc homepage group and rename ingress file 2026-02-13 09:13:32 -08:00
README.md Add Immich photo management + migrate forge URLs (#62) 2026-01-26 11:20:11 -08:00

ArgoCD

GitOps continuous delivery for Kubernetes, with self-management via ArgoCD.

Prerequisites

  • Tailscale operator deployed (see argocd/manifests/tailscale-operator/README.md)
  • SSH key added to Forgejo user for access to all forge repos (not a deploy key)

Manual Bootstrap

Bootstrap is required when setting up a new cluster. After bootstrap, ArgoCD manages itself.

# 1. Create namespace
kubectl create namespace argocd

# 2. Apply ArgoCD manifests via kustomize
kubectl apply -k argocd/manifests/argocd/

# 3. Wait for ArgoCD to be ready
kubectl wait --for=condition=available deployment/argocd-server -n argocd --timeout=300s

# 4. Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo

# 5. Login and change password
argocd login argocd.tail8d86e.ts.net --username admin --grpc-web
argocd account update-password

# 6. Apply repo-creds-forge credential template for SSH access to all forge repos
PRIV_KEY=$(op read "op://vg6xf6vvfmoh5hqjjhlhbeoaie/csjncynh6htjvnh2l2da65y32q/private key?ssh-format=openssh")$'\n' && \
kubectl create secret generic repo-creds-forge -n argocd \
  --from-literal=type=git \
  --from-literal=url='ssh://forgejo@forge.ops.eblu.me:2222/eblume/' \
  --from-literal=insecure=true \
  --from-literal=sshPrivateKey="$PRIV_KEY" && \
kubectl label secret repo-creds-forge -n argocd argocd.argoproj.io/secret-type=repo-creds

# 7. Apply ArgoCD Applications (self-management + app-of-apps)
kubectl apply -f argocd/apps/argocd.yaml
kubectl apply -f argocd/apps/apps.yaml

After step 7, ArgoCD manages itself and all applications defined in argocd/apps/.

Access

ArgoCD CLI Commands

# Check all applications
argocd app list

# Sync a specific application
argocd app sync <app-name>

# Check application status
argocd app get <app-name>

# Hard refresh (clear git cache)
argocd app get <app-name> --hard-refresh

Adding New Applications

  1. Create an Application manifest in argocd/apps/<app-name>.yaml
  2. Commit and push to forge
  3. ArgoCD (via app-of-apps) automatically picks it up

Example Application:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git
    targetRevision: main
    path: argocd/manifests/my-app
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

Files

File Description
kustomization.yaml References upstream install.yaml + local customizations
service-tailscale.yaml Tailscale Ingress for external access with Let's Encrypt TLS
argocd-cmd-params-cm.yaml Patch to disable HTTPS redirect (TLS terminates at Ingress)
repo-forge-secret.yaml.tpl Template for forge SSH credential template (manual)
README.md This file

Notes

  • TODO: Secrets (repo-creds-forge) are not managed by ArgoCD and must be applied manually. Future improvement: integrate with a secrets operator (e.g., External Secrets).
  • The credential template (repo-creds) uses a URL prefix to match all repos under eblume/.
  • ArgoCD uses Tailscale Ingress with Let's Encrypt for TLS termination.
  • The --grpc-web flag is required for CLI access through the Tailscale ingress.