TD1 - Virtualisation & conteneurisation
Infrastructure de conteneurisation
{chroot & cgroup & namespace & OverlayFS}
Rappel : À tout moment, pour retrouver plus de détails sur les commandes et outils Linux, référez-vous aux pages du manuel à l'aide de l'instruction : man commande.
1. chroot
La commande chroot nous laisse isoler les programmes en changeant le répertoire racine, tout en gardant l'arborescence extérieure invisible.
Étape 1 : Créer un répertoire racine avec des sous-répertoires bin, lib et lib64.
mkdir -p racine/{bin,lib,lib64}
Étape 2 : On s'intéresse à utiliser les commandes bash, ls et kill. Copier les fichiers nécessaires afin de pouvoir utiliser ces commandes dans le chroot.
mylibs=$(ldd $(which ls) | cut -d' ' -f3)
cp $mylibs racine/lib
mylibs=$(ldd $(which kill) | cut -d' ' -f3)
cp $mylibs racine/lib
mylibs=$(ldd $(which bash) | cut -d' ' -f3)
cp $mylibs racine/lib
Étape 3 : Lancer chroot pour changer la racine vers le répertoire chroot déjà créé.
chroot racine bash
Étape 4 : Pour vérifier que l'encapsulation ne garantit pas la sécurité dans chroot, créer un processus sleep 500 dans le terminal principal, et essayer ensuite de le tuer dans votre session chroot.
2. cgroup
La configuration des cgroup se fait directement par manipulation des fichiers correspondants.
2.1 Processus
On va créer un groupe de contrôle qui va limiter le nombre de processus maximal :
Étape 1 : Créer un sous-groupe de contrôle :
mkdir /sys/fs/cgroup/pidsgrp
Étape 2 : Établir une limite de 5 processus :
echo 5 | tee /sys/fs/cgroup/pidsgrp/pids.max
Étape 3 : Associer la ligne de commande courante au groupe de contrôle déjà créé :
echo $$ | tee /sys/fs/cgroup/pidsgrp/cgroup.procs
more /proc/self/cgroup
Étape 4 : Essayer de lancer plus de 5 processus :
for i in $(seq 15); do sleep 100 & done
Télécharger la vidéo du bash&retry lors de la modif sur pids max
2.2 Mémoire
Contrôler l'utilisation mémoire d'un groupe s'effectue en manipulant le fichier memory.max dans le répertoire du cgroup en question :
Étape 1 : Créer un sous-groupe memgroup pour tester le contrôle de mémoire :
mkdir /sys/fs/cgroup/memgroup
Étape 2 : Changer la limite pour que notre nouveau cgroup ne dépasse pas 128MB d'utilisation mémoire :
echo 128M > /sys/fs/cgroup/memgroup/memory.max
Étape 3 : Associer un bash au cgroup déjà créé :
echo $$ > /sys/fs/cgroup/memgroup/cgroup.procs
Étape 4 : Lancer une commande qui va consommer 256MB de mémoire et surveiller son exécution à l'aide de la commande top :
yes | tr -d '\\n' | head -c 256M | pv | grep n
Étape 5 : Associer un autre bash au cgroup créé, et essayer de lancer un autre processus lourd en utilisation mémoire.
Innovation: (commande pas utilisée en cours)
stress --vm 1 --vm-bytes 256M --timeout 30s
La commande stress est utilisée pour générer une charge sur le système, en particulier sur la mémoire dans ce cas.
Explication des options :
- --vm 1 : Crée une tâche qui va consommer de la mémoire (une "virtual memory worker").
- --vm-bytes 256M : Alloue 256MB de mémoire à la tâche.
- --timeout 30s : Fait tourner cette tâche pendant 30 secondes, après quoi elle s'arrête automatiquement.
Cette commande permet de tester comment le système et les cgroups réagissent face à une forte demande de mémoire sur une période limitée, en consommant 256MB pendant 30 secondes.
Étape 6 : Quelles observations pourrait-on extraire en surveillant l'utilisation mémoire des deux processus ?
☠️ Télécharger la vidéo où le pc est en monde memory reboot
Étape 6 : Quelles observations pourrait-on extraire en surveillant l'utilisation mémoire des deux processus ?
En surveillant l'utilisation mémoire des deux processus à l'aide de top, voici les observations que l'on peut faire :
1. Respect de la limite mémoire : Les deux processus sont contraints par la limite de 128MB imposée par le cgroup. Même si un processus tente de consommer plus de mémoire, il sera restreint à la limite définie.
2. Répartition de la mémoire : Chaque processus consomme une partie de la mémoire disponible. Par exemple, le premier processus peut consommer environ 100MB tandis que le second utilise environ 25MB. Cela montre que la mémoire est bien partagée entre les processus.
3. Impact des dépassements de mémoire : Si un processus tente de consommer plus que la mémoire disponible dans le cgroup, il pourrait être stoppé ou rencontrer des erreurs. Cela peut provoquer des arrêts ou des ralentissements pour les autres processus dans le même cgroup.
4. Gestion efficace de la mémoire : Le cgroup s'assure que la limite mémoire est respectée, empêchant un processus de monopoliser les ressources. Cela permet de garantir une utilisation équilibrée de la mémoire entre les différents processus.
5. Ralentissements possibles : Si la limite est atteinte, les processus peuvent être ralentis, et tu pourrais observer une augmentation de l'utilisation du swap si le système tente de compenser la restriction mémoire.
En résumé, les processus sont bien limités à 128MB et la mémoire est partagée entre eux. Toute tentative de dépassement entraînerait un comportement inattendu, et la gestion de la mémoire est bien assurée par le cgroup.
2.3 Processeur
Contrôler l'utilisation CPU d'un groupe s'effectue en manipulant le fichier cpu.max dans le répertoire du cgroup en question :
Étape 1 : Créer un sous-groupe cpugroup pour tester le contrôle de l'utilisation du processeur :
mkdir /sys/fs/cgroup/cpugroup
Étape 2 : Changer la limite pour que notre nouveau cgroup ne dépasse pas 10% d'utilisation processeur :
echo 10000 > /sys/fs/cgroup/cpugroup/cpu.max
Étape 3 : Associer un bash au cgroup déjà créé :
echo $$ > /sys/fs/cgroup/cpugroup/cgroup.procs
Étape 4 : Lancer une commande qui va consommer le processeur et surveiller son exécution à l'aide de la commande top :
yes | pv
☠️ Télécharger la vidéo pour voir un processus à 10% max d'utilisation CPU
Étape 5 : Associer un autre bash au cgroup créé, et essayer de lancer un autre processus lourd en utilisation processeur.
☠️ Télécharger la vidéo pour voir un processus à 10% max d'utilisation CPUÉtape 6 : Quelles observations pourrait-on extraire en surveillant l'utilisation processeur des deux processus ?
Étape 7 : Tuer tous les processus appartenant aux cgroups créés :
echo 1 > /sys/fs/cgroup/memgroup/cgroup.kill
echo 1 > /sys/fs/cgroup/cpugroup/cgroup.kill
☠️ Télécharger la vidéo pour voir les deux processus killés ☠️
2.4 Entrée/Sortie
Étape 1 : Créer un nouveau cgroup pour limiter le débit de lecture et d'écriture sur un matériel donné :
mkdir /sys/fs/cgroup/iogroup
Étape 2 : Associer le terminal courant à ce cgroup :
echo $$ > /sys/fs/cgroup/iogroup/cgroup.procs
Étape 3 : Assurer que le I/O est activé pour le cgroup :
echo '+io' > /sys/fs/cgroup/iogroup/cgroup.subtree_control
Étape 4 : Retrouver le numéro majeur et mineur du disque dur :
more /proc/devices # ou ls -l /dev/nvme
Étape 5 : Limiter la vitesse de lecture à 1000KBps et 2000KBps pour écriture :
echo '259:0 rbps=1024000 wbps=2048000' > /sys/fs/cgroup/iogroup/io.max
Étape 6 : Tester cette configuration :
yes | pv > test
3. Namespace
Pour lancer une commande dans un nouvel espace de nom, on utilise la commande unshare. Dans la suite, on va apprendre son utilisation dans les exemples.
3.1 UTS
Cet espace de nom nous permet de redéfinir le nom d’hôte dans le sous-espace.
Étape 1 : Vérifier le nom d’hôte dans notre système :
hostname
Étape 2 : Créer un espace de nom UTS :
unshare -ur bash
Étape 3 : Changer le nom d’hôte dans l’espace de nom. Vérifier ensuite que le changement a eu lieu :
hostname nouveau_nom
hostname
Étape 4 : Dans un shell du système, vérifier que le nom d’hôte n’a pas changé :
hostname
3.2 PID
Pour créer un nouvel espace de nom pour les identifiants des processus, il suffit d’utiliser la commande suivante :
Étape 1 : Création de deux namespaces réseau :
unshare -pf --mount-proc=/proc -r bash
Ou bien, si on souhaite effectuer le montage à l’intérieur :
unshare -pf -m -r bash
mount -t proc proc /proc
Étape 2 : Lancer des processus à l’intérieur de notre nouvel espace de nom et vérifier ensuite les processus visibles :
3.3 Réseau
Dans cette partie, on va créer deux espaces de nom réseau, et on va les connecter par un réseau virtuel comme l'indique le schéma de la figure 1 :
Fig. 1 : Construction d'un réseau virtuel entre 2 espaces de noms.
Étape 1 : Création de deux namespaces réseau :
ip netns add espaceA
ip netns add espaceB
Étape 2 : Création d’une paire d’interfaces ethernet virtuel (veth) qu’on va utiliser pour connecter nos namespaces réseau. Et afficher ensuite la liste des interfaces disponibles :
ip link add vethA type veth peer name vethB
ip link list
Étape 3 : Affecter chacune des interfaces virtuelles créées aux namespaces correspondants :
ip link set vethA netns espaceA # ou bien fichier /proc/PID/ns/net
ip link set vethB netns espaceB
Pour consulter les interfaces réseaux depuis notre namespace espaceA, on utilise ip netns exec de la façon suivante :
ip netns exec espaceA ip link
Étape 4 : On va affecter des adresses IP aux interfaces veth à l'intérieur de chaque namespace en lançant les commandes suivantes :
ip netns exec espaceA ip addr add 192.168.0.1/24 dev vethA
ip netns exec espaceB ip addr add 192.168.0.2/24 dev vethB
Étape 5 : On va activer maintenant les interfaces virtuelles à l'intérieur de leurs espaces de nom :
ip netns exec espaceA ip link set vethA up
ip netns exec espaceB ip link set vethB up
Étape 6 : On ajoute ensuite les routes par défaut pour chaque espace de nom. Cela permet au système de savoir comment acheminer les paquets à n'importe quelle adresse IP :
ip netns exec espaceA ip route add default via 192.168.0.1 dev vethA
ip netns exec espaceB ip route add default via 192.168.0.2 dev vethB
Étape 7 : Enfin, on peut vérifier le bon fonctionnement en "pingant" à l'intérieur de espaceA :
ip netns exec espaceA ping 192.168.0.2
4. OverlayFS
Monter notre système de fichiers sur plusieurs couches afin de pouvoir réutiliser des informations précédentes. Les changements des couches plus hautes ne vont pas modifier les couches plus basses.
Étape 1 : Créer des répertoires représentant, par ordre, le répertoire contenant respectivement les informations de la couche inférieure, celles de la couche supérieure, le travail effectué et les informations manipulées par l'utilisateur directement :
mkdir -p overlay/{lower,upper,work,merged}
Note : Considérez à remplir lower par quelques fichiers pour pouvoir les manipuler dans les étapes suivantes.
Étape 2 : Ensuite, on doit monter le système de fichiers de type overlay en utilisant les répertoires déjà créés :
mount overlay -t overlay -o lowerdir=overlay/lower,\
upperdir=overlay/upper,workdir=overlay/work overlay/merged
Étape 3 : Effectuer des manipulations sur des fichiers dans le répertoire merged, et consulter les changements dans les répertoires originaux.