Frigate NVR¶
Status: Production
Namespace: frigate
URL: https://frigate.skaggsfamily.us
Deployed: January 2026
Overview¶
Frigate is a network video recorder (NVR) with real-time AI object detection using Google Coral TPU hardware acceleration. The deployment uses NFS storage for recordings and clips, with a file-based configuration approach that allows UI-driven configuration changes (like motion masks) to persist across restarts.
Architecture¶
Core Components¶
| Component | Version | Purpose | Storage Backend |
|---|---|---|---|
| Frigate | 0.15.1 | NVR with AI detection | Hybrid (Ceph + NFS) |
| Coral TPU | PCIe Accelerator | Object detection inference | N/A |
Infrastructure Dependencies¶
- Storage: Hybrid architecture (Ceph for config, NFS for recordings)
- Ingress: Traefik IngressRoute with TLS
- DNS: External-DNS for automatic DNS management
- Certificate: Let's Encrypt TLS certificate via cert-manager
- Hardware: Google Coral TPU (PCIe) on dedicated worker node
Node Scheduling¶
Frigate requires access to the Coral TPU hardware, which is passed through to a specific worker node. The deployment uses a node selector to ensure scheduling on the correct node:
The Coral TPU device (/dev/apex_0) is mounted into the container with privileged security context to allow direct hardware access.
Storage Architecture¶
Design Principle¶
Configuration lives on Ceph for performance and reliability. Recordings live on NFS for capacity.
Volume Layout¶
| Volume | Size | Storage Class | Access Mode | Purpose |
|---|---|---|---|---|
frigate-config |
5Gi | ceph-block |
RWO | Configuration, database, model files |
frigate-media |
500Gi | nfs-storage-network |
RWX | Recordings, clips, snapshots |
Configuration Storage Strategy¶
Frigate's configuration is stored as a writable file (config.yml) in the config PVC rather than a Kubernetes ConfigMap. This allows:
- UI-driven configuration changes (motion masks, zones, detection settings)
- Changes persist across pod restarts
- No GitOps commit required for operational tweaks
Configuration Approach¶
File-Based Configuration¶
The Frigate Helm chart normally creates a ConfigMap from inline values and mounts it at /config/config.yml. This makes the configuration read-only, preventing UI-based changes from persisting.
To enable writable configuration, the deployment uses Flux postRenderers to remove the ConfigMap volume mount after Helm renders the deployment:
# helmrelease.yaml
postRenderers:
- kustomize:
patches:
- target:
kind: Deployment
name: frigate
patch: |-
- op: test
path: /spec/template/spec/volumes/0/name
value: configmap
- op: remove
path: /spec/template/spec/volumes/0
- op: test
path: /spec/template/spec/containers/0/volumeMounts/1/name
value: configmap
- op: remove
path: /spec/template/spec/containers/0/volumeMounts/1
Why JSON Patch Operations?
- The
testoperation ensures the patch targets the correct volume (safety check) - The
removeoperation deletes the ConfigMap volume and volumeMount - This allows the PVC-mounted
/configdirectory to contain the authoritativeconfig.yml
Helm Chart Settings¶
persistence:
config:
enabled: true
existingClaim: frigate-config
# Don't copy ConfigMap to volume on startup
ephemeralWritableConfigYaml: false
The ephemeralWritableConfigYaml: false setting prevents the chart from copying any ConfigMap content to the PVC at startup, ensuring the PVC's config.yml is the single source of truth.
Deployment¶
Source Files¶
Location: apps/_bases/frigate/
Key files:
helmrelease.yaml- Main Frigate deployment with postRenderersingressroute.yaml- Traefik routing for web UIdnsendpoint.yaml- DNS record for frigate.skaggsfamily.uspvc.yaml- Config and media persistent volume claimssealedsecret-camera-credentials.yaml- Camera RTSP credentialssealedsecret-frigate-env.yaml- Environment variablesbackup/- VolSync backup configuration
Helm Chart¶
- Repository: https://blakeblackshear.github.io/blakeshome-charts
- Chart:
frigate - Version: 7.5.1
- Application Version: 0.15.1
Dependencies¶
infra-sources-helm- Helm repositoryinfra-namespaces- frigate namespaceinfra-sealed-secrets- Secret decryptioninfra-traefik- Ingress controllerinfra-cert-manager- TLS certificates
Resource Allocation¶
Rationale:
- Object detection is CPU-intensive for decoding video streams
- Memory needed for detection model and frame buffers
- Coral TPU offloads inference, reducing CPU load significantly
Operations¶
Accessing the Service¶
# Open web UI
open https://frigate.skaggsfamily.us
# Direct pod access (debugging)
kubectl port-forward -n frigate svc/frigate 5000:5000
Monitoring¶
# Check pod status
kubectl get pods -n frigate
# View logs
kubectl logs -n frigate -l app.kubernetes.io/name=frigate --tail=100
# Check HelmRelease status
kubectl get helmrelease -n frigate
# Verify Coral TPU is detected
kubectl logs -n frigate -l app.kubernetes.io/name=frigate | grep -i coral
Editing Configuration¶
Configuration changes can be made through:
- Frigate Web UI (recommended for operational changes)
- Navigate to Settings in the web UI
- Make changes (motion masks, zones, detection settings)
- Click "Restart Frigate" when prompted
-
Changes persist in the config PVC
-
Direct File Edit (for major changes)
Setting Up Motion Masks¶
Motion masks prevent false detections in areas with constant motion (trees, reflections, etc.):
- Open Frigate web UI
- Navigate to the camera you want to configure
- Click "Debug" → "Motion Mask"
- Draw mask zones on the video feed
- Click "Save"
- Click "Restart Frigate" when prompted
The mask configuration is stored in /config/config.yml and persists across restarts.
Backup and Recovery¶
Backup Configuration¶
Config Volume (VolSync):
- Method: Restic to MinIO S3
- Schedule: Daily at 3:00 AM
- Retention: 7 daily, 4 weekly, 6 monthly
- Destination:
s3://volsync-backups/frigate-config
apiVersion: volsync.backube/v1alpha1
kind: ReplicationSource
metadata:
name: frigate-config-backup
namespace: frigate
spec:
sourcePVC: frigate-config
trigger:
schedule: "0 3 * * *"
restic:
repository: frigate-restic-secret
copyMethod: Direct
retain:
daily: 7
weekly: 4
monthly: 6
pruneIntervalDays: 7
Backup Verification¶
# Check VolSync backup status
kubectl get replicationsource -n frigate
# View last backup details
kubectl describe replicationsource frigate-config-backup -n frigate
# Check backup job logs
kubectl logs -n frigate -l volsync.backube/replicationSource=frigate-config-backup
Recovery Procedures¶
Config Volume Recovery:
- Create a ReplicationDestination to restore from backup
- Point the PVC at the restored data
- See VolSync documentation for detailed restore procedures
Recordings Recovery:
- Media volume is not backed up (high volume, low value)
- Recordings can be regenerated from camera feeds
- Consider S3 lifecycle policies for long-term clip retention
Troubleshooting¶
Config Not Persisting¶
Symptom: Motion masks or other UI changes disappear after restart
Diagnosis:
# Check if config is read-only
kubectl logs -n frigate -l app.kubernetes.io/name=frigate | grep -i "read-only"
# Verify postRenderers removed ConfigMap mount
kubectl get deploy frigate -n frigate -o yaml | grep -A5 "volumeMounts"
Resolution: Ensure the HelmRelease has the correct postRenderers to remove the ConfigMap volume mount. The config PVC must be the only source for /config/config.yml.
Coral TPU Not Detected¶
Symptom: Detection running on CPU, high CPU usage
Diagnosis:
# Check device is mounted
kubectl exec -n frigate deploy/frigate -- ls -la /dev/apex_0
# Check Frigate logs for Coral
kubectl logs -n frigate -l app.kubernetes.io/name=frigate | grep -i "edge tpu"
Resolution:
- Verify node has
feature.node.kubernetes.io/coral-tpu: "true"label - Check pod is scheduled on correct node
- Verify privileged security context is enabled
Camera Connection Issues¶
Symptom: Camera feed not loading, "No frames received"
Diagnosis:
# Check camera connectivity from pod
kubectl exec -n frigate deploy/frigate -- \
ffprobe -v quiet -print_format json -show_streams rtsp://user:pass@camera-ip/stream
# Check Frigate logs for camera errors
kubectl logs -n frigate -l app.kubernetes.io/name=frigate | grep -i camera-name
Resolution:
- Verify camera RTSP URL is correct
- Check network connectivity from cluster to camera VLAN
- Verify credentials in sealed secret
High Memory Usage¶
Symptom: Pod OOMKilled or memory pressure
Diagnosis:
# Check current memory usage
kubectl top pod -n frigate
# Check for memory-related events
kubectl describe pod -n frigate -l app.kubernetes.io/name=frigate | grep -A5 "Events"
Resolution:
- Reduce number of cameras or detection resolution
- Adjust
detectsettings in config (fps, resolution) - Increase memory limits if resources available
Hardware Configuration¶
Coral TPU Passthrough¶
The Coral TPU PCIe card is passed through from the Proxmox host to the Kubernetes worker node:
- Proxmox Host: Coral PCIe device added to VM
- Talos Node: Device appears as
/dev/apex_0 - Frigate Pod: Device mounted with privileged access
Helm Values:
Camera Requirements¶
- RTSP stream support (H.264 recommended)
- Dedicated substream for detection (lower resolution, 5-10 fps)
- Main stream for recording (full resolution)
References¶
- GitOps Repository: flux-repo/apps/_bases/frigate
- Helm Chart: blakeblackshear/blakeshome-charts
- Official Docs: Frigate Documentation
- Coral TPU Docs: Google Coral Documentation
Last Updated: January 6, 2026