diff --git a/README.md b/README.md index a3a22ac..71c92a0 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ cd helm-charts | [Jellyfin](docs/jellyfin.md) | Media server with PostgreSQL support | Ready | | [Home Assistant](docs/home-assistant.md) | Home automation with PostgreSQL recorder and managed secrets | Ready | | [ESPHome](docs/esphome.md) | ESPHome dashboard with host network for device discovery | Ready | +| Frigate | NVR with Rockchip RK3588 hardware acceleration (rkmpp + rknn) | Ready | ### 3. Usage with FluxCD diff --git a/frigate/Chart.yaml b/frigate/Chart.yaml new file mode 100644 index 0000000..ec6a5bd --- /dev/null +++ b/frigate/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: frigate +description: Frigate NVR Helm chart with Rockchip RK3588 hardware acceleration (CPU/GPU/NPU) +type: application +version: 0.1.0 +appVersion: "0.15.0" +annotations: + version-source: github-release:blakeblackshear/frigate + version-pattern: "s|^v||" diff --git a/frigate/templates/_helpers.tpl b/frigate/templates/_helpers.tpl new file mode 100644 index 0000000..d7ed461 --- /dev/null +++ b/frigate/templates/_helpers.tpl @@ -0,0 +1,18 @@ +{{/* +Common labels +*/}} +{{- define "frigate.labels" -}} +app.kubernetes.io/name: {{ .Chart.Name }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +app.kubernetes.io/component: nvr +app.kubernetes.io/part-of: home-automation +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "frigate.selectorLabels" -}} +app: {{ .Release.Name }} +{{- end -}} diff --git a/frigate/templates/configmap.yaml b/frigate/templates/configmap.yaml new file mode 100644 index 0000000..6485beb --- /dev/null +++ b/frigate/templates/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-config + labels: + {{- include "frigate.labels" . | nindent 4 }} +data: + config.yaml: | +{{ toYaml .Values.frigateConfig | indent 4 }} diff --git a/frigate/templates/deployment.yaml b/frigate/templates/deployment.yaml new file mode 100644 index 0000000..471bc2a --- /dev/null +++ b/frigate/templates/deployment.yaml @@ -0,0 +1,135 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }} + labels: + {{- include "frigate.labels" . | nindent 4 }} + annotations: + version-source: {{ index .Chart.Annotations "version-source" }} +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + {{- include "frigate.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "frigate.selectorLabels" . | nindent 8 }} + annotations: + # Roll the pod when the config ConfigMap changes + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + spec: + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default (printf "%s-rk" (.Chart.AppVersion | toString)) }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.httpPort }} + protocol: TCP + - name: rtsp + containerPort: {{ .Values.rtspPort }} + protocol: TCP + - name: webrtc + containerPort: {{ .Values.webrtcPort }} + protocol: TCP + - name: webrtc-udp + containerPort: {{ .Values.webrtcPort }} + protocol: UDP + env: + - name: TZ + value: {{ .Values.timezone | quote }} + - name: LIBVA_DRIVER_NAME + value: rkmpp + {{- if .Values.existingSecret }} + envFrom: + - secretRef: + name: {{ .Values.existingSecret }} + {{- end }} + securityContext: + # RK3588 device nodes (/dev/dri, /dev/rga, /dev/mpp_service) are + # accessible only to root + video/render groups. Privileged is the + # simplest reliable path on k3s; tighten later with explicit + # supplementalGroups if you want. + privileged: {{ .Values.rockchip.enabled }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + readinessProbe: + httpGet: + path: /api/version + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /api/version + port: http + initialDelaySeconds: 120 + periodSeconds: 30 + timeoutSeconds: 10 + failureThreshold: 3 + volumeMounts: + - name: config-file + mountPath: /config/config.yaml + subPath: config.yaml + - name: config + mountPath: /config + - name: media + mountPath: /media/frigate + - name: dshm + mountPath: /dev/shm + - name: localtime + mountPath: /etc/localtime + readOnly: true + {{- if .Values.rockchip.enabled }} + {{- range .Values.rockchip.devices }} + - name: {{ . | base | replace "_" "-" }} + mountPath: {{ . }} + {{- end }} + {{- end }} + volumes: + - name: config-file + configMap: + name: {{ .Release.Name }}-config + items: + - key: config.yaml + path: config.yaml + - name: config + hostPath: + path: {{ required "config.hostPath is required" .Values.config.hostPath }} + type: DirectoryOrCreate + - name: media + hostPath: + path: {{ required "media.hostPath is required" .Values.media.hostPath }} + type: DirectoryOrCreate + - name: dshm + emptyDir: + medium: Memory + sizeLimit: {{ .Values.shmSizeMi }}Mi + - name: localtime + hostPath: + path: /etc/localtime + type: File + {{- if .Values.rockchip.enabled }} + {{- range .Values.rockchip.devices }} + - name: {{ . | base | replace "_" "-" }} + hostPath: + path: {{ . }} + {{- end }} + {{- end }} diff --git a/frigate/templates/ingress.yaml b/frigate/templates/ingress.yaml new file mode 100644 index 0000000..742d7e5 --- /dev/null +++ b/frigate/templates/ingress.yaml @@ -0,0 +1,29 @@ +{{- range $name, $config := .Values.ingresses }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $.Release.Name }}-{{ $name }} + labels: + {{- include "frigate.labels" $ | nindent 4 }} + {{- with $config.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + rules: + - host: {{ $config.host }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $.Release.Name }} + port: + number: {{ $.Values.service.httpPort }} + {{- with $config.tls }} + tls: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/frigate/templates/service.yaml b/frigate/templates/service.yaml new file mode 100644 index 0000000..a555748 --- /dev/null +++ b/frigate/templates/service.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }} + labels: + {{- include "frigate.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + selector: + {{- include "frigate.selectorLabels" . | nindent 4 }} + ports: + - name: http + port: {{ .Values.service.httpPort }} + targetPort: http + protocol: TCP + - name: rtsp + port: {{ .Values.service.rtspPort }} + targetPort: rtsp + protocol: TCP + - name: webrtc-tcp + port: {{ .Values.service.webrtcPort }} + targetPort: webrtc + protocol: TCP + - name: webrtc-udp + port: {{ .Values.service.webrtcPort }} + targetPort: webrtc-udp + protocol: UDP diff --git a/frigate/values.yaml b/frigate/values.yaml new file mode 100644 index 0000000..e4bb677 --- /dev/null +++ b/frigate/values.yaml @@ -0,0 +1,146 @@ +# Default values for the Frigate Helm chart +# Tailored for Orange Pi 5 Plus (Rockchip RK3588): CPU + Mali GPU + RKNPU detector + +image: + # Use the -rk variant for Rockchip hardware acceleration + repository: ghcr.io/blakeblackshear/frigate + tag: "" # defaults to "stable-rk" (see deployment.yaml) when empty + pullPolicy: IfNotPresent + +timezone: "Europe/Kyiv" + +# Web UI / RTMP / RTSP ports +httpPort: 5000 +rtspPort: 8554 +webrtcPort: 8555 + +service: + type: ClusterIP + httpPort: 5000 + rtspPort: 8554 + webrtcPort: 8555 + +# Frigate needs a large /dev/shm for clip processing. +# Rough rule of thumb: 40MB per 1080p camera + 10MB overhead. +shmSizeMi: 512 + +resources: + requests: + cpu: "500m" + memory: "1Gi" + limits: + cpu: "4" + memory: "4Gi" + +# /config persistence (Frigate database, model cache, runtime state) +config: + hostPath: "" # e.g. /srv/data/frigate/config + +# /media/frigate persistence (recordings + snapshots) +media: + hostPath: "" # e.g. /srv/data/frigate/media + +# Rockchip device passthrough (RK3588). +# Frigate's rockchip docs require these devices for ffmpeg-rkmpp + RKNPU detector. +rockchip: + enabled: true + devices: + - /dev/dri + - /dev/dma_heap + - /dev/rga + - /dev/mpp_service + +# Existing Kubernetes Secret with Frigate substitution env vars +# (every key in this Secret is exposed in the container as an env var; Frigate +# substitutes ${KEY} tokens in its config from any env var prefixed FRIGATE_). +# The Secret must define at minimum: +# FRIGATE_MQTT_HOST, FRIGATE_MQTT_USER, FRIGATE_MQTT_PASSWORD +# Plus one user/password pair per camera, e.g.: +# FRIGATE_REOLINK_FRONT_USER, FRIGATE_REOLINK_FRONT_PASSWORD +existingSecret: "" + +# Inline frigate config.yaml. Rendered into a ConfigMap and mounted at +# /config/config.yaml. Everything except secrets (rtsp passwords, mqtt creds) +# belongs here; secrets are pulled from `existingSecret` via env substitution. +frigateConfig: + mqtt: + enabled: true + host: "{FRIGATE_MQTT_HOST}" + port: 1883 + user: "{FRIGATE_MQTT_USER}" + password: "{FRIGATE_MQTT_PASSWORD}" + topic_prefix: frigate + client_id: frigate + + # Rockchip NPU detector (RKNPU on RK3588 has 3 cores). + detectors: + rknn: + type: rknn + num_cores: 3 + + # Detection model. Frigate auto-downloads supported RKNN models into + # /config/model_cache/rknn_cache on first start. Override here to use a + # custom .rknn placed on the config volume. + model: + path: /config/model_cache/rknn_cache/yolov9-t-320x320.rknn + model_type: yolo-generic + width: 320 + height: 320 + input_tensor: nhwc + input_pixel_format: rgb + + # Hardware-accelerated video decoding via Rockchip MPP. + ffmpeg: + hwaccel_args: preset-rkmpp + + detect: + enabled: true + width: 1280 + height: 720 + fps: 5 + + snapshots: + enabled: true + bounding_box: true + retain: + default: 7 + + record: + enabled: true + retain: + days: 3 + mode: motion + alerts: + retain: + days: 14 + mode: motion + detections: + retain: + days: 10 + mode: motion + + birdseye: + enabled: true + mode: motion + + go2rtc: + streams: {} + + logger: + default: info + + # Cameras. Override / extend in the cluster HelmRelease. + # Use ${VAR} tokens for any value sourced from `existingSecret`. + cameras: {} + +nodeSelector: {} +tolerations: [] +affinity: {} + +ingresses: {} + # https: + # host: frigate.example.com + # annotations: {} + # tls: + # - hosts: + # - frigate.example.com