Chapitre 712 minIntermédiaire
Conteneurs LXC sous Proxmox : créer un CT, VM ou conteneur ?
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- expliquer comment un conteneur partage le noyau de l'hôte ;
- distinguer un conteneur privilégié d'un conteneur non privilégié ;
- créer un conteneur dans l'interface et avec
pct; - choisir entre une VM et un conteneur pour un service donné.
4 exercices corrigés
Un conteneur LXC est un système Linux isolé qui partage le noyau de l'hôte Proxmox au lieu d'avoir le sien : il démarre en une ou deux secondes, consomme quelques dizaines de mégaoctets de mémoire, et s'administre comme un petit serveur Debian ou Ubuntu. Proxmox VE l'appelle CT (container). Ce chapitre explique comment fonctionne un conteneur, la différence entre conteneur privilégié et non privilégié, la création d'un conteneur dans l'interface et avec pct, ses limites, et comment choisir entre une VM et un conteneur.
Comment fonctionne un conteneur LXC
LXC (Linux Containers) est un ensemble d'outils qui utilise trois mécanismes du noyau Linux :
- les namespaces donnent à chaque conteneur sa propre vue du système : ses processus (le premier processus du conteneur se croit numéro 1), ses interfaces réseau, ses points de montage, ses utilisateurs, son nom d'hôte ;
- les cgroups (groupes de contrôle) limitent ce que le conteneur consomme : nombre de cœurs, mémoire, espace de swap, débit disque ;
- AppArmor et un filtre d'appels système (seccomp) interdisent au conteneur les opérations dangereuses pour l'hôte, comme charger un module dans le noyau.
Il n'y a ni carte mère simulée, ni noyau à démarrer, ni pilotes : les processus du conteneur tournent directement sur le noyau de l'hôte, juste « dans une boîte ». D'où la légèreté, et d'où la principale limite : un conteneur ne peut faire tourner que Linux, avec le noyau de l'hôte (Linux 7.0 sous Proxmox VE 9.2), quelle que soit la distribution choisie.
Conteneur privilégié ou non privilégié
C'est le réglage de sécurité le plus important d'un conteneur.
| Non privilégié (unprivileged, par défaut) | Privilégié (privileged) | |
|---|---|---|
L'utilisateur root du conteneur est, sur l'hôte… | L'utilisateur sans droits 100000 | Le vrai root de l'hôte |
| Si un attaquant s'échappe du conteneur | Il n'a aucun droit sur l'hôte | Il a tous les droits sur l'hôte |
| Compatibilité | Quelques logiciels refusent (serveur NFS dans le conteneur, certains montages) | Tout fonctionne, ou presque |
| Recommandation | Toujours, sauf exception justifiée | Seulement pour un besoin précis, sur un hôte de test |
Dans un conteneur non privilégié, les identifiants sont décalés : l'utilisateur numéro 0 du conteneur (root) correspond à l'utilisateur 100000 de l'hôte, l'utilisateur 33 (www-data) à 100033, et ainsi de suite. C'est ce qui rend une évasion inoffensive. C'est aussi ce qui provoque des problèmes de droits quand on partage un dossier de l'hôte avec le conteneur (voir plus bas).
Les modèles de conteneurs
Un conteneur se crée à partir d'un modèle (template) : une archive qui contient un système de base déjà installé. Proxmox en propose pour Debian, Ubuntu, Alma Linux, Rocky Linux, Alpine, Fedora, Arch Linux et quelques applications toutes prêtes. Dans l'interface : sélectionne le stockage local, puis CT Templates > Templates, choisis le modèle et clique sur Download. En ligne de commande :
pveam update # met à jour la liste des modèles
pveam available --section system # liste les systèmes disponibles
pveam download local debian-13-standard_13.6-1_amd64.tar.zst
pveam list local # les modèles téléchargés
Les noms des modèles changent à chaque mise à jour du système (13.6-1 ici) : prends le nom exact affiché par pveam available.
Depuis Proxmox VE 9.1, un conteneur peut aussi être créé à partir d'une image OCI, le format des images Docker : le stockage de modèles sait récupérer une image depuis un registre comme Docker Hub. Pour les conteneurs système (Debian, Alpine…), c'est une autre source de modèles ; pour les conteneurs d'application, qui font tourner un seul programme, la fonction est encore un aperçu technologique. Pour une vraie plateforme Docker, avec Compose et des dizaines d'images, une VM Debian avec Docker reste la solution recommandée (cours Docker).
Créer un conteneur, onglet par onglet
Sorbier veut un petit serveur web interne, ct-horaires, qui affiche les horaires des tournées aux salariés. Un conteneur suffit. Clique sur Create CT.
| Onglet | Champ | Valeur | Explication |
|---|---|---|---|
| General | Node, CT ID, Hostname | pve1, 182, ct-horaires | Le CT ID partage la même numérotation que les VM |
| Unprivileged container | Coché | Le réglage par défaut, à garder | |
| Nesting | Coché (par défaut) | Nécessaire au bon fonctionnement de systemd dans les distributions récentes | |
| Password, SSH public key | Un mot de passe long, ta clé publique | Pour te connecter à root du conteneur | |
| Template | Storage, Template | local, debian-13-standard_13.6-1_amd64.tar.zst | Le modèle téléchargé |
| Disks | Storage, Disk size (GiB) | truenas-nfs, 8 | Le disque racine (rootfs) |
| CPU | Cores | 1 | |
| Memory | Memory (MiB), Swap (MiB) | 512, 512 | Un serveur web léger tient dans 512 Mio |
| Network | Name, Bridge, VLAN Tag | eth0, vmbr0, 21 | Le VLAN 21 APPLIS des applications internes |
| IPv4, IPv4/CIDR, Gateway | Static, 192.168.21.182/24, 192.168.21.254 | Contrairement à une VM, l'adresse se règle ici, et Proxmox l'écrit dans le conteneur | |
| DNS | DNS domain, DNS servers | ad.sorbier.example, 192.168.10.177 | |
| Confirm | Start after created | Coché |
Le conteneur démarre en deux secondes. Ouvre sa Console, connecte-toi en root, puis installe le serveur web :
apt update && apt full-upgrade
apt install nginx
systemctl status nginx
La même création, en une commande :
pct create 182 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst \
--hostname ct-horaires --unprivileged 1 --features nesting=1 \
--cores 1 --memory 512 --swap 512 \
--rootfs truenas-nfs:8 \
--net0 name=eth0,bridge=vmbr0,tag=21,ip=192.168.21.182/24,gw=192.168.21.254,firewall=1 \
--nameserver 192.168.10.177 --searchdomain ad.sorbier.example \
--ssh-public-keys /root/.ssh/id_ed25519.pub --onboot 1 --start 1
Administrer un conteneur
La configuration est dans /etc/pve/lxc/<CT ID>.conf :
arch: amd64
cores: 1
features: nesting=1
hostname: ct-horaires
memory: 512
nameserver: 192.168.10.177
net0: name=eth0,bridge=vmbr0,firewall=1,gw=192.168.21.254,hwaddr=BC:24:11:9D:41:6E,ip=192.168.21.182/24,tag=21,type=veth
onboot: 1
ostype: debian
rootfs: truenas-nfs:182/vm-182-disk-0.raw,size=8G
searchdomain: ad.sorbier.example
swap: 512
unprivileged: 1
Les commandes pct ressemblent à celles de qm :
| Commande | Effet |
|---|---|
pct list | Les conteneurs du nœud et leur état |
pct start 182, pct shutdown 182, pct stop 182 | Démarrer, arrêter proprement, couper |
pct enter 182 | Ouvre un shell root dans le conteneur, depuis l'hôte |
pct exec 182 -- systemctl restart nginx | Lance une commande dans le conteneur |
pct set 182 --memory 1024 | Change un réglage, souvent à chaud |
pct resize 182 rootfs +4G | Agrandit le disque racine (le système de fichiers suit automatiquement) |
pct snapshot 183 avant-maj | Prend un snapshot (ici de ct-tests, dont le disque est sur local-lvm) |
pct migrate 182 pve2 --restart | Déplace le conteneur sur pve2, en le redémarrant |
Partager un dossier de l'hôte se fait avec un point de montage (mount point) : pct set 182 --mp0 /srv/horaires,mp=/var/www/horaires monte le dossier /srv/horaires de l'hôte dans le conteneur. Dans un conteneur non privilégié, les fichiers doivent alors appartenir sur l'hôte aux identifiants décalés : pour que www-data (33) du conteneur puisse écrire, le dossier doit appartenir à l'utilisateur 100033 sur l'hôte (chown -R 100033:100033 /srv/horaires).
Les limites d'un conteneur
| Limite | Conséquence |
|---|---|
| Linux seulement, avec le noyau de l'hôte | Ni Windows, ni pfSense (FreeBSD), ni un noyau spécifique |
| Pas de migration à chaud | Le conteneur est arrêté puis redémarré sur l'autre nœud (--restart) : une coupure de quelques secondes |
| Pas de module noyau, accès limité au matériel | Un VPN WireGuard ou un pilote particulier doit être chargé sur l'hôte, ou dans une VM |
| Isolation plus faible qu'une VM | Pas de service exposé ou sensible en conteneur |
| Mises à jour du noyau | Le noyau du conteneur est celui de l'hôte : on met à jour l'hôte, pas le conteneur, pour les failles du noyau |
VM ou conteneur : comment choisir
| Question | Si oui |
|---|---|
| Le système est-il Windows, BSD (pfSense, OPNsense, TrueNAS CORE) ou une appliance ? | VM |
| Le service est-il exposé à Internet, ou gère-t-il la sécurité (journaux, sauvegardes, annuaire) ? | VM |
| Faut-il une migration à chaud sans coupure ? | VM |
| Faut-il Docker et plusieurs conteneurs d'application ? | VM avec Docker |
| Est-ce un service Linux léger et interne (web interne, DNS de laboratoire, outil d'équipe) ? | Conteneur |
| Faut-il beaucoup d'instances jetables pour des tests ? | Conteneur |
Exercices
Exercice 1 sur 4 Créer un conteneur de test Réussi À revoir
Écris la commande pct create d'un conteneur 183, ct-tests, à partir du modèle Debian 13, non privilégié, avec 2 cœurs, 1 024 Mio de mémoire, 512 Mio de swap, 10 Gio sur local-lvm, dans le VLAN 20 en DHCP. Explique pourquoi ce conteneur n'obtiendra peut-être pas d'adresse.
Voir la réponseMasquer la réponse de l'exercice 1
pct create 183 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst \
--hostname ct-tests --unprivileged 1 --features nesting=1 \
--cores 2 --memory 1024 --swap 512 \
--rootfs local-lvm:10 \
--net0 name=eth0,bridge=vmbr0,tag=20,ip=dhcp
Chez Sorbier, le VLAN 20 des serveurs n'a pas de DHCP : les serveurs ont des adresses fixes, et le DHCP de srv-ad ne distribue des adresses (par relais) que dans les VLAN des postes, de l'entrepôt, des visiteurs et de la téléphonie. Le conteneur n'aura donc pas d'adresse : il faut lui donner une adresse fixe libre du VLAN, après avoir vérifié le plan d'adressage.
Tu avais trouvé ?
Exercice 2 sur 4 Les identifiants décalés Réussi À revoir
Dans le conteneur non privilégié 182, Nginx tourne sous l'utilisateur www-data (UID 33) et root a l'UID 0. Le dossier de l'hôte /srv/horaires, monté dans le conteneur, appartient à root:root sur l'hôte.
- Sous quel UID les processus de
rootet dewww-datadu conteneur apparaissent-ils sur l'hôte ? - Pourquoi Nginx ne peut-il pas écrire dans le dossier monté ?
- Quelle commande, sur l'hôte, corrige le problème ?
Voir la réponseMasquer la réponse de l'exercice 2
- Décalage de 100 000 :
rootdu conteneur est 100000 sur l'hôte,www-dataest 100033. - Le dossier appartient au vrai
rootde l'hôte (UID 0). Pour le noyau,www-datadu conteneur est l'utilisateur 100033, qui n'a aucun droit sur ce dossier. chown -R 100033:100033 /srv/horairessur l'hôte : dans le conteneur, le dossier apparaît alors comme appartenant àwww-data.
Tu avais trouvé ?
Exercice 3 sur 4 Classer les services Réussi À revoir
Pour chaque service, choisis VM ou conteneur et justifie en une ligne : un pfSense de laboratoire ; un wiki interne de l'équipe informatique ; le serveur Wazuh qui collecte les alertes de sécurité ; un serveur DNS Unbound de laboratoire ; une application métier livrée sous forme de cinq conteneurs Docker avec Compose ; un serveur de fichiers Windows.
Voir la réponseMasquer la réponse de l'exercice 3
- pfSense : VM, c'est FreeBSD.
- Wiki interne : conteneur, service Linux léger et interne.
- Wazuh : VM, service de sécurité, cible des attaquants, gros consommateur de ressources.
- DNS de laboratoire : conteneur, très léger, jetable.
- Application en cinq conteneurs Docker : VM Debian avec Docker et Compose, la configuration recommandée.
- Serveur de fichiers Windows : VM, c'est Windows.
Tu avais trouvé ?
Exercice 4 sur 4 La migration qui coupe Réussi À revoir
Pendant une maintenance de pve1, un technicien migre tous les invités vers pve2. Les utilisateurs de ct-horaires signalent une coupure de quelques secondes, ceux de srv-gestion (une VM) aucune. Explique la différence.
Voir la réponseMasquer la réponse de l'exercice 4
Une VM se migre à chaud : sa mémoire est copiée pendant qu'elle tourne, puis elle bascule sur pve2 en une fraction de seconde. Un conteneur ne se migre pas à chaud sous Proxmox : pct migrate --restart l'arrête, le déplace et le redémarre sur pve2. La coupure dure le temps de l'arrêt et du démarrage, quelques secondes avec un disque sur stockage partagé.
Tu avais trouvé ?