Aller au contenu

Virtualisation et abstraction matérielle

Hyperviseurs, conteneurs et le coût de l'abstraction entre le logiciel et le matériel.


Pourquoi virtualiser

La virtualisation résout un problème économique avant d'être un choix technique. Un serveur physique typique utilise 10 a 15% de sa capacité CPU en moyenne. Virtualiser permet de consolider plusieurs charges de travail sur le même matériel, augmentant l'utilisation a 60-80%.

Au-delà de la consolidation, la virtualisation apporte l'isolation (chaque charge est séparée des autres), la portabilité (une VM ou un conteneur tourne partout) et l'élasticité (on peut créer et détruire des instances en secondes).


Hyperviseurs

Un hyperviseur est le logiciel qui crée et géré les machines virtuelles. Il intercepte les instructions privilégiées des systèmes d'exploitation invites et les traduit vers le matériel réel.

Type 1 : bare-metal

L'hyperviseur s'installe directement sur le matériel, sans système d'exploitation hôte. Il a un contrôle total sur les ressources.

graph TB
    VM1["VM 1<br>Linux"] --> HV["Hyperviseur Type 1"]
    VM2["VM 2<br>Windows"] --> HV
    VM3["VM 3<br>Linux"] --> HV
    HV --> HW["Materiel"]

Exemples : VMware ESXi, Microsoft Hyper-V (bare-metal), KVM (techniquement hybride — le noyau Linux est l'hyperviseur), Xen.

  • Avantages : performances proches du natif, isolation forte, gestion fine des ressources
  • Inconvénients : nécessité du matériel dédié, complexité d'administration

Type 2 : hosted

L'hyperviseur s'installe comme une application sur un système d'exploitation existant. Plus simple à déployer, mais avec un overhead supplémentaire.

graph TB
    VM1["VM 1"] --> HV["Hyperviseur Type 2"]
    VM2["VM 2"] --> HV
    HV --> OS["OS hote"]
    OS --> HW["Materiel"]

Exemples : VirtualBox, VMware Workstation, Parallels Desktop.

  • Avantages : installation facile, cohabitation avec l'OS hôte
  • Inconvénients : overhead de la double couche OS, performances moindres
  • Usage : développement local, tests, postes de travail

Virtualisation assistee par le matériel

Les processeurs modernes intègrent des extensions de virtualisation (Intel VT-x, AMD-V) qui permettent à l'hyperviseur d'exécuter le code invite directement sur le CPU, sans émulation. Cela réduit l'overhead CPU a 1-5% pour la plupart des charges.

Les extensions incluent :

  • VT-x / AMD-V : exécution directe des instructions non-privilégiées
  • EPT / NPT : traduction d'adresses mémoire a deux niveaux (guest virtual → guest physical → host physical), éliminant le coût de la shadow page table
  • VT-d / AMD-Vi : accès direct aux périphériques (passthrough I/O), permettant à une VM d'utiliser un GPU ou une carte réseau sans overhead

Virtualisation complète vs para-virtualisation

Virtualisation complète

Le système invite ne sait pas qu'il est virtualise. L'hyperviseur emule un matériel complet. Aucune modification du guest OS n'est nécessaire.

  • Avantage : n'importe quel OS non modifie fonctionne
  • Inconvénient : certaines opérations (I/O, interruptions) sont plus lentes car émulées

Para-virtualisation

Le système invite est modifie pour coopérer avec l'hyperviseur. Au lieu d'exécuter des instructions privilégiées (qui doivent être interceptées), le guest appelle directement l'hyperviseur via des hypercalls.

  • Avantage : meilleures performances I/O (le guest sait qu'il est virtualise)
  • Inconvénient : nécessité un noyau modifie

En pratique, l'approche dominante est hybride : virtualisation complète assistee par le matériel pour le CPU et la mémoire, drivers para-virtualisés (virtio) pour le réseau et le stockage. C'est le modèle de KVM/QEMU avec les drivers virtio, qui combine le meilleur des deux mondes.


Conteneurs

Les conteneurs sont une forme de virtualisation au niveau du système d'exploitation. Au lieu de virtualiser le matériel, on isole les processus en utilisant des fonctionnalités du noyau Linux.

Mécanismes fondamentaux

Mécanisme Rôle
Namespaces Isolation : chaque conteneur a sa propre vue du PID, du réseau, du filesystem, des utilisateurs
Cgroups Limitation : contrôle la quantite de CPU, mémoire, I/O qu'un conteneur peut utiliser
Overlay FS Efficacité : les images sont composees de couches en lecture seule, seule la couche supérieure est modifiable
Seccomp Sécurité : filtre les appels système autorises
Capabilities Sécurité : granularité fine des privileges root
graph TB
    subgraph "Machine virtuelle"
        APP1["Application"] --> GUESTOS["Guest OS complet"]
        GUESTOS --> HV2["Hyperviseur"]
        HV2 --> HW2["Materiel"]
    end
graph TB
    subgraph "Conteneur"
        APP2["Application"] --> RUNTIME["Container runtime"]
        RUNTIME --> HOSTOS["Noyau hote (partage)"]
        HOSTOS --> HW3["Materiel"]
    end

La différence fondamentale : une VM embarque un système d'exploitation complet (noyau + userland), typiquement 200 MB a plusieurs GB. Un conteneur partage le noyau de l'hôte et n'embarque que les librairies nécessaires à l'application, typiquement 10-200 MB.

Comparaison VM vs conteneur

Critère Machine virtuelle Conteneur
Isolation Forte (matériel virtualise) Modérée (noyau partage)
Overhead CPU 1-5% < 1%
Overhead mémoire 200 MB - 2 GB par VM (guest OS) 5-50 MB par conteneur
Temps de démarrage 30 s - 2 min 100 ms - 2 s
Densite 10-50 VM par serveur 100-1000 conteneurs par serveur
Sécurité Forte (surface d'attaque réduite) Plus faible (noyau partage)
Portabilité OS Tout OS (Linux, Windows, BSD) Même famille d'OS que l'hôte
Cas d'usage Isolation forte, OS hétérogènes Microservices, CI/CD, densite

Warning

L'isolation d'un conteneur est fondamentalement plus faible que celle d'une VM. Un conteneur partage le noyau de l'hôte — une vulnérabilité noyau (container escape) compromet toute la machine. C'est pourquoi les environnements multi-tenant sensibles (cloud public) utilisent des micro-VM (Firecracker, gVisor) qui combinent l'isolation d'une VM avec la légèreté d'un conteneur.


Overhead de la virtualisation

L'overhead varie considérablement selon le type de charge :

CPU

Avec les extensions matérielles (VT-x), l'overhead CPU est de 1 a 5% pour les VM et negligeable pour les conteneurs. Les calculs purs (compression, encryption, calcul scientifique) tournent quasiment a vitesse native.

Mémoire

  • VM : chaque VM réservé un bloc de RAM pour le guest OS. La technique de memory ballooning permet de réclamer la mémoire inutilisee, mais elle a un coût.
  • Conteneur : pas d'overhead structurel. Les cgroups limitent la mémoire mais ne la reservent pas à l'avance.
  • KSM (Kernel Same-page Merging) : deduplique les pages mémoire identiques entre VM. Efficace quand plusieurs VM exécutent le même OS.

I/O

L'I/O est historiquement le point faible de la virtualisation :

Approche Overhead I/O
Émulation complète (IDE virtuel) 20-50%
Para-virtualisation (virtio) 5-15%
Passthrough (VT-d, SR-IOV) < 1%
Conteneur (accès direct au noyau) < 1%

Le SR-IOV (Single Root I/O Virtualization) permet à une carte réseau physique de se présenter comme plusieurs cartes virtuelles, chacune assignee a une VM. Cela éliminé l'overhead de virtualisation réseau pour les charges sensibles à la latence.

Réseau

La virtualisation réseau (vSwitch, overlay networks) ajoute typiquement 10-20% d'overhead en throughput et 5-50 us de latence supplémentaire. Les techniques comme DPDK et XDP dans le datapath reduisent cet overhead.


vCPU et vRAM : mapping vers le matériel

vCPU

Un vCPU est un thread d'exécution assigne a une VM ou un conteneur. Le mapping vers les cœurs physiques est géré par l'hyperviseur ou l'OS :

  • 1:1 (pinning) : un vCPU est lie a un cœur physique. Performance maximale, pas de contention.
  • N:M (overcommit) : plus de vCPU que de cœurs physiques. Fonctionne quand les VM n'utilisent pas toutes leur CPU simultanément. Ratio typique : 2:1 a 4:1.

Tip

L'overcommit CPU est acceptable pour les charges intermittentes (serveurs web, API). Il est dangereux pour les charges CPU-bound constantes (bases de données, calcul). En cloud public, un vCPU AWS ou GCP est typiquement un hyper-thread — la moitie d'un cœur physique. Dimensionnez en conséquence.

vRAM

La mémoire virtuelle d'une VM est de la mémoire physique de l'hôte (sauf si swap). L'overcommit mémoire (allouer plus de vRAM que de RAM physique) est risque : si toutes les VM consomment leur allocation, l'hôte passe en swap ou tue des processus (OOM killer).


Technologies emergentes

Micro-VM

Les micro-VM (Firecracker, Cloud Hypervisor) sont des VM minimalistes qui démarrent en 125 ms et consomment 5 MB de mémoire. Elles offrent l'isolation d'une VM avec la densite d'un conteneur. AWS Lambda utilisé Firecracker en interne.

Unikernels

Les unikernels compilent l'application et les composants OS nécessaires en une seule image, sans noyau generaliste. Temps de boot en millisecondes, surface d'attaque minimale. Encore experimental pour la production.

WebAssembly (Wasm)

Wasm emerge comme une alternative aux conteneurs pour certaines charges : sandboxing fort, démarrage sub-milliseconde, portabilité. Encore immature pour les workloads serveur complexes, mais prometteur pour les edge functions et les plugins.


Choisir la bonne abstraction

Le choix entre VM, conteneur, micro-VM et bare-metal dépend du contexte. Voici un arbre de décision simplifie.

graph TD
    Q1{"Isolation forte<br>requise ?"} --oui--> Q2{"Latence de<br>demarrage critique ?"}
    Q1 --non--> Q3{"Densite<br>maximale ?"}
    Q2 --oui--> MICROVM["Micro-VM<br>(Firecracker)"]
    Q2 --non--> VM["VM classique<br>(KVM, VMware)"]
    Q3 --oui--> CONTAINER["Conteneur<br>(Docker, containerd)"]
    Q3 --non--> Q4{"Performance<br>I/O critique ?"}
    Q4 --oui--> BARE["Bare-metal<br>ou VM avec passthrough"]
    Q4 --non--> CONTAINER2["Conteneur"]

Cas d'usage par type d'abstraction

Abstraction Cas d'usage typique
Bare-metal Bases de données haute performance, HPC, trading
VM classique Multi-tenant, OS hétérogènes, legacy, compliance
Micro-VM FaaS (Lambda), sandboxing d'exécution non fiable
Conteneur Microservices, CI/CD, applications cloud-native
Unikernel Edge computing, IoT, cas très spécifiques

Coût opérationnel

L'overhead ne se mesure pas seulement en CPU et mémoire — le coût opérationnel compte aussi. Une VM nécessité un OS invite à patcher, surveiller et maintenir. Un conteneur partage le noyau de l'hôte mais ajoute la complexité de l'orchestration (Kubernetes). Le bare-metal élimine l'abstraction mais rend le provisioning et le scaling beaucoup plus lents.

En pratique, la majorité des organisations utilisent un mix : bare-metal ou VM pour les bases de données, conteneurs orchestres par Kubernetes pour les applications stateless, et micro-VM ou conteneurs pour les fonctions serverless.


Implications pour l'architecte

  1. Conteneurs pour les microservices, VM pour l'isolation forte : c'est la règle par défaut. Les conteneurs gagnent en densite et en vitesse de déploiement ; les VM gagnent en isolation. Les micro-VM combinent les deux pour le serverless.

  2. Dimensionner en connaissant l'overhead : un vCPU n'est pas un cœur physique. En cloud, prevoyez 20-30% de capacité supplémentaire par rapport à un benchmark bare-metal. Pour les charges I/O-intensive, verifiez l'overhead réseau et disque spécifiquement.

  3. Optimiser l'I/O d'abord : l'overhead CPU de la virtualisation est negligeable ; l'overhead I/O peut être significatif. Utilisez virtio (standard), SR-IOV (haute performance) ou le passthrough (performance maximale) selon les besoins.

  4. Micro-VM pour le serverless : si vous concevez une plateforme de functions-as-a-service, les micro-VM offrent le meilleur compromis isolation/densite/démarrage. AWS Lambda a prouve le modèle à l'échelle.

  5. Ne pas negliger la sécurité des conteneurs : un conteneur compromis sur un noyau partage est un risque pour tout l'hôte. Combinez les namespaces avec seccomp, AppArmor/SELinux, et des images minimales (distroless, scratch) pour réduire la surface d'attaque.


Chapitre suivant : Impact sur les choix d'architecture — comment les contraintes matérielles guident les décisions logicielles.