
À la maison, j’ai déployé un Kubernetes vanilla sur un cluster de trois mini-PC NiPoGi AM21. À côté, mon NAS, un serveur custom, héberge des applications avec Docker Compose.
Pourquoi conserver les deux ? Parce qu’ils répondent à des besoins différents. Je veux pouvoir exploiter plusieurs machines, améliorer la disponibilité de certains services et industrialiser les déploiements. Je veux aussi garder une solution simple pour les applications qui n’ont pas besoin de toute cette infrastructure.
Le fil conducteur de ce homelab, c’est la résilience, la sauvegarde et la possibilité de tout remonter facilement. Avec une contrainte très concrète : à la campagne, une coupure d’électricité reste possible, même quand on a prévu un onduleur.
Deux environnements pour un même homelab
Mon installation se répartit aujourd’hui de cette façon :
| Environnement | Matériel | Services hébergés |
|---|---|---|
| Kubernetes vanilla | 3 mini-PC NiPoGi AM21 | LLDAP, Keycloak, WordPress, Grafana, Loki, Prometheus, GitLab, PlantUML, Diagrams, GLPI, Traefik, Pi-hole, Home Assistant avec des conteneurs additionnels pour certains protocoles, et un service custom qui affiche la page d’accueil de mon domaine. |
| Docker Compose | NAS sur serveur custom | Traefik, Nextcloud, Immich, Jellyfin, Nexus et Calibre. |
Cette répartition correspond à mon contexte. Elle ne signifie pas que Nextcloud ou Immich ne peuvent pas fonctionner sur Kubernetes, ni que WordPress nécessite un cluster. Le choix dépend aussi du stockage, des dépendances et du temps que je souhaite consacrer à chaque application.
Deux façons différentes d’exploiter des conteneurs
La comparaison porte surtout sur l’exploitation. Compose décrit une application composée de services que Docker exécute sur un hôte. Kubernetes reçoit des ressources via son API, puis travaille en continu pour rapprocher la situation réelle de l’état souhaité.
Dans Kubernetes, le scheduler choisit un nœud pour les pods qui ne sont pas encore affectés. Le kubelet de chaque nœud pilote leur exécution via le runtime, tandis que les contrôleurs surveillent les ressources qu’ils gèrent. Cette séparation explique à la fois la flexibilité du système et le nombre de couches à examiner en cas de problème. Voir la documentation sur l’architecture Kubernetes.
Un fichier YAML ne représente donc pas exactement le même contrat dans les deux environnements. Avec Compose, je décris la stack du serveur ciblé. Avec Kubernetes, j’alimente un système distribué de réconciliation. Le second offre davantage de possibilités, mais réclame davantage de composants pour fonctionner.
Kubernetes : exploiter un cluster et viser une meilleure disponibilité
L’intérêt de Kubernetes, pour moi, commence avec les trois machines. Il permet de répartir les applications et de décrire l’état attendu : quels services doivent tourner, avec quelles ressources et combien de réplicas.
Ses contrôleurs cherchent ensuite à maintenir cet état. Un conteneur peut être redémarré ; les pods gérés par un contrôleur peuvent être remplacés après une défaillance, éventuellement sur un autre nœud si les conditions le permettent. C’est une base intéressante pour les services dont je souhaite réduire les interruptions. Ces mécanismes sont détaillés dans la documentation Kubernetes sur l’autoréparation.
Il faut toutefois prévoir de la marge. Si les trois mini-PC sont déjà saturés, perdre une machine ne crée pas miraculeusement de capacité sur les deux autres. Et un processus unique ne cumule pas automatiquement la puissance des trois nœuds : le gain vient de la répartition des charges et des applications capables de fonctionner avec plusieurs instances.
Trois nœuds ne suffisent pas, à eux seuls, à garantir la haute disponibilité. Il faut aussi considérer le plan de contrôle, etcd et l’accès à l’API. À titre d’exemple, la topologie avec etcd colocalisé décrite par Kubernetes prévoit au moins trois nœuds de contrôle pour la haute disponibilité. La répartition des rôles compte donc autant que le nombre de machines. Voir les topologies haute disponibilité de Kubernetes.
Il reste ensuite la disponibilité de l’application : ses réplicas, sa base de données, ses volumes et ses dépendances. Un pod recréé ailleurs n’est utile que s’il peut retrouver ce dont il a besoin. Pour une application avec état, la stratégie de stockage est aussi importante que l’orchestrateur.
Le quorum etcd : trois machines ne racontent pas toute l’histoire
Dans une architecture avec trois membres etcd, la majorité nécessaire au fonctionnement est de deux membres. La perte d’un membre peut être tolérée ; la perte de deux empêche etcd d’accepter de nouvelles écritures. Cela suppose bien trois membres etcd, et pas simplement trois machines dont une seule assurerait ce rôle. Ce mécanisme est expliqué dans la documentation etcd sur les pannes.
Une indisponibilité du plan de contrôle ne signifie pas que tous les conteneurs déjà lancés s’arrêtent immédiatement. En revanche, je ne peux plus compter sur le fonctionnement normal des déploiements et du remplacement des pods. Maintenir le trafic existant et pouvoir réagir à une nouvelle défaillance sont deux propriétés distinctes.
Répartir les réplicas et conserver de la marge
Pour une application compatible avec plusieurs instances, il faut éviter de concentrer tous les réplicas sur le même nœud. Les règles d’anti-affinité et les topologySpreadConstraints permettent d’exprimer des contraintes ou des préférences de répartition. Une règle stricte peut cependant laisser un pod en attente si le cluster ne peut plus la satisfaire. Voir les contraintes de répartition topologique.
Sur trois machines comparables, raisonner en capacité « N−1 » consiste à vérifier si les services prioritaires tiennent encore sur deux nœuds. Il faut compter la mémoire, le CPU, le stockage accessible et les contraintes de placement. Les requests participent aux décisions du scheduler ; les limitsencadrent la consommation. Une limite mémoire trop basse peut entraîner une terminaison pour dépassement mémoire, tandis qu’une limite CPU peut provoquer du throttling. Voir la gestion des ressources Kubernetes.
Pour les maintenances, un PodDisruptionBudget peut limiter les évictions volontaires simultanées, notamment pendant le drainage d’un nœud. Il n’empêche pas une panne matérielle et ne garantit pas, à lui seul, la disponibilité. Il faut aussi assez de réplicas et de capacité pour poursuivre la maintenance. Voir les budgets de perturbation.
Un conteneur lancé n’est pas forcément un service prêt
Kubernetes distingue trois contrôles : la startupProbe laisse à l’application le temps de démarrer, la readinessProbe indique si elle peut recevoir du trafic via les services, et la livenessProbe détecte une situation pouvant nécessiter le redémarrage du conteneur. Une readiness en échec ne redémarre pas le conteneur à elle seule. Voir la documentation des probes.
Cette distinction compte pour les applications longues à initialiser. Une liveness trop agressive peut interrompre le démarrage en boucle. À l’inverse, vérifier uniquement qu’un port est ouvert peut laisser passer une application incapable de traiter une requête. Faire dépendre la liveness d’une base momentanément indisponible peut aussi provoquer des redémarrages en cascade sans résoudre la cause. Les endpoints et les seuils doivent donc correspondre au comportement réel du service.
Helm et la flexibilité : un vrai confort de déploiement
Kubernetes m’intéresse aussi pour son écosystème. Avec autant de services, pouvoir décrire et réutiliser les déploiements devient précieux.
Les charts Helm regroupent les ressources nécessaires à une application ou à une stack. On peut adapter leur configuration avec des valeurs propres à son environnement et conserver des versions identifiées. Cela évite de réécrire systématiquement tous les manifests. La documentation Helm présente ce fonctionnement.
Cette souplesse se retrouve dans la gestion des ressources, l’exposition des services et l’intégration de la supervision. Avec Grafana, Loki et Prometheus dans le cluster, l’observabilité fait elle aussi partie du homelab.
Un chart facilite l’installation, mais il ne dispense pas de comprendre l’application : persistance, consommation mémoire, sauvegarde et migrations restent à examiner. Déployer une stack et savoir l’exploiter dans la durée sont deux compétences complémentaires.
Pour rendre les déploiements reproductibles, il est utile de fixer la version du chart et de versionner les fichiers de valeurs. La version du chart et celle de l’application sont distinctes : il faut vérifier les images réellement déployées. Et un retour à une ancienne release ne garantit pas l’annulation d’une migration de base de données. Le retour arrière doit inclure l’état applicatif, pas seulement les manifests. La structure des charts Helm permet de comprendre cette séparation.
Le prix du vanilla : je maintiens aussi la plateforme
En choisissant Kubernetes vanilla, je garde la main sur l’assemblage de l’infrastructure. Cette liberté implique de choisir, configurer et maintenir plusieurs composants.
Parmi les sujets à traiter, on retrouve :
- L’exécution des conteneurs : un runtime compatible CRI, comme containerd ou CRI-O. La CRI est l’interface, pas le moteur lui-même. Voir la documentation sur les runtimes.
- Le réseau des pods : un plugin CNI, éventuellement fondé sur eBPF. eBPF est une technologie utilisée notamment par Cilium, pas un composant obligatoire de tout cluster.
- L’exposition des applications : un contrôleur comme Traefik et, selon l’architecture, une solution comme MetalLB pour les services de type LoadBalancer sur du bare metal.
- Les certificats : une solution comme cert-manager pour automatiser leur émission et leur renouvellement.
- Le stockage : les volumes persistants, leur disponibilité et leur restauration.
Il faut ensuite suivre les mises à jour, les compatibilités et les évolutions de configuration. Le coût se mesure autant en temps et en compétences qu’en ressources matérielles.
Le débogage demande aussi une vue d’ensemble. Un service inaccessible peut venir de l’application, du DNS, du réseau, du routage, d’un certificat ou d’un volume indisponible. Lire les logs ne suffit pas toujours : il faut pouvoir suivre le chemin de la requête et comprendre les événements du cluster.
C’est passionnant dans un homelab destiné aussi à apprendre. C’est plus contraignant lorsqu’on veut simplement remettre un service en route rapidement.
Traefik, MetalLB et le CNI n’ont pas le même rôle
Le CNI fournit le réseau nécessaire aux pods. Dans une architecture courante sur un réseau domestique, MetalLB rend joignable une adresse de service de type LoadBalancer. Traefik reçoit les requêtes HTTP ou HTTPS et les oriente vers les applications selon le domaine et les règles configurées. cert-manager peut gérer le cycle de vie des certificats utilisés pour cette exposition.
En mode Layer 2, MetalLB utilise ARP pour IPv4 et NDP pour IPv6 : un nœud annonce l’adresse du service. Le trafic entrant d’une IP passe par un seul nœud à un instant donné. Le mécanisme permet une bascule de l’annonce, mais ne cumule pas la bande passante des trois mini-PC pour cette adresse. La documentation MetalLB sur le mode Layer 2 présente aussi les limites de convergence lors d’une bascule.
La présence de Traefik dans mes deux environnements permet de conserver le même type de reverse proxy. Il faut néanmoins organiser les noms DNS, les adresses et le point d’entrée réseau. Deux instances indépendantes ne constituent pas automatiquement un dispositif commun de haute disponibilité.
Déboguer en suivant le chemin de la requête
Pour un service inaccessible, une méthode utile consiste à examiner la résolution DNS, le point d’entrée, le routage, les endpoints du service et l’état des pods. Un pod Pending peut signaler un problème de ressources ou de volume ; un CrashLoopBackOff invite à consulter les logs et les causes de sortie. L’objectif est de localiser la couche défaillante avant de relancer quoi que ce soit.
Ces commandes de lecture donnent un premier aperçu, avec des noms à adapter au service concerné :
kubectl get nodes
kubectl -n mon-app get pods -o wide
kubectl -n mon-app describe pod mon-pod
kubectl -n mon-app logs mon-pod --all-containers --tail=100
kubectl -n mon-app get events --sort-by=.metadata.creationTimestamp
kubectl -n mon-app get services,endpointslices,pvc
L’option --previous permet également de consulter les logs de la précédente instance d’un conteneur lorsqu’ils sont disponibles. La démarche est détaillée dans le guide de diagnostic Kubernetes.
Le stockage : là où la résilience se joue souvent
Une landing page sans état et une application qui conserve des fichiers n’ont pas les mêmes contraintes. Pour la première, recréer un pod peut suffire. Pour la seconde, il faut retrouver des données cohérentes, avec les bons droits et un stockage accessible depuis le nœud choisi.
Un PersistentVolumeClaim exprime une demande de stockage ; un PersistentVolume représente une ressource de stockage ; une StorageClass définit une classe et ses paramètres de provisionnement. Un pilote CSI peut assurer l’intégration avec le stockage. Ces abstractions facilitent son utilisation, mais ne déterminent pas à elles seules sa durabilité ou sa réplication.
Les modes d’accès comptent aussi. ReadWriteOnce signifie un montage en lecture-écriture depuis un seul nœud, pas nécessairement depuis un seul pod. ReadWriteMany permet l’écriture depuis plusieurs nœuds lorsque le stockage le prend en charge. Cela ne rend pas sûre toute écriture concurrente : l’application doit la supporter. Voir la documentation des volumes persistants.
Un volume local reste dépendant de son nœud. Un stockage réseau centralisé déplace la dépendance vers le serveur de stockage et le réseau. Un stockage distribué ajoute un coût de réplication, de la latence et des contraintes de reconstruction après panne. Sur du matériel de homelab, ces compromis méritent autant d’attention que le nombre de réplicas des applications.
Un StatefulSet apporte notamment des identités stables et une gestion adaptée à certains workloads avec état. Il ne transforme pas une base autonome en cluster répliqué. La réplication et la promotion d’une nouvelle instance principale relèvent de la base elle-même ou d’un opérateur spécialisé. Voir la documentation des StatefulSets.
WordPress illustre bien la question : multiplier les instances web oblige à réfléchir aux fichiers téléversés, à la cohérence du code et des extensions, ainsi qu’à la disponibilité de la base. Un service critique peut conserver une dépendance unique, même lorsqu’il est hébergé dans un cluster.
Docker Compose : une simplicité qui a toute sa place
Sur le NAS, Docker Compose apporte une approche plus directe. Un fichier décrit les services, leurs images, leurs volumes, leurs réseaux et leur configuration.
Pour une application simple, une image et quelques paramètres peuvent suffire. Mais Compose sait aussi gérer plusieurs conteneurs : une application, sa base de données et un cache, par exemple. Sa simplicité tient surtout à la gestion de cet ensemble dans une configuration lisible. Voir le modèle applicatif de Compose.
Je n’ai pas de plan de contrôle Kubernetes à exploiter pour ces services. Cela réduit les composants d’infrastructure, leur consommation et le nombre de couches à examiner en cas de problème. Le système hôte, Docker et les applications demandent évidemment toujours des mises à jour et des sauvegardes.
Cette approche convient bien à la partie de mon homelab qui héberge notamment les fichiers, les photos et les médias. Elle reste tout à fait valable pour des services durables : Docker documente explicitement l’utilisation de Compose en production, notamment sur un serveur unique.
Sa limite, dans mon installation, est celle de l’hôte unique. Des politiques de redémarrage peuvent aider lorsqu’un conteneur s’arrête, mais elles ne déplacent pas les applications sur une autre machine si le NAS tombe en panne. La reprise dépend alors de la remise en service de l’hôte ou d’une restauration ailleurs.
Je peux accepter une interruption pour certains usages. Cela ne rend pas leurs données moins précieuses : la disponibilité de Jellyfin et la sauvegarde de mes photos ne répondent pas au même besoin.
Redémarrage, healthcheck et ordre de démarrage
Une politique comme restart: unless-stopped permet à Docker de relancer un conteneur dans les conditions prévues par cette politique. Un healthcheck produit un état de santé. Avec Docker Engine et Compose, le passage à unhealthy ne déclenche pas automatiquement un redémarrage tant que le processus continue à tourner : détection et réaction sont distinctes. Voir les politiques de redémarrage Docker.
Un simple depends_on définit un ordre de démarrage, sans garantir qu’une base accepte déjà les connexions. La condition service_healthy permet d’attendre son healthcheck lors du démarrage piloté par Compose. Elle ne remplace pas les mécanismes de reconnexion de l’application après une panne ultérieure. Voir la documentation sur l’ordre de démarrage.
Cet extrait pédagogique illustre ces réglages. Il s’agit d’un fragment à intégrer à une stack complète : images, volumes, secrets et paramètres de connexion restent à définir.
services:
application:
restart: unless-stopped
depends_on:
database:
condition: service_healthy
database:
restart: unless-stopped
healthcheck:
# Pour une image PostgreSQL disposant de pg_isready
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
Le double dollar conserve les variables pour leur évaluation dans le conteneur. Les durées sont à ajuster et pg_isready vérifie la disponibilité du serveur PostgreSQL, pas le fonctionnement de toutes les requêtes métier. Ce niveau de rigueur améliore déjà l’exploitation d’une stack Compose.
Les volumes et les bind mounts demandent la même attention. Il faut savoir où les données résident réellement et conserver leurs chemins, propriétaires et droits d’accès. Le nom d’un volume ne dit pas comment le restaurer. Voir la documentation du stockage Docker. Pour des applications comme Jellyfin ou Immich, la proximité des médias et l’accès éventuel à un accélérateur matériel peuvent également peser dans le choix de l’hôte.
La reproductibilité se prépare avec les deux solutions
Un homelab qui fonctionne aujourd’hui, c’est bien. Un homelab que je peux reconstruire sans retrouver une suite de commandes dans mon historique, c’est l’objectif.
Ansible peut servir de base commune : préparer les machines, installer les paquets, distribuer les configurations et automatiser les étapes de déploiement. Des playbooks conçus de manière idempotente permettent de réappliquer un état attendu sans refaire inutilement les changements. Cette propriété dépend des modules et de la façon d’écrire les tâches, comme le précise la documentation Ansible.
La démarche peut ensuite combiner :
- des playbooks Ansible pour préparer l’infrastructure ;
- des fichiers Compose ou des manifests et valeurs Helm versionnés ;
- des versions d’images et de charts explicitement fixées ;
- des secrets protégés et récupérables lors d’une reconstruction ;
- une procédure de restauration des données et un ordre de redémarrage documenté.
Cette industrialisation est accessible avec Compose. Kubernetes offre davantage de mécanismes d’orchestration, mais un fichier Compose maîtrisé et un déploiement automatisé constituent déjà une base solide.
Il faut aussi pouvoir récupérer les outils de reconstruction lorsque le homelab est arrêté. Avec GitLab dans le cluster et Nexus sur le NAS, conserver une copie accessible des configurations et prévoir l’accès aux images nécessaires évite de dépendre exclusivement des services que l’on cherche justement à restaurer.
Ansible pour préparer une reconstruction, pas seulement une installation
Pour structurer la reprise, je séparerais les responsabilités : préparation du système, installation du moteur ou du cluster, configuration des composants d’infrastructure, restauration des données, puis remise en service des applications. Cette séparation permet de comprendre ce qui manque lorsqu’une étape échoue.
Côté Compose, Ansible peut préparer les répertoires et les permissions, déposer les configurations, puis piloter les services. Côté Kubernetes, il peut automatiser la préparation des nœuds et des composants avant le déploiement des ressources ou des releases Helm. Le module community.docker.docker_compose_v2 illustre l’intégration avec Compose.
La rapidité arrive après ce travail. Un playbook rend une procédure répétable ; il ne supprime ni le téléchargement des images ni la restauration de plusieurs téraoctets. Il faut tester son idempotence réelle et documenter les étapes manuelles. Un premier déploiement réussi ne suffit pas à prouver que l’environnement peut être reconstruit.
Les secrets font partie de cette préparation. Leur récupération est indispensable, mais un encodage base64 n’est pas un chiffrement. Une solution comme Ansible Vault peut protéger les fichiers sensibles conservés avec le code, à condition de récupérer séparément la clé ou le mot de passe. Voir la documentation Ansible Vault.
Résilience, sauvegarde et coupure électrique
Je distingue trois objectifs : continuer à fonctionner malgré certaines pannes, récupérer les données après un incident et reconstruire l’environnement. Ils se complètent.
Une réplication ne protège pas forcément d’une suppression accidentelle. Un fichier de déploiement ne contient pas les photos d’Immich ni les fichiers de Nextcloud. Et une sauvegarde disponible ne garantit pas une restauration immédiate.
Pour rendre la reprise crédible, il faut prévoir des sauvegardes cohérentes des bases de données, des fichiers et des configurations, en garder une copie hors des machines concernées et tester leur restauration. Les éventuelles sauvegardes d’etcd répondent à un autre besoin : elles ne remplacent pas celles des données applicatives.
Le stockage mérite une attention particulière : si des volumes du cluster reposent sur un NAS unique, celui-ci reste un point de dépendance, même avec trois nœuds Kubernetes. C’est une question à examiner dans l’architecture, pas une propriété que Kubernetes résout automatiquement.
À la campagne, la coupure électrique rappelle aussi une limite physique : mes machines partagent le même site. L’onduleur apporte du temps pour traverser une coupure courte ou organiser un arrêt propre, selon son autonomie. Il ne permet pas de tenir indéfiniment.
Le retour du courant fait donc partie du scénario de reprise : réseau, stockage, DNS, authentification, puis applications selon leurs dépendances. Pour Home Assistant et les conteneurs liés à certains protocoles, il faut également tenir compte des éventuels périphériques ou passerelles : leur disponibilité ne se résume pas au redémarrage d’un pod.
Le résultat que je recherche : savoir ce qui peut continuer à fonctionner, quelles données je peux récupérer et comment remettre l’ensemble en service.
Définir ce que signifie « remonter facilement »
Deux indicateurs aident à rendre l’objectif concret : le RPO correspond à la quantité de données que l’on accepte de perdre, exprimée en durée ; le RTO correspond au délai visé pour rétablir le service. À titre d’exemple, une sauvegarde quotidienne réussie peut laisser presque vingt-quatre heures de modifications à perdre, selon l’instant de la panne. Une copie volumineuse à restaurer peut imposer plusieurs heures d’interruption même si les conteneurs se redéploient en quelques minutes.
Ces objectifs peuvent varier selon le service. Une landing page se reconstruit facilement si son code et son image sont disponibles. Pour une photothèque ou un espace de fichiers, la restauration des données devient centrale. Pour l’authentification et le DNS, le problème inclut les services qui en dépendent. Le bon scénario de reprise commence donc par ces dépendances, pas par l’ordre alphabétique des applications.
Dans Kubernetes, il faut également distinguer la restauration du cluster depuis un snapshot etcd et la reconstruction d’un cluster neuf à partir des déclarations versionnées. Ce sont deux procédures différentes. Le snapshot etcd contient l’état Kubernetes, pas le contenu des volumes applicatifs. Les contraintes de version et les étapes de restauration méritent une procédure dédiée, comme le précise la documentation d’exploitation d’etcd.
Tester le redémarrage et vérifier le service rendu
Après une coupure, voir tous les conteneurs démarrés ne suffit pas. Il faut vérifier une résolution DNS, une authentification, l’ouverture d’un fichier, l’accès aux médias ou une interaction domotique selon le service. Une base peut tourner alors que l’application échoue sur des droits de fichiers, un secret manquant ou une dépendance réseau.
Le scénario doit aussi inclure un accès d’administration indépendant des services en cours de restauration. Si l’authentification centrale est arrêtée, il faut pouvoir intervenir sur les machines. Si le DNS du homelab ne répond plus, il faut encore savoir joindre les équipements indispensables. Et si le monitoring est dans le cluster, son silence peut lui-même provenir de la panne que l’on cherche à détecter.
Un exercice progressif, sur un service non critique puis sur une restauration isolée, permet de mesurer les délais et de repérer les étapes oubliées. L’objectif est de vérifier que les sauvegardes sont exploitables et que la procédure fonctionne avec les ressources disponibles après l’incident. C’est ce test qui donne du sens à l’automatisation.
Kubernetes ou Compose : choisir selon son contexte
Pour décider où placer un service, je retiens quelques critères :
| Besoin | Orientation |
|---|---|
| Déployer sur un serveur avec peu de composants à maintenir | Docker Compose |
| Répartir des applications entre plusieurs machines | Kubernetes |
| Réduire l’impact de la perte d’un nœud | Kubernetes, avec une architecture applicative et un stockage adaptés |
| Automatiser et reproduire les déploiements | Les deux, avec du versionnement et des outils comme Ansible |
| Protéger les données et restaurer après un incident | Une stratégie de sauvegarde, quelle que soit la plateforme |
Mon choix est de faire cohabiter les deux. Kubernetes me donne un terrain pour la résilience, la flexibilité et l’industrialisation sur plusieurs machines. Docker Compose conserve une place essentielle pour sa simplicité d’exploitation sur le NAS.
Selon ses besoins, son temps et ses compétences, utiliser Docker Compose est déjà un très bon choix. Un homelab complet peut reposer sur cette seule solution, à condition de prendre soin de ses configurations et de ses données.
Chez moi, les deux environnements servent le même objectif : héberger mes services, apprendre et préparer leur remise en route quand quelque chose finit par tomber en panne. Y compris quand ce quelque chose, c’est l’électricité.