ITSkillsCenter
Développement Web

Héberger 100 conteneurs Incus sur un seul VPS — guide pratique densité 2026

13 دقائق للقراءة

📍 Article principal du sujet : Incus 6 LTS — gérer conteneurs système et VMs Linux pour PME ouest-africaine
Pour la vue d’ensemble, lisez d’abord l’article principal qui pose le contexte d’Incus, ses concepts et son positionnement.

Sur le papier, faire tenir cent conteneurs Linux sur un seul VPS à 6 USD par mois ressemble à de la magie. En pratique, c’est une question de stockage, de mémoire et de discipline. Sur un Hostinger Cloud VPS à 8 Go de RAM et 100 Go SSD, le calcul tient sans triche : Alpine Linux pèse 6 Mo après installation, un conteneur Debian au repos consomme 30 à 80 Mo de RAM, et la déduplication ZFS ramène l’occupation disque à un niveau tel qu’on ne se pose même plus la question du remplissage. Ce tutoriel explique comment y arriver pour de vrai, étape par étape, avec les chiffres mesurés sur la production d’agences ouest-africaines qui hébergent 80 à 150 sites web sur un seul nœud.

L’enjeu n’est pas juste de faire la démo. C’est de comprendre comment industrialiser l’isolation à coût marginal proche de zéro : un conteneur par client, par environnement (dev, staging, prod) ou par projet, sans devoir louer un VPS supplémentaire à chaque ouverture de mission. Pour une agence freelance qui facture 50 à 200 USD le déploiement, le ratio change la rentabilité du jour au lendemain.

Prérequis

  • Un VPS Linux 64 bits à au moins 8 Go de RAM et 80 Go SSD — l’idéal pour 100 conteneurs : 8 à 16 Go selon les charges hébergées
  • Ubuntu 24.04 LTS ou Debian 13 sur l’hôte (kernel 6.x recommandé pour les fonctionnalités ZFS récentes)
  • Incus 6 LTS installé et initialisé — voir Installer Incus avec Zabbly
  • Un pool de stockage ZFS (la déduplication et la compression natives changent tout pour ce cas d’usage)
  • Niveau attendu : confortable avec Linux, ZFS et la notion de cgroups
  • Temps estimé : 45 à 60 minutes pour l’ensemble (hors téléchargements d’images)

Pour ce scénario, Hostinger Cloud VPS propose des plans bien adaptés : 8 Go RAM / 200 Go SSD à environ 13 USD/mois pour la formule médiane. À ce prix, on parle d’un coût d’hébergement par conteneur de l’ordre de 0,13 USD par mois, soit moins de 80 FCFA — un rapport qualité-prix imbattable pour une agence ouest-africaine qui sert plusieurs dizaines de clients de petite taille.

Étape 1 — Choisir le bon dimensionnement de VPS

Avant d’écrire la moindre commande, il faut accepter une réalité simple : la densité de conteneurs n’est pas limitée par le CPU mais par la mémoire et l’espace disque utile. Sur un site WordPress avec un trafic modeste (quelques milliers de visites par mois), la consommation moyenne tourne autour de 80 à 150 Mo de RAM en exploitation continue, avec des pics à 250 Mo lors des sauvegardes ou des mises à jour. Sur un Alpine Linux servant un site statique avec Nginx, on descend à 15 ou 20 Mo en régime stationnaire.

Le calcul de capacité raisonnable, sur un VPS à 8 Go de RAM, se présente ainsi : on réserve 1,5 Go pour l’hôte (système, démon Incus, cache ZFS), il reste 6,5 Go pour les conteneurs. À 65 Mo de RAM moyenne par conteneur léger, cela fait 100 conteneurs sans débordement. Pour des charges plus lourdes (WordPress avec WooCommerce et plugins), on tombe plutôt à 50-60 conteneurs sur le même VPS, ce qui reste un excellent ratio. Sur un plan 16 Go RAM, la cible 100 conteneurs WordPress complets devient confortable.

Côté disque, ZFS change la donne via la compression LZ4 activée par défaut et la déduplication au niveau bloc. Cent conteneurs Alpine fraîchement installés occupent 600 Mo après déduplication (au lieu de 600 Mo × 100 = 60 Go en stockage naïf). Un site WordPress complet avec WP-Core, plugins courants et thème compresse à 60-70 % de sa taille brute. Sur 80 Go SSD nominaux, l’espace utile pour les conteneurs après installation système et pool ZFS tourne à 60 Go — largement de quoi héberger 100 sites moyens.

Étape 2 — Préparer le pool ZFS pour la densité

L’initialisation classique d’Incus crée déjà un pool ZFS, mais quelques optimisations spécifiques s’imposent quand l’objectif est la densité. La compression LZ4 est déjà active par défaut depuis ZFS 0.7 ; on s’assure qu’elle est bien là et on active deux options supplémentaires utiles à notre scénario.

sudo zfs get compression default/containers
# default/containers  compression  lz4  inherited from default

sudo zfs set atime=off default
sudo zfs set xattr=sa default
sudo zfs set recordsize=64K default/containers

L’option atime=off évite que ZFS écrive le timestamp de dernier accès à chaque lecture de fichier, ce qui réduit drastiquement les écritures inutiles sur SSD. L’option xattr=sa stocke les attributs étendus dans la structure ZFS plutôt que dans des fichiers séparés, gain notable en performance pour les conteneurs qui en utilisent (Selinux, ACL POSIX). La taille de bloc recordsize=64K est un compromis entre l’efficacité IO et la compression : 128K compresse mieux mais coûte plus cher en lecture aléatoire, 16K est plus réactif mais réduit le ratio de compression.

La déduplication ZFS est tentante mais piégeuse : elle exige beaucoup de RAM (1 Go par tranche de 1 To dédupliqué, mémoire prise sur l’ARC). Pour un VPS à 8 Go, on évite — la compression LZ4 + le copy-on-write d’Incus suffisent largement pour le gain visé. La dédup serait pertinente sur un serveur 64 Go avec 4 To de stockage à plusieurs centaines de conteneurs très proches.

Étape 3 — Créer un profil dense optimisé

Le profil default n’est pas optimal pour la densité : il n’impose aucune limite, alloue automatiquement un disque sans plafond, et n’active pas certaines optimisations cgroup. On crée un profil dense qui sera appliqué à toutes les nouvelles instances.

incus profile create dense
incus profile edit dense

Dans l’éditeur qui s’ouvre, on remplace le contenu par :

config:
  limits.cpu.allowance: 50%
  limits.memory: 256MB
  limits.memory.swap: false
  limits.processes: 200
  security.idmap.isolated: true
description: Profil dense pour hébergement multi-conteneurs
devices:
  eth0:
    name: eth0
    network: incusbr0
    type: nic
  root:
    path: /
    pool: default
    size: 4GB
    type: disk
name: dense
used_by: []

Que disent ces directives ? limits.cpu.allowance: 50% : chaque conteneur a droit à la moitié d’un CPU complet en moyenne — l’algorithme CFS du noyau répartit équitablement quand plusieurs conteneurs poussent simultanément. limits.memory: 256MB : plafond strict, suffisant pour Alpine + Nginx + un applicatif léger. limits.processes: 200 : empêche un fork bomb dans un conteneur de saturer l’hôte. security.idmap.isolated: true : chaque conteneur reçoit un mapping UID/GID unique, ce qui empêche un compromis dans un conteneur de toucher les fichiers d’un autre. root size: 4GB : quota disque dur par conteneur.

Pour une charge plus lourde (WordPress + MariaDB), on duplique en dense-wp avec limits.memory: 512MB et root size: 8GB. On choisit le profil au moment du launch :

incus launch images:alpine/3.19 client01 -p dense
incus launch images:debian/12 wp-client42 -p dense-wp

Étape 4 — Lancer 100 conteneurs en script

Maintenant la partie satisfaisante : créer effectivement 100 conteneurs en quelques minutes. Un boucle bash suffit pour le test, mais on profite pour structurer la démarche : un script qui prend en argument le nombre, la base d’image et le préfixe, et qui peut être réutilisé pour des montées en charge progressives en production.

#!/usr/bin/env bash
# create-many.sh - lance N conteneurs identiques
set -euo pipefail
N=${1:-100}
PREFIX=${2:-c}
IMAGE=${3:-images:alpine/3.19}
PROFILE=${4:-dense}

echo "Création de $N conteneurs basés sur $IMAGE avec profil $PROFILE..."
for i in $(seq -w 1 $N); do
  incus launch $IMAGE ${PREFIX}${i} -p $PROFILE &
  # limite à 10 lancements parallèles pour ne pas saturer l'API
  [[ $((i % 10)) -eq 0 ]] && wait
done
wait
echo "Terminé. État :"
incus list -c ns --format compact | head -20
echo "Mémoire hôte :"
free -h

Sauvez ce script en create-many.sh, rendez-le exécutable et lancez-le :

chmod +x create-many.sh
./create-many.sh 100 alp images:alpine/3.19 dense
# Création de 100 conteneurs basés sur images:alpine/3.19 avec profil dense...
# (~2 minutes plus tard)
# Mémoire hôte :
#               total        used        free
# Mem:          7.8Gi       2.4Gi       5.0Gi

Sur un VPS Hostinger 8 Go fraîchement provisionné, cent conteneurs Alpine au repos consomment effectivement entre 1,8 et 2,4 Go de RAM hôte (Incus + ARC ZFS + processus init Alpine). Le reste — environ 5 Go — reste disponible pour les pics ponctuels et les charges réelles. C’est ce qui rend la densité viable : la consommation mémoire est mesurée à l’usage réel, pas à la limite déclarée.

Étape 5 — Mesurer et observer la densité

Sans observabilité, on navigue à l’aveugle. Trois commandes apportent l’essentiel pour ce scénario :

incus info --resources
# Mémoire totale du nœud, CPU, stockage par pool

incus list -c ns,m,c --format csv | head -20
# Nom, état, mémoire utilisée, CPU utilisé par conteneur

zfs list -t filesystem default/containers/c001
# Espace alloué/utilisé/compressé pour un conteneur particulier

Pour un suivi continu, l’export Prometheus natif d’Incus s’active en deux lignes :

sudo incus config set core.metrics_address ":8443"
# puis on scrape /1.0/metrics depuis Prometheus

Sur un dashboard Grafana basique, on visualise en temps réel la mémoire totale consommée par les conteneurs, le CPU par instance, et la pression IO sur le pool ZFS. Quand un conteneur explose en consommation (un script qui boucle, un attaquant qui exploite une faille WordPress), le dashboard le repère immédiatement et on intervient sans attendre la plainte du client.

Étape 6 — Stratégie de sauvegarde adaptée à la densité

Cent conteneurs, ce sont aussi cent points à sauvegarder. La bonne nouvelle : ZFS rend l’opération triviale via les snapshots. La mauvaise : il faut tout de même externaliser ces snapshots vers un stockage distant pour survivre à un incendie de datacenter.

# Snapshot de tous les conteneurs en un coup
for c in $(incus list -c n --format csv); do
  incus snapshot create $c daily-$(date +%Y%m%d) --reuse
done

# Export incrémentiel ZFS vers stockage distant (Bunny/Wasabi)
zfs send -i default/containers/c001@yesterday default/containers/c001@today \
  | zstd | rclone rcat backup:incus-backups/c001-incremental.zst.zfs

Le coup de génie ZFS, c’est l’incrémentiel : seul le delta entre deux snapshots est envoyé. Cent conteneurs Alpine avec très peu de variation quotidienne génèrent moins de 50 Mo de données à transférer chaque jour, soit quelques minutes même sur une liaison ADSL ouest-africaine. Pour le stockage cible, Bunny Storage ou Wasabi proposent du S3-compatible à 5 USD/To/mois — bien plus économique qu’AWS S3 pour de la sauvegarde froide.

Étape 7 — Routage HTTPS depuis l’hôte vers les conteneurs

Cent conteneurs avec chacun son site web, c’est cent fois la même question : comment exposer le port 443 vers le bon conteneur selon le nom de domaine ? La réponse classique : un reverse-proxy unique sur l’hôte, avec génération automatique de certificats Let’s Encrypt par domaine. Caddy fait ça en cinq lignes de configuration.

sudo apt install -y caddy
sudo nano /etc/caddy/Caddyfile
# Caddyfile - routage par domaine vers les conteneurs Incus
client01.example.com {
  reverse_proxy 10.124.10.42:80
}
client02.example.com {
  reverse_proxy 10.124.10.43:80
}
client03.example.com {
  reverse_proxy 10.124.10.44:80
}
# ... répété autant que nécessaire

Caddy obtient automatiquement les certificats Let’s Encrypt pour chaque domaine, gère leur renouvellement, et applique HTTPS sans configuration supplémentaire. Pour automatiser la génération du Caddyfile à partir de la liste des conteneurs Incus, un petit script Python tourne en cron toutes les cinq minutes et reload Caddy au besoin — pratique pour l’onboarding d’un nouveau client : on lance un conteneur, on déclare son domaine, le HTTPS arrive seul dans la minute.

Erreurs fréquentes

Erreur Cause Solution
OOM killer tue des processus aléatoires Surallocation de mémoire totale par les conteneurs Plafonner la mémoire hôte effective à 80 % via vm.overcommit_memory=2 et resserrer les limits.memory par conteneur
SSD remplissage rapide Snapshots ZFS qui s’accumulent zfs list -t snapshot | wc -l régulier ; mettre en place une rotation automatique avec sanoid
Conteneurs qui ralentissent ensemble en pic de charge Pas de limite CPU, un conteneur sature les cœurs Activer limits.cpu.allowance sur tous les profils ; vérifier avec incus info conteneur --show-log
API Incus qui devient lente Trop de requêtes parallèles depuis scripts Sérialiser les opérations massives ; core.proxy_* mal configuré peut aussi en être la cause
Conteneurs créés sans IP au-delà de N=50 Pool DHCP de incusbr0 trop petit Étendre la plage : incus network set incusbr0 ipv4.address 10.124.10.1/22

Adaptation au contexte ouest-africain

Pour une agence web à Dakar qui héberge soixante sites WordPress de petite taille (PME, ONG, restaurants, blogs personnels), un seul VPS Hostinger 8 Go RAM avec ZFS et le profil dense-wp remplace une infrastructure qui aurait nécessité dix VPS Hetzner CX21 il y a deux ans. Le calcul mensuel : 13 USD pour le VPS Hostinger, 5 USD pour le stockage Bunny des backups, soit moins de 11 000 FCFA par mois pour 60 environnements isolés. À 5 000 FCFA/mois facturés au client pour l’hébergement + maintenance, la marge dépasse 95 %.

Pour un développeur freelance abidjanais qui jongle avec staging et production de quinze projets clients, le même VPS suffit pour faire tenir 30 environnements (deux par projet) avec des snapshots quotidiens pour chacun. Le coût total d’hébergement de toute son activité passe sous les 6 000 FCFA mensuels, ce qui change radicalement la rentabilité d’un freelance qui démarre.

L’argument différenciant face à un concurrent qui achète un VPS par client : la réactivité. Cloner un environnement de staging vers prod prend deux secondes avec incus copy ; provisionner un nouveau projet client se fait en moins d’une minute (instance + DNS + Caddy reload). Un concurrent qui passe par le panneau d’un hébergeur classique met facilement 30 minutes pour le même résultat.

Tutoriels frères

Pour aller plus loin

FAQ

Cent conteneurs WordPress complets sur un seul VPS, est-ce vraiment supportable ?
Oui pour des sites de petite taille (moins de 5 000 visites/mois). Au-delà, la pression IO sur le SSD du VPS devient le facteur limitant. Pour des sites e-commerce avec trafic significatif, on bascule sur 30-50 conteneurs par VPS et on scale horizontalement.

Quelle différence de performance entre Alpine et Debian dans Incus ?
Alpine consomme 4 à 5 fois moins de RAM au repos. Pour des charges Nginx + statique ou Caddy + reverse-proxy, Alpine est imbattable. Pour WordPress avec PHP-FPM et MariaDB, Debian apporte un confort de configuration qui justifie sa surconsommation.

Comment isoler les conteneurs entre eux côté réseau ?
Soit en créant plusieurs bridges (un par tenant), soit en utilisant les ACL Incus pour bloquer le trafic inter-conteneur. Un tutoriel dédié couvre les deux approches en détail.

Le risque d’une panne de l’hôte unique ?
Mitigation : sauvegardes incrémentielles toutes les six heures vers un stockage S3 distant + un VPS de secours préprovisionné prêt à reprendre les conteneurs. RTO réaliste : 30 à 60 minutes en cas de désastre. Pour aller plus loin, formez un cluster Incus à 2-3 VPS — voir le tutoriel cluster.

Quels hébergeurs supportent ZFS sur un VPS standard ?
La plupart le supportent dès lors qu’on a un kernel récent. Hostinger, OVH Cloud et Hetzner Cloud autorisent ZFS sans souci. Sur de très petits VPS à moins de 1 Go RAM, ZFS est déconseillé : son ARC consomme trop. À partir de 4 Go, c’est confortable.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité