Aller au contenu
  1. Docs/
  2. Domotique/

Déploiement Home Assistant (GitOps)

·Temps de lecture : 7 minutes· loading · loading · ·
ksh2177
GitOps Argo CD Kubernetes App-of-Apps DevOps Homelab K3s Helm Sealed Domotique
ksh2177
Auteur
ksh2177
Ingénieur DevOps passionné par l’automatisation, la fiabilité et le design système.
Auteur
ksh2177
Ingénieur DevOps passionné par l’automatisation, la fiabilité et le design système. J’apporte des solutions robustes et bien pensées.
Table des matières

🏠 Objectif
#

Déployer Home Assistant dans votre cluster K3s 100 % GitOps :

  • chart Helm local ultra‑léger (4 ressources)
  • arborescence helm/ + overlays/prod/
  • secrets chiffrés avec Bitnami Sealed Secrets
  • synchro continue via Argo CD App‑of‑Apps

📂 1. Arborescence GitOps spécifique
#

Arborescence Gitops - HA


📝 2. Chart Helm minimal (helm/home-assistant/charts.yaml)
#

apiVersion: v2
name: home-assistant                     # Réutilisé par helpers.tpl
description: Minimal chart for Home Assistant (GitOps)
type: application
version: 0.1.0                           # Version du *chart* (pas de l'App)
appVersion: "2025.7.2"                     # Version HA par défaut

values.yaml
#

# ---------------------------------------------------------------------------
# Valeurs partagées par tous les environnements. Les surcharges se font
# dans overlays/prod/values-prod.yaml
# ---------------------------------------------------------------------------
image:
  repository: ghcr.io/home-assistant/home-assistant
  tag: "2025.7.2"            # 🔄  bump ici pour upgrade HA

replicaCount: 1            # HA n’est pas (encore) stateless → 1 seul pod

service:
  type: ClusterIP
  port: 8123

ingress:
  enabled: true
  className: nginx
  host: votre-domaine.com
  tlsSecret: homeassistant-tls          # géré par cert‑manager

nodeSelector: {}                        # overridé en prod
resources: {}                           # overridé en prod

storage:                                # PVC Longhorn
  size: 10Gi
  storageClass: longhorn
  accessMode: ReadWriteOnce

# ---------------------------------------------------------------------------
# Fichier configuration.yaml versionné → monté en lecture seule
# ---------------------------------------------------------------------------
configuration: |-
  homeassistant:
    external_url: "https://votre-domaine.com"
    internal_url: "http://home-assistant.home-assistant.svc.cluster.local:8123"

  http:
    use_x_forwarded_for: true
    trusted_proxies:
      - 10.42.0.0/16        # CIDR pods/ingress
      - 192.168.1.211       # IP MetalLB
      - 192.168.1.0/24      # LAN

  # Ajoute ici l’intégration de base souhaitée
  default_config:

Vous pouvez ajouter vos intégrations YAML directement dans ce bloc, l’image étant read‑only.


📑 3 Templates
#

_helper.tpl (utile pour ne pas répété les infos)
#

{{- /* 📌 Fonctions utilitaires pour ne pas dupliquer les noms, labels, etc. */ -}}

{{- define "ha.name" -}} home-assistant {{- end }}
{{- define "ha.fullname" -}} {{ include "ha.name" . }} {{- end }}

{{- define "ha.labels" -}}
app.kubernetes.io/name: {{ include "ha.name" . }}
app.kubernetes.io/managed-by: Helm
{{- end }}

{{- define "ha.selectorLabels" -}}
app.kubernetes.io/name: {{ include "ha.name" . }}
{{- end }}

service.yaml
#

# ---------------------------------------------------------------------------
# 📡 Expose Home Assistant en interne ou en externe selon le type de service
# (ClusterIP, NodePort, etc.)
# ---------------------------------------------------------------------------

apiVersion: v1
kind: Service
metadata:
  name: {{ include "ha.fullname" . }}
  labels: {{- include "ha.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - name: http
      port: {{ .Values.service.port }}
      targetPort: http
  selector: {{- include "ha.selectorLabels" . | nindent 4 }}

pvc.yaml
#

# ---------------------------------------------------------------------------
# 💾 Provisionne un volume persistant pour stocker les données de Home Assistant
# ---------------------------------------------------------------------------
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: {{ include "ha.fullname" . }}-data
  labels: {{- include "ha.labels" . | nindent 4 }}
spec:
  accessModes: [{{ .Values.storage.accessMode }}]
  storageClassName: {{ .Values.storage.storageClass }}
  resources:
    requests:
      storage: {{ .Values.storage.size }}

configmap.yaml
#

# ---------------------------------------------------------------------------
# ⚙️ Injecte la configuration YAML de Home Assistant depuis les valeurs Helm
# ---------------------------------------------------------------------------
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "ha.fullname" . }}-config
  labels: {{- include "ha.labels" . | nindent 4 }}
data:
  # Le fichier bootstrapé ; toute modif = PR → Argo CD → diff appliqué
  configuration.yaml: |
{{ .Values.configuration | indent 4 }}

ingress.yaml
#

# ---------------------------------------------------------------------------
# 🌐 Déclare un Ingress HTTPs avec redirection SSL et certificats Let's Encrypt 
# (si activé)
# ---------------------------------------------------------------------------
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "ha.fullname" . }}
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-http01
    nginx.ingress.kubernetes.io/limit-rpm: "300"
    nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
  ingressClassName: {{ .Values.ingress.className }}
  tls:
    - secretName: {{ .Values.ingress.tlsSecret }}
      hosts: [{{ .Values.ingress.host }}]
  rules:
    - host: {{ .Values.ingress.host }}
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: {{ include "ha.fullname" . }}
                port:
                  number: {{ .Values.service.port }}
{{- end }}
L’ingress est purement optionnel. Cela va exposé votre pod vers l’exterieur - Faites très attention avec cette partie. De plus il vous faudra rediriger les port TCP {80,443} vers NGINX Ingress Controller.. et éventuellement disposer d’un nom de domaine pour rediriger vers votre IP Publique.. Je ne saurais que vous conseillez d’utiliser des bonnes rêgles firewall ainsi qu’un 2FA en cas d’exposition.

deployment.yaml
#

# ---------------------------------------------------------------------------
# 🚀 Déploie Home Assistant avec montée en réplica, volume persistant, ConfigMap # et variables d’environnement via Secret
# ---------------------------------------------------------------------------
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "ha.fullname" . }}
  labels: {{- include "ha.labels" . | nindent 4 }}
  annotations:
    # Force le rollout si le ConfigMap change
    checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels: {{- include "ha.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels: {{- include "ha.selectorLabels" . | nindent 8 }}
    spec:
      nodeSelector: {{- toYaml .Values.nodeSelector | nindent 8 }}
      containers:
        - name: home-assistant
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8123
          env:                       # ex: TZ
            - name: TZ
              value: Europe/Paris
            # --- clé API Govee depuis le Secret scellé ---
            - name: GOVEE_TOKEN
              valueFrom:
                secretKeyRef:
                  name: home-assistant-env    # ⬅️ doit correspondre au SealedSecret
                  key: GOVEE_TOKEN
          volumeMounts:
            - name: data
              mountPath: /config
            - name: bootstrap-config
              mountPath: /config/configuration.yaml
              subPath: configuration.yaml
              readOnly: true          # ⬅️ verrou GitOps
          resources: {{- toYaml .Values.resources | nindent 12 }}
      volumes:
        - name: data                 # PVC RW (Longhorn)
          persistentVolumeClaim:
            claimName: {{ include "ha.fullname" . }}-data
        - name: bootstrap-config     # ConfigMap RO
          configMap:
            name: {{ include "ha.fullname" . }}-config

📑 4. Overlays prod/
#

overlays/prod/kustomization.yaml
#

# ---------------------------------------------------------------------------
# 🧩 Point d’entrée Kustomize : applique le chart Helm local avec des valeurs   # "prod" et un SealedSecret
# ---------------------------------------------------------------------------
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

# On commence par tout ce qui se trouve dans ../../base
resources:
  - home-assistant-env-sealed.yaml
# Chemin où Kustomize ira chercher les charts Helm locaux
helmGlobals:
  chartHome: ../../helm

# Déclaration du chart à rendre pour cet overlay
helmCharts:
  - name: home-assistant            # dossier sous charts/
    releaseName: home-assistant
    namespace: home-assistant
    valuesFile: values-prod.yaml    # surcharge « prod »
    includeCRDs: false

values-prod.yaml
#

# ---------------------------------------------------------------------------
# 🔧 Surcharges propres à l’environnement "prod" : affinage CPU, mémoire et node # ciblé
# ---------------------------------------------------------------------------
nodeSelector:
  kubernetes.io/hostname: cube00

resources:
  requests:
    cpu: 100m
    memory: 256Mi
  limits:
    cpu: "2"    # ← 2 vCPU complets
    memory: 1Gi   # ← gardez 1 Gi ; montez à 1.5 Gi si ça reste juste

home-assistant-env-sealed.yaml
#

Govee est une marque de luminaire connecté - Cette étape n’est pas du tout obligatoire si vous ne disposez pas de leurs équipements.
kubectl -n home-assistant create secret generic home-assistant-env \
 --from-literal=GOVEE_TOKEN="<votre‑clé>" -o yaml --dry-run=client | \
 kubeseal -n home-assistant \
   --controller-namespace sealed-secrets \
   --controller-name sealed-secrets \
   --format yaml > overlays/prod/home-assistant-env-sealed.yaml

Argo CD le déchiffre à l’application et crée le Secret « clair » dans le namespace.

home-assistant-env.sealed.yaml
#

# ---------------------------------------------------------------------------
# 🔐 Secret chiffré via SealedSecrets : injecte des variables d’environnement    # sensibles (ex: GOVEE_TOKEN)
# ---------------------------------------------------------------------------
---
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  creationTimestamp: null
  name: home-assistant-env
  namespace: home-assistant
spec:
  encryptedData:
    GOVEE_TOKEN: Votre_Token_IcI_en_base64
  template:
    metadata:
      creationTimestamp: null
      name: home-assistant-env
      namespace: home-assistant

📄 5. Déclaration Argo CD - app-of-apps (app.yaml)
#

# ---------------------------------------------------------------------------
# 🚀 Manifest de déclaration de l'application dans ArgoCD
# ---------------------------------------------------------------------------
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: home-assistant
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://gitlab.com/<votre-repo>/homelab-gitops.git
    targetRevision: main
    path: apps/home-automation/home-assistant/overlays/prod
    kustomize:
      enableHelm: true            # ← suffisant avec Argo v3
  destination:
    server: https://kubernetes.default.svc
    namespace: home-assistant
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

Tip : Ce fichier est découvert automatiquement par l’App‑of‑Apps parent, nul besoin de l’appliquer manuellement.


🕹️ 6. Étape unique de bootstrap
#

# Argo CD est déjà installé
kubectl apply -f apps/home-automation/home-assistant/app.yaml

Si vous avez suivi les précédents articles sur app-of-apps, alors le déploiement se fera à la prochaine réconciliation.

En quelques secondes :

  • le namespace home-assistant est créé ;
  • PVC, ConfigMap, Ingress, Secret sont provisionnés ;
  • votre instance Home Assistant est accessible sur https://votre-domaine.com avec certificat Let’s Encrypt.

Home Assistant - ArgoCD

🔌 Tester sans DNS : port forwarding local
#

Si vous n’avez pas encore de nom de domaine configuré, accédez à Home Assistant localement :

kubectl -n home-assistant port-forward svc/home-assistant 8123:8123

Puis ouvrez : http://localhost:8123 🧪

Interface HA accessible en HTTPS ou via un port forwarding en local :

Home Assistant - Première Connexion


📌 7. Aller plus loin
#

  • Automatiser les sauvegardes (addon Backup) vers votre NAS ;
  • Superviser Home Assistant via Prometheus/Loki (ServiceMonitor, règles PromQL) ;
  • Ajouter des NetworkPolicies ou une PodDisruptionBudget (voir base/kustomization.yaml).

💡 La prochaine page détaillera l’intégration Govee LAN et la découverte mDNS depuis un Pod.


TL;DR
#

ÉlémentLocalisation Git
Chart Helm minimalhelm/home-assistant/
Overlay prod + Secret scelléoverlays/prod/
Application Argo CDapp.yaml
Point d’entrée App‑of‑Appsbootstrap/homelab.yaml → apps/
URL d’accèshttps://votre-domaine.com

Accrochez‑vous : tout est piloté par Git ; un commit = un déploiement.✨

Articles connexes

Installation d’Argo CD avec Ansible
·Temps de lecture : 4 minutes· loading · loading
ksh2177
Argo CD Kubernetes Helm GitOps Ansible DevOps K3s Homelab
Déployer Argo CD dans le cluster K3s à l’aide d’un playbook Ansible Helm complet et idempotent.
Structure GitOps et App-of-Apps
·Temps de lecture : 2 minutes· loading · loading
ksh2177
GitOps Argo CD Kubernetes App-of-Apps DevOps Homelab K3s
Organisation du dépôt GitOps et déclaration du manifeste App-of-Apps dans Argo CD pour gérer les applications.
Network settings
·Temps de lecture : 4 minutes· loading · loading
ksh2177
K3s Kubernetes MetalLB LoadBalancer Helm Network ClusterIP Homelab DevOps
Déploiement de MetalLB pour gérer des adresses IP externes avec K3s : installation via Helm, configuration d’un pool d’IP et vérifications réseau.
Helm arkade
·Temps de lecture : 2 minutes· loading · loading
ksh2177
K3s Kubernetes Helm Arkade Package Manager CLI Tools DevOps Homelab
Installation de Helm et Arkade sur le cluster K3s : deux outils indispensables pour déployer et gérer des applications Kubernetes simplement.
Storage settings
·Temps de lecture : 9 minutes· loading · loading
ksh2177
K3s Kubernetes Storage Longhorn Ansible Raspberry Pi PersistentVolume DevOps Homelab
Choix, préparation et installation de Longhorn comme solution de stockage persistant Kubernetes pour K3s sur Raspberry Pi, avec montage automatique via Ansible.
Os settings
·Temps de lecture : 1 minutes· loading · loading
ksh2177
K3s Kubernetes DietPi Linux OS Iptables Ansible Homelab DevOps
Réglages système post-installation pour DietPi : mise à jour de l’OS, configuration réseau, iptables et préparation à Kubernetes.
Conf noeuds
·Temps de lecture : 3 minutes· loading · loading
ksh2177
K3s Kubernetes Ansible Raspberry Pi Homelab SSH Inventory Automation DevOps
Préparer les nœuds Raspberry Pi pour le cluster K3s : connectivité, SSH sans mot de passe, configuration d’Ansible et inventaire dynamique.
Bootstrap du cluster K3s - Préparation
·Temps de lecture : 3 minutes· loading · loading
ksh2177
K3s Ansible Bootstrap Homelab GitOps Infrastructure Raspberry Pi
Initialisation du dépôt homelab-k3s et création de l’inventaire Ansible pour les nœuds du cluster.
Design goal
·Temps de lecture : 2 minutes· loading · loading
ksh2177
K3s Kubernetes Ansible Raspberry Pi Homelab SSH Automation Cluster Infra-as-Code
Préparation des nœuds Raspberry Pi avant le déploiement du cluster K3s : réseau, SSH, Ansible et inventaire automatisé.