apiVersion: v1 kind: PersistentVolumeClaim metadata: name: zigbee2mqtt-pvc namespace: monitoring spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi --- apiVersion: v1 kind: ConfigMap metadata: name: zigbee2mqtt-config-template namespace: monitoring data: configuration.yaml: | homeassistant: true availability: active: timeout: 10 permit_join: false mqtt: base_topic: zigbee2mqtt server: mqtt://mosquitto.datalab.svc.cluster.local:1883 user: sender serial: port: tcp://192.168.10.10:7638 frontend: port: 8080 host: 0.0.0.0 advanced: network_key: GENERATE --- apiVersion: apps/v1 kind: Deployment metadata: name: zigbee2mqtt namespace: monitoring labels: app: zigbee2mqtt spec: replicas: 1 selector: matchLabels: app: zigbee2mqtt template: metadata: labels: app: zigbee2mqtt spec: securityContext: fsGroup: 1000 runAsUser: 1000 initContainers: - name: init-config image: busybox:latest command: - sh - -c - | if [ ! -f /app/data/configuration.yaml ]; then echo "Initializing configuration.yaml..." cp /tmp/config/configuration.yaml /app/data/configuration.yaml chmod 600 /app/data/configuration.yaml else echo "configuration.yaml already exists. Skipping initialization." fi securityContext: runAsUser: 1000 volumeMounts: - name: data mountPath: /app/data - name: config-template mountPath: /tmp/config containers: - name: zigbee2mqtt image: koenkk/zigbee2mqtt:latest env: # Override MQTT credentials/settings using environment variables - name: ZIGBEE2MQTT_CONFIG_MQTT_SERVER value: "mqtt://mosquitto.datalab.svc.cluster.local:1883" - name: ZIGBEE2MQTT_CONFIG_MQTT_USER value: "sender" - name: ZIGBEE2MQTT_CONFIG_MQTT_PASSWORD valueFrom: secretKeyRef: name: zigbee2mqtt-secret key: mqtt-password # Override Zigbee Coordinator settings using environment variables - name: ZIGBEE2MQTT_CONFIG_SERIAL_PORT value: "tcp://192.168.10.10:7638" - name: ZIGBEE2MQTT_CONFIG_SERIAL_ADAPTER value: "zstack" ports: - name: http-frontend containerPort: 8080 resources: requests: cpu: 10m memory: 64Mi limits: cpu: 200m memory: 256Mi volumeMounts: - name: data mountPath: /app/data volumes: - name: data persistentVolumeClaim: claimName: zigbee2mqtt-pvc - name: config-template configMap: name: zigbee2mqtt-config-template --- apiVersion: v1 kind: Service metadata: name: zigbee2mqtt namespace: monitoring labels: app: zigbee2mqtt spec: ports: - name: http-frontend port: 8080 targetPort: 8080 protocol: TCP selector: app: zigbee2mqtt --- apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: name: zigbee2mqtt-auth namespace: monitoring spec: basicAuth: secret: zigbee2mqtt-auth-secret removeHeader: true --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: zigbee2mqtt namespace: monitoring annotations: cert-manager.io/cluster-issuer: "letsencrypt-prod" traefik.ingress.kubernetes.io/router.middlewares: monitoring-zigbee2mqtt-auth@kubernetescrd spec: ingressClassName: traefik rules: - host: zigbee2mqtt.moritzgraf.de http: paths: - path: / pathType: ImplementationSpecific backend: service: name: zigbee2mqtt port: number: 8080 tls: - hosts: - "zigbee2mqtt.moritzgraf.de" secretName: zigbee2mqtt-tls --- apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: zigbee2mqtt-alerts namespace: monitoring labels: release: prometheus-operator spec: groups: - name: zigbee2mqtt.rules rules: - alert: Zigbee2MQTTDown expr: kube_pod_container_status_ready{container="zigbee2mqtt", namespace="monitoring"} == 0 for: 1h labels: severity: critical annotations: summary: "Zigbee2MQTT is down" description: "The Zigbee2MQTT pod is not ready. This typically indicates a connection failure to the SLZB-MR1U coordinator host at 192.168.10.10:7638, or a crash within the Z2M application." - alert: Zigbee2MQTTBridgeOffline expr: homeassistant_binary_sensor_state{entity="binary_sensor.zigbee2mqtt_bridge_connection_state"} == 0 for: 1h labels: severity: critical annotations: summary: "Zigbee2MQTT Bridge Connection Offline" description: "The Zigbee2MQTT bridge connection is reported as offline. The bridge has lost communication with the MQTT broker or the Zigbee coordinator." - alert: ShellyWS90MetricsStale expr: absent(homeassistant_sensor_temperature_celsius{entity="sensor.shelly_ws90_temperatur"}) or (time() - homeassistant_last_updated_time_seconds{entity="sensor.shelly_ws90_temperatur"} > 0) for: 1h labels: severity: warning annotations: summary: "Shelly WS90 Weather Station metrics are stale" description: "No new metrics have been received from the Shelly WS90 weather station (sensor.shelly_ws90_temperatur) for over 1 hour. The device may be offline, out of range, or batteries might be depleted."