Partie 10: Installation de home-assistant avec ArgoCD
Introduction
Après avoir complété la mise en place du pipeline CI/CD sur mon cluster K3s, il était temps d'installer Home Assistant, la plateforme domotique open-source qui va centraliser tous mes devices connectés. L'objectif était de déployer Home Assistant de manière propre et reproductible via GitOps, tout en permettant l'accès à ma clé Zigbee USB pour la communication avec mes capteurs et actionneurs.
Architecture cible
- Cluster K3s: 5 Raspberry Pi (1x RPi4 8GB master, 2x RPi4 2GB/4GB workers, 2x RPi3 1GB workers)
- ArgoCD: Déploiement GitOps automatique
- Home Assistant: Version 2024.12 en conteneur
- Clé Zigbee: Branchée sur rpi4-worker2 (
/dev/ttyUSB0) - Accès web: HTTPS via nginx-ingress avec Let's Encrypt (
ha.home-fonta.fr) - Stockage: Volume persistant 5 Go avec local-path-provisioner
Contexte et défis
Défi 1: Accès au matériel USB dans Kubernetes
Home Assistant a besoin d'un accès direct à la clé Zigbee USB. Dans Kubernetes, l'accès aux devices USB nécessite:
- Un
hostPathvolume pointant vers/dev/ttyUSB0 - Un conteneur en mode
privileged - Un
nodeSelectorpour forcer le pod sur le nœud avec la clé USB
Défi 2: Reverse proxy et trusted proxies
Home Assistant refuse par défaut les connexions via reverse proxy pour des raisons de sécurité. Il faut configurer explicitement les proxies de confiance.
Défi 3: Stockage persistant lié au nœud
Le storage class local-path crée des volumes liés à un nœud spécifique. Impossible de migrer le pod sans recréer le volume.
Étape 1: Création du Helm Chart
J'ai créé un Helm chart complet pour Home Assistant dans helm-charts/homeassistant/.
Structure du chart
helm-charts/homeassistant/
├── Chart.yaml
├── values.yaml
└── templates/
├── _helpers.tpl
├── configmap.yaml
├── deployment.yaml
├── ingress.yaml
├── pvc.yaml
└── service.yaml
Chart.yaml
apiVersion: v2
name: homeassistant
description: Home Assistant on K3s with Zigbee support
type: application
version: 1.0.0
appVersion: "2024.12"
values.yaml (configuration)
replicaCount: 1
image:
repository: ghcr.io/home-assistant/home-assistant
tag: "2024.12"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 8123
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod-dns"
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
hosts:
- host: ha.home-fonta.fr
paths:
- path: /
pathType: Prefix
tls:
- secretName: ha-home-fonta-tls
hosts:
- ha.home-fonta.fr
persistence:
enabled: true
storageClass: "local-path"
accessMode: ReadWriteOnce
size: 5Gi
# Force deployment on rpi4-worker2 for Zigbee USB access
nodeSelector:
kubernetes.io/hostname: rpi4-worker2
# USB device access
zigbee:
enabled: true
device: /dev/ttyUSB0
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 200m
memory: 512Mi
# Security context for USB access
securityContext:
privileged: true
# Home Assistant specific proxy settings
homeassistant:
trustedProxies:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
Deployment avec accès USB
Le deployment est la partie critique car il doit gérer l'accès USB:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "homeassistant.fullname" . }}
spec:
replicas: 1
strategy:
type: Recreate # Important: pas de rolling update avec USB
template:
spec:
nodeSelector:
kubernetes.io/hostname: rpi4-worker2 # Force sur le bon nœud
containers:
- name: homeassistant
image: ghcr.io/home-assistant/home-assistant:2024.12
securityContext:
privileged: true # Nécessaire pour USB
env:
- name: TZ
value: "Europe/Paris"
volumeMounts:
- name: config
mountPath: /config
- name: ha-config
mountPath: /config/configuration.yaml
subPath: configuration.yaml
- name: usb
mountPath: /dev/ttyUSB0 # Device Zigbee
volumes:
- name: config
persistentVolumeClaim:
claimName: homeassistant
- name: ha-config
configMap:
name: homeassistant-config
- name: usb
hostPath:
path: /dev/ttyUSB0 # Accès direct au device
ConfigMap pour la configuration reverse proxy
Le problème majeur rencontré: Home Assistant refusait les connexions avec "HTTP integration is not set-up for reverse proxies".
Solution: créer un ConfigMap avec configuration.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: homeassistant-config
data:
configuration.yaml: |
# Loads default set of integrations
default_config:
frontend:
themes: !include_dir_merge_named themes
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
# HTTP Configuration for reverse proxy
http:
use_x_forwarded_for: true
trusted_proxies:
- 10.42.0.0/16 # Pod network
- 10.43.0.0/16 # Service network
Étape 2: Application ArgoCD
Création de l'application ArgoCD pour le déploiement GitOps:
# argocd-apps/applications/homeassistant.yaml
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: homeassistant
namespace: argocd
spec:
project: default
source:
repoURL: git@github.com:Nikob2o/ansible-k3s.git
targetRevision: HEAD
path: helm-charts/homeassistant
helm:
valueFiles:
- values.yaml
destination:
server: https://kubernetes.default.svc
namespace: homeassistant
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Étape 3: Déploiement
Commit et push
git add helm-charts/homeassistant/ argocd-apps/applications/homeassistant.yaml
git commit -m "Ajout Home Assistant avec la clé Zigbee"
git push
Vérification du déploiement
# Vérifier l'application ArgoCD
kubectl get applications -n argocd
# Vérifier le pod
kubectl get pods -n homeassistant -o wide
NAME READY STATUS RESTARTS AGE NODE
homeassistant-59db64d779-bcdqt 1/1 Running 0 5m rpi4-worker2
# Vérifier l'accès USB
kubectl exec -n homeassistant homeassistant-59db64d779-bcdqt -- ls -l /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 0 Jan 4 19:58 /dev/ttyUSB0
Problèmes rencontrés et solutions
Problème 1: Manque d'espace disque sur rpi4-master
Symptôme: Pods évictés avec The node was low on resource: ephemeral-storage
Diagnostic:
ansible rpi4-master -i inventory/hosts.ini -m shell -a "df -h /" --become
# Résultat: 11G utilisés sur 14G (77%)
Cause: Fichier swap de 2.1 Go non désactivé + journaux
Solution:
# Désactiver et supprimer le swap
sudo swapoff -a
sudo rm -f /var/swap
# Nettoyer les journaux
sudo journalctl --vacuum-time=7d
# Résultat: passage de 77% à 69% d'utilisation
Changemant de plan, on va mettre home-assistant sur la rpi4-worker2
Problème 2: PVC lié au mauvais nœud
Symptôme: Pod en Pending avec "didn't match Pod's node affinity"
Cause: Le PVC créé sur rpi4-master ne peut pas être monté sur rpi4-worker2 (storage class local-path)
Solution: Supprimer et recréer le PVC
kubectl delete pvc homeassistant -n homeassistant
# ArgoCD recrée automatiquement sur le bon nœud
Problème 3: 400 Bad Request du reverse proxy
Symptôme:
ERROR (MainThread) [homeassistant.components.http.forwarded]
A request from a reverse proxy was received from 10.42.0.63,
but your HTTP integration is not set-up for reverse proxies
Solution: Ajout du ConfigMap avec la configuration HTTP (voir ci-dessus)
Problème 4: rpi4-worker2 ne rejoignait pas le cluster
Symptôme: "Node password rejected, duplicate hostname"
Cause: Secret et fichier /etc/rancher/node/password en conflit
Solution:
# Sur le master
kubectl delete secret rpi4-worker2.node-password.k3s -n kube-system
# Sur le worker
sudo systemctl stop k3s-agent
sudo rm -rf /etc/rancher/node
sudo systemctl start k3s-agent
Résultat final
✅ Home Assistant accessible: https://ha.home-fonta.fr
✅ Clé Zigbee détectée: /dev/ttyUSB0 accessible dans le conteneur
✅ Certificat SSL: Let's Encrypt automatique via cert-manager
✅ GitOps: Tout commit sur le repo déclenche un déploiement automatique
✅ Haute disponibilité: Redémarrage automatique en cas de crash
Configuration post-installation
1. Premier démarrage
Lors du premier accès à https://ha.home-fonta.fr, Home Assistant demande:
- Création du compte administrateur
- Nom de la maison
- Localisation (pour les automations basées sur le lever/coucher du soleil)
- Partage des analytics (optionnel)
2. Configuration Zigbee (ZHA)
Pour connecter la clé Zigbee:
- Paramètres → Appareils et services → Ajouter une intégration
- Chercher ZHA (Zigbee Home Automation)
- Sélectionner le port série:
/dev/ttyUSB0 - Choisir le type de dongle
- Laisser créer le réseau Zigbee
Une fois configuré, on peut ajouter les devices Zigbee en mode appairage.
3. Sécurité recommandée
- Activer l'IP Banning dans Paramètres → Système → Réseau (Pas trouvé avec ma version)
- Configurer les Trusted Networks pour les réseaux locaux
- Utiliser un mot de passe fort
- Activer l'authentification à deux facteurs (MFA)
Commandes utiles
# Logs du pod
kubectl logs -n homeassistant -l app.kubernetes.io/name=homeassistant -f
# Redémarrer Home Assistant
kubectl rollout restart deployment homeassistant -n homeassistant
# Accéder au shell du conteneur
kubectl exec -it -n homeassistant deployment/homeassistant -- /bin/bash
# Synchroniser manuellement ArgoCD
argocd app sync homeassistant
# Copier une sauvegarde vers le pod
kubectl cp backup.tar homeassistant/homeassistant-xxx:/config/backups/
Ajout du support Bluetooth
Après le déploiement initial, j'ai constaté que l'intégration Bluetooth n'était pas disponible dans Home Assistant. Voici les étapes pour activer le Bluetooth.
Vérification de l'adaptateur Bluetooth
Sur rpi4-worker2, vérification de la présence de l'adaptateur:
hciconfig
# hci0: Type: Primary Bus: UART
# BD Address: 88:A2:9E:5F:F3:36 ACL MTU: 1021:8 SCO MTU: 64:1
# DOWN
L'adaptateur hci0 est bien présent mais non accessible dans le pod.
Modification du Helm Chart pour Bluetooth
Ajout dans values.yaml:
bluetooth:
enabled: true
securityContext:
privileged: true
capabilities:
add:
- NET_ADMIN
- NET_RAW
- SYS_ADMIN
Les capabilities NET_ADMIN, NET_RAW et SYS_ADMIN sont nécessaires pour que Home Assistant puisse interagir avec l'adaptateur Bluetooth via D-Bus.
Modification du Deployment
Dans templates/deployment.yaml, ajout de hostNetwork et du montage D-Bus:
spec:
template:
spec:
hostNetwork: true # Nécessaire pour Bluetooth
containers:
- name: homeassistant
volumeMounts:
- name: config
mountPath: /config
- name: usb
mountPath: /dev/ttyUSB0
- name: dbus
mountPath: /var/run/dbus
readOnly: true
volumes:
- name: dbus
hostPath:
path: /var/run/dbus
Problème: Erreur 400 avec hostNetwork
L'activation de hostNetwork: true a provoqué une nouvelle erreur 400:
ERROR [homeassistant.components.http.forwarded]
A request from a reverse proxy was received from 192.168.1.51,
but your HTTP integration is not set-up for reverse proxies
Cause: Avec hostNetwork: true, Home Assistant voit mon IP locale (192.168.1.51) au lieu de l'IP du pod nginx-ingress (10.42.x.x).
Solution: Suppression du ConfigMap initial et ajout de la configuration directement dans le PVC:
kubectl exec -n homeassistant $(kubectl get pod -n homeassistant \
-l app.kubernetes.io/name=homeassistant -o name) -- \
/bin/bash -c "cat > /config/configuration.yaml << 'EOF'
default_config:
http:
use_x_forwarded_for: true
trusted_proxies:
- 192.168.1.0/24 # Réseau local
- 10.42.0.0/16 # Réseau pods K3s
- 10.43.0.0/16 # Réseau services K3s
- 127.0.0.1
- ::1
EOF
"
Activation de BlueZ experimental
Lors de la première activation du Bluetooth dans Home Assistant:
Failed to start Bluetooth: passive scanning on Linux requires
BlueZ >= 5.56 with --experimental enabled and Linux kernel >= 5.10
Solution: Activer le mode experimental sur BlueZ directement sur rpi4-worker2:
# Sur rpi4-worker2 en SSH
sudo systemctl edit bluetooth.service --full
# Modifier la ligne ExecStart:
# Avant: ExecStart=/usr/lib/bluetooth/bluetoothd
# Après: ExecStart=/usr/lib/bluetooth/bluetoothd --experimental
# Redémarrer le service
sudo systemctl daemon-reload
sudo systemctl restart bluetooth
# Vérification
sudo systemctl status bluetooth | grep experimental
Résultat Bluetooth
✅ Adaptateur Bluetooth détecté: hci0 accessible dans Home Assistant
✅ Intégration Bluetooth disponible: Dans Paramètres → Appareils et services
✅ Détection d'appareils: Scan Bluetooth fonctionnel
Point d'attention: Configuration non GitOps
⚠️ La configuration http.trusted_proxies est stockée dans le PVC, pas dans le code GitOps. En cas de suppression du PVC, il faudra reconfigurer cette section manuellement.
⚠️ L'activation de BlueZ experimental sur rpi4-worker2 n'est pas gérée par Ansible et devra être refaite manuellement sur de nouveaux nœuds.
Améliorations futures possibles
- Zigbee2MQTT: Alternative à ZHA avec plus de flexibilité
- Node-RED: Pour des automations avancées
- Grafana + InfluxDB: Historisation et graphiques des métriques
- ESPHome: Intégration de devices ESP32/ESP8266 custom
- Frigate: Détection d'objets sur caméras avec IA
- Automatisation BlueZ: Ajouter la configuration
--experimentaldans les playbooks Ansible
Conclusion
L'installation de Home Assistant sur Kubernetes n'est pas triviale, surtout avec l'accès USB pour Zigbee. Les principaux challenges étaient:
- La gestion du device USB dans Kubernetes (hostPath + privileged)
- Le storage persistant lié au nœud
- La configuration du reverse proxy
Mais le résultat final est robuste et suit les bonnes pratiques GitOps. Tout changement dans le Git se déploie automatiquement, et le système se remet automatiquement de pannes.
Prochaine étape: migration de Passbolt depuis le NAS vers K3s!
Ressources: