Version : 2022.01

Dernière mise-à-jour :

DOF101 - La Virtualisation par Isolation

Contenu du Module

DOF101 - La Virtualisation par Isolation

Contenu du Module

Présentation de la Virtualisation par Isolation

Historique

Présentation des Namespaces

Présentation des CGroups

LAB #1 - Travailler avec les CGroups

1.1 - Limitation de la Mémoire

1.2 - Le Paquet cgroup-tools

La commande cgcreate

La Commande cgexec

La Commande cgdelete

Le Fichier /etc/cgconfig.conf

Présentation de Linux Containers

LAB #2 - Travailler avec LXC

2.1 - Installation

2.2 - Création d'un Conteneur Simple

2.3 - Démarrage d'un Conteneur Simple

2.4 - S'attacher à un Conteneur Simple

2.5 - Commandes LXC de Base

La Commande lxc-console

La Commande lxc-stop

La Commande lxc-execute

La Commande lxc-info

La Commande lxc-freeze

La Commande lxc-unfreeze

Autres commandes

2.6 - Création d'un Conteneur Non-Privilégié

User Namespaces

Création d'un Utilisateur Dédié

Création du Mappage

Création du Conteneur

Contrôle du Mappage

2.7 - Création d'un Conteneur Éphémère

La Commande lxc-copy

2.8 - Sauvegarde des Conteneurs

La Commande lxc-snapshot

Présentation de la Virtualisation par Isolation

Un isolateur est un logiciel qui permet d'isoler l'exécution des applications dans des containers, des contextes ou des zones d'exécution.

Historique

1979 - chroot - l'isolation par changement de racine,

2000 - BSD Jails - l'isolation en espace utilisateur,

2004 - Solaris Containers - l'isolation par zones,

2005 - OpenVZ - l'isolation par partitionnement du noyau sous Linux,

2008 - LXC - LinuX Containers - l'isolation en utilisant des namespaces et des CGroups avec liblxc,

2013 - Docker - l'isolation en utilisant des namespaces et des CGroups avec libcontainer,

2014 - LXD - LinuX Container Daemon - l'isolation en utilisant des namespaces et des CGroups avec liblxc.

Présentation des Namespaces

Les espaces de noms permettent de regrouper des processus dans un même espace et d'attribuer des droits sur des ressources par espace. Ceci permet l'exécution de plusieurs init, chacun dans un namespace, afin de recréer un environnement pour les processus qui doivent être isolés.

Présentation des CGroups

Les Groupes de Contrôles (Control Groups) aussi appelés CGroups, sont une nouvelle façon de contrôler et de limiter des ressources. Les groupes de contrôle permettent l'allocation de ressources, même d'une manière dynamique pendant que le système fonctionne, telles le temps processeur, la mémoire système, la bande réseau, ou une combinaison de ces ressources parmi des groupes de tâches (processus) définis par l'utilisateur et exécutés sur un système.

Les CGroups sont organisés de manière hiérarchique, comme des processus. Par contre, la comparaison entre les deux démontre que tandis que les processus se trouvent dans une arborescence unique descendant tous du processus init et héritant de l'environnement de leurs parents, les CGroups peuvent être multiples donnant lieu à des arborescences ou hiérarchies multiples qui héritent de certains attributs de leurs groupes de contrôle parents.

Ces hiérarchies multiples et séparés sont necéssaires parce que chaque hiérarchie est attaché à un ou plusieurs sous-système(s) aussi appelés des Contrôleurs de Ressources ou simplement des Contrôleurs. Les contrôleurs disponibles sont :

blkio - utilisé pour établir des limites sur l'accès des entrées/sorties à partir et depuis des périphériques blocs,

cpu - utilisé pour fournir aux tâches des groupes de contrôle accès au CPU grâce au planificateur,

cpuacct - utilisé pour produire des rapports automatiques sur les ressources CPU utilisées par les tâches dans un groupe de contrôle,

cpuset - utilisé pour assigner des CPU individuels sur un système multicœur et des nœuds de mémoire à des tâches dans un groupe de contrôle,

devices - utilisé pour autoriser ou pour refuser l'accès des tâches aux périphériques dans un groupe de contrôle,

freezer - utilisé pour suspendre ou pour réactiver les tâches dans un groupe de contrôle,

memory - utilisé pour établir les limites d'utilisation de la mémoire par les tâches d'un groupe de contrôle et pour génèrer des rapports automatiques sur les ressources mémoire utilisées par ces tâches,

net_cls - utilisé pour repérer les paquets réseau avec un identifiant de classe (classid) afin de permettre au contrôleur de trafic Linux, tc, d'identifier les paquets provenant d'une tâche particulière d'un groupe de contrôle.

perf_event - utilisé pour permettre le monitoring des CGroups avec l'outil perf,

hugetlb - utilisé pour limiter des ressources sur des pages de mémoire virtuelle de grande taille.

Les hiérarchies ont des points de montage dans le répertoire /sys/fs/cgroup :

trainee@debian9:~$ su -
Mot de passe : fenestros
root@debian9:~# ls -l /sys/fs/cgroup/
total 0
dr-xr-xr-x 2 root root 0 mai 26 08:52 blkio
lrwxrwxrwx 1 root root 11 mai 26 08:52 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 mai 26 08:52 cpuacct -> cpu,cpuacct
dr-xr-xr-x 2 root root 0 mai 26 08:52 cpu,cpuacct
dr-xr-xr-x 2 root root 0 mai 26 08:52 cpuset
dr-xr-xr-x 5 root root 0 mai 26 08:52 devices
dr-xr-xr-x 2 root root 0 mai 26 08:52 freezer
dr-xr-xr-x 2 root root 0 mai 26 08:52 memory
lrwxrwxrwx 1 root root 16 mai 26 08:52 net_cls -> net_cls,net_prio
dr-xr-xr-x 2 root root 0 mai 26 08:52 net_cls,net_prio
lrwxrwxrwx 1 root root 16 mai 26 08:52 net_prio -> net_cls,net_prio
dr-xr-xr-x 2 root root 0 mai 26 08:52 perf_event
dr-xr-xr-x 5 root root 0 mai 26 08:52 pids
dr-xr-xr-x 5 root root 0 mai 26 08:52 systemd

Systemd organise les processus dans chaque CGroup. Par exemple tous les processus démarrés par le serveur Apache se trouveront dans le même CGroup, y compris les scripts CGI. Ceci implique que la gestion des ressources en utilisant des hiérarchies est couplé avec l'arborescence des unités de Systemd.

En haut de l'arborescence des unités de Systemd se trouve la tranche root - -.slice, dont dépend :

le system.slice - l'emplacement des services système,

le user.slice - l'emplacement des sessions des utilisateurs,

le machine.slice - l'emplacement des machines virtuelles et conteneurs.

En dessous des tranches peuvent se trouver :

des scopes - des processus crées par fork,

des services - des processus créés par une Unité.

Les slices peuvent être visualisés avec la commande suivante :

root@debian9:~# systemctl list-units --type=slice
UNIT LOAD ACTIVE SUB DESCRIPTION
-.slice loaded active active Root Slice
system-getty.slice loaded active active system-getty.slice
system.slice loaded active active System Slice
user-1000.slice loaded active active User Slice of trainee
user-112.slice loaded active active User Slice of lightdm
user.slice loaded active active User and Session Slice
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
6 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

L'arborescence des unités de Systemd est la suivante :

root@debian9:~# systemd-cgls
Control group /:
-.slice
├─user.slice
│ ├─user-112.slice
│ │ ├─user@112.service
│ │ │ ├─dbus.service
│ │ │ │ └─539 /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
│ │ │ ├─init.scope
│ │ │ │ ├─527 /lib/systemd/systemd --user
│ │ │ │ └─528 (sd-pam)
│ │ │ └─gvfs-daemon.service
│ │ │ └─547 /usr/lib/gvfs/gvfsd
│ │ └─session-c1.scope
│ │ ├─524 lightdm --session-child 18 21
│ │ ├─532 /usr/sbin/lightdm-gtk-greeter
│ │ ├─534 /usr/lib/at-spi2-core/at-spi-bus-launcher --launch-immediately
│ │ ├─541 /usr/bin/dbus-daemon --config-file=/usr/share/defaults/at-spi2/accessibility.conf --nofork --print-address 3
│ │ └─543 /usr/lib/at-spi2-core/at-spi2-registryd --use-gnome-session
│ └─user-1000.slice
│ ├─session-2.scope
│ │ ├─668 sshd: trainee [priv]
│ │ ├─679 sshd: trainee@pts/0
│ │ ├─680 -bash
│ │ ├─689 su -
│ │ ├─690 -su
│ │ ├─708 systemd-cgls
│ │ └─709 systemd-cgls
│ └─user@1000.service
│ └─init.scope
│ ├─670 /lib/systemd/systemd --user
│ └─671 (sd-pam)
├─init.scope
│ └─1 /sbin/init
└─system.slice
├─lightdm.service
│ ├─410 /usr/sbin/lightdm
│ ├─425 /usr/lib/xorg/Xorg :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
│ └─588 lightdm --session-child 14 21
├─anacron.service
lines 1-39

En utilisant Systemd, plusieurs ressources peuvent être limitées :

CPUShares - par défaut 1024,

MemoryLimit - limite exprimée en Mo ou en Go. Pas de valeur par défaut,

BlockIOWeight - valeur entre 10 et 1000. Pas de valeur par défaut,

StartupCPUShares - comme CPUShares mais uniquement appliqué pendant le démarrage,

StartupBlockIOWeight - comme BlockIOWeight mais uniquement appliqué pendant le démarrage,

CPUQuota - utilisé pour limiter le temps CPU, même quand le système ne fait rien.

Important : Consultez le manuel systemd.resource-control(5) pour voir les paramètres CGroup qui peuvent être passés à systemctl.

LAB #1 - Travailler avec les CGroups

1.1 - Limitation de la Mémoire

Pour travailler avec les CGroups dans Debian 9, il convient d'installer les outils nécessaires :

root@debian9:~# apt-get install libcgroup1 cgroup-tools

Commencez ensuite par créer le script hello-world.sh qui servira à générer un processus pour travailler avec les CGroups :

root@debian9:~# vi hello-world.sh
root@debian9:~# cat hello-world.sh
#!/bin/bash
while [ 1 ]; do
echo "hello world"
sleep 60
done

Rendez le script exécutable et testez-le :

root@debian9:~# chmod u+x hello-world.sh
root@debian9:~# ./hello-world.sh
hello world
hello world
^C

Créez maintenant un CGroup dans le sous-système memory appelé helloworld :

root@debian9:~# mkdir /sys/fs/cgroup/memory/helloworld

Par défaut, ce CGroup héritera de l'ensemble de la mémoire disponible. Pour éviter cela, créez maintenant une limite de 40000000 octets pour ce CGroup :

root@debian9:~# echo 40000000 > /sys/fs/cgroup/memory/helloworld/memory.limit_in_bytes
root@debian9:~# cat /sys/fs/cgroup/memory/helloworld/memory.limit_in_bytes
39997440

Important - Notez que les 40 000 000 demandés sont devenus 39 997 440 ce qui correspond à un nombre entier de pages mémoire du noyau de 4Ko. ( 39 997 440 / 4096 = 9 765 ).

Lancez maintenant le script helloworld.sh :

root@debian9:~# ./hello-world.sh &
[1] 1012
root@debian9:~# hello world
root@debian9:~# ps aux | grep hello-world
root 1012 0.0 0.1 11172 2868 pts/0 S 10:24 0:00 /bin/bash ./hello-world.sh
root 1015 0.0 0.0 12784 968 pts/0 S+ 10:25 0:00 grep hello-world

Notez l'héritage par défaut :

root@debian9:~# ps -ww -o cgroup 1012
CGROUP
6:devices:/user.slice,3:pids:/user.slice/user-1000.slice/session-2.scope,1:name=systemd:/user.slice/user-1000.slice/session-2.scope

Insérer le PID de notre script dans le CGroup helloworld :

root@debian9:~# echo 1012 > /sys/fs/cgroup/memory/helloworld/cgroup.procs

Notez maintenant l'héritage de la limitation de la mémoire - 2:memory:/helloworld :

root@debian9:~# ps -ww -o cgroup 1012
CGROUP
6:devices:/user.slice,3:pids:/user.slice/user-1000.slice/session-2.scope,2:memory:/helloworld,1:name=systemd:/user.slice/user-1000.slice/session-2.scope

Constatez ensuite l'occupation mémoire réelle :

root@debian9:~# cat /sys/fs/cgroup/memory/helloworld/memory.usage_in_bytes
319488

Tuez le script hello-world.sh :

root@debian9:~# kill 1012
root@debian9:~# ps aux | grep hello-world
root 1038 0.0 0.0 12784 936 pts/0 S+ 10:33 0:00 grep hello-world
[1]+ Complété ./hello-world.sh

Créez un second CGroup beaucoup plus restrictif :

root@debian9:~# mkdir /sys/fs/cgroup/memory/helloworld1
root@debian9:~# echo 6000 > /sys/fs/cgroup/memory/helloworld1/memory.limit_in_bytes
root@debian9:~# cat /sys/fs/cgroup/memory/helloworld1/memory.limit_in_bytes
4096

Relancez le script hello-world.sh et insérez-le dans le nouveau CGroup :

root@debian9:~# ./hello-world.sh &
[1] 1042
root@debian9:~# hello world
root@debian9:~# echo 1042 > /sys/fs/cgroup/memory/helloworld1/cgroup.procs

Attendez la prochaine sortie de hello world sur le canal standard puis constatez que le script s'arrête :

root@debian9:~# hello world
[1]+ Processus arrêté ./hello-world.sh

Consultez en suite la fin du fichier /var/log/messages :

root@debian9:~# tail /var/log/messages
Jul 28 10:39:26 debian9 kernel: [ 1501.775169] [<ffffffffabe6253d>] ? __do_page_fault+0x4bd/0x4f0
Jul 28 10:39:26 debian9 kernel: [ 1501.775171] [<ffffffffabfc2950>] ? SyS_brk+0x160/0x180
Jul 28 10:39:26 debian9 kernel: [ 1501.775175] [<ffffffffac41a358>] ? page_fault+0x28/0x30
Jul 28 10:39:26 debian9 kernel: [ 1501.775176] Task in /helloworld1 killed as a result of limit of /helloworld1
Jul 28 10:39:26 debian9 kernel: [ 1501.775180] memory: usage 4kB, limit 4kB, failcnt 17
Jul 28 10:39:26 debian9 kernel: [ 1501.775180] memory+swap: usage 0kB, limit 9007199254740988kB, failcnt 0
Jul 28 10:39:26 debian9 kernel: [ 1501.775181] kmem: usage 0kB, limit 9007199254740988kB, failcnt 0
Jul 28 10:39:26 debian9 kernel: [ 1501.775181] Memory cgroup stats for /helloworld1: cache:0KB rss:4KB rss_huge:0KB mapped_file:0KB dirty:0KB writeback:0KB inactive_anon:0KB active_anon:0KB inactive_file:0KB active_file:0KB unevictable:0KB
Jul 28 10:39:26 debian9 kernel: [ 1501.775188] [ pid ] uid tgid total_vm rss nr_ptes nr_pmds swapents oom_score_adj name
Jul 28 10:39:26 debian9 kernel: [ 1501.775219] [ 1042] 0 1042 2795 732 10 3 0 0 hello-world.sh

Important - Notez la trace Task in /helloworld1 killed as a result of limit of /helloworld1.

1.2 - Le Paquet cgroup-tools

Le paquet cgroup-tools installe des commandes dites de facilité dont :

La commande cgcreate

Cette commande permet la création d'un CGroup :

root@debian9:~# cgcreate -g memory:helloworld2
root@debian9:~# ls -l /sys/fs/cgroup/memory/helloworld2/
total 0
-rw-r--r-- 1 root root 0 juil. 28 11:09 cgroup.clone_children
--w--w--w- 1 root root 0 juil. 28 11:09 cgroup.event_control
-rw-r--r-- 1 root root 0 juil. 28 11:09 cgroup.procs
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.failcnt
--w------- 1 root root 0 juil. 28 11:09 memory.force_empty
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 juil. 28 11:09 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.kmem.tcp.failcnt
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 juil. 28 11:09 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 juil. 28 11:09 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 juil. 28 11:09 memory.numa_stat
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.oom_control
---------- 1 root root 0 juil. 28 11:09 memory.pressure_level
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 juil. 28 11:09 memory.stat
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.swappiness
-r--r--r-- 1 root root 0 juil. 28 11:09 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 11:09 memory.use_hierarchy
-rw-r--r-- 1 root root 0 juil. 28 11:09 notify_on_release
-rw-r--r-- 1 root root 0 juil. 28 11:09 tasks

Il n'existe cependant pas de commande pour affecter une limitation de la mémoire :

root@debian9:~# echo 40000000 > /sys/fs/cgroup/memory/helloworld2/memory.limit_in_bytes

La Commande cgexec

Cette commande permet d'insérer la limitation dans le CGroup et de lancer le script en une seule ligne :

root@debian9:~# cgexec -g memory:helloworld2 ./hello-world.sh &
[2] 1860
root@debian9:~# hello world
root@debian9:~#

La Commande cgdelete

Une fois le script terminé, cette commande permet de supprimer le cgroup :

root@debian9:~# ps aux | grep *.sh
root 1073 0.0 0.1 11172 2868 pts/0 S 11:18 0:00 /bin/bash ./hello-world.sh
root 1076 0.0 0.0 528 4 pts/0 R+ 11:18 0:00 grep hello-world.sh
root@debian9:~# kill 1073
root@debian9:~# ps aux | grep *.sh
root 1078 0.0 0.0 12784 920 pts/0 S+ 11:18 0:00 grep hello-world.sh
[1]+ Complété cgexec -g memory:helloworld2 ./hello-world.sh
root@debian9:~# cgdelete memory:helloworld2
root@debian9:~# ls -l /sys/fs/cgroup/memory/helloworld2/
ls: impossible d'accéder à '/sys/fs/cgroup/memory/helloworld2/': Aucun fichier ou dossier de ce type

Le Fichier /etc/cgconfig.conf

Afin de les rendre persistants, il convient de créer les CGroups dans le fichier /etc/cgconfig.conf :

root@debian9:~# vi /etc/cgconfig.conf
root@debian9:~# cat /etc/cgconfig.conf
group helloworld2 {
cpu {
cpu.shares = 100;
}
memory {
memory.limit_in_bytes = 40000;
}
}

Important - Notez la création de deux limitations, une de 40 000 octets de mémoire et l'autre de 100 cpu.shares. Cette dernière est une valeur exprimée sur 1 024, où 1 024 représente 100% du temps CPU. La limite fixée est donc equivalente à 9,77% du temps CPU.

Créez donc les deux CGroups concernés :

root@debian9:~# cgcreate -g memory:helloworld2
root@debian9:~# ls -l /sys/fs/cgroup/memory/helloworld2/
total 0
-rw-r--r-- 1 root root 0 juil. 28 12:47 cgroup.clone_children
--w--w--w- 1 root root 0 juil. 28 12:47 cgroup.event_control
-rw-r--r-- 1 root root 0 juil. 28 12:47 cgroup.procs
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.failcnt
--w------- 1 root root 0 juil. 28 12:47 memory.force_empty
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 juil. 28 12:47 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.kmem.tcp.failcnt
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 juil. 28 12:47 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 juil. 28 12:47 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 juil. 28 12:47 memory.numa_stat
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.oom_control
---------- 1 root root 0 juil. 28 12:47 memory.pressure_level
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 juil. 28 12:47 memory.stat
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.swappiness
-r--r--r-- 1 root root 0 juil. 28 12:47 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 juil. 28 12:47 memory.use_hierarchy
-rw-r--r-- 1 root root 0 juil. 28 12:47 notify_on_release
-rw-r--r-- 1 root root 0 juil. 28 12:47 tasks

root@debian9:~# cgcreate -g cpu:helloworld2
root@debian9:~# ls -l /sys/fs/cgroup/cpu/helloworld2/
total 0
-rw-r--r-- 1 root root 0 juil. 28 12:48 cgroup.clone_children
-rw-r--r-- 1 root root 0 juil. 28 12:48 cgroup.procs
-r--r--r-- 1 root root 0 juil. 28 12:48 cpuacct.stat
-rw-r--r-- 1 root root 0 juil. 28 12:48 cpuacct.usage
-r--r--r-- 1 root root 0 juil. 28 12:48 cpuacct.usage_all
-r--r--r-- 1 root root 0 juil. 28 12:48 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 juil. 28 12:48 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 juil. 28 12:48 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 juil. 28 12:48 cpuacct.usage_sys
-r--r--r-- 1 root root 0 juil. 28 12:48 cpuacct.usage_user
-rw-r--r-- 1 root root 0 juil. 28 12:48 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 juil. 28 12:48 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 juil. 28 12:48 cpu.shares
-r--r--r-- 1 root root 0 juil. 28 12:48 cpu.stat
-rw-r--r-- 1 root root 0 juil. 28 12:48 notify_on_release
-rw-r--r-- 1 root root 0 juil. 28 12:48 tasks

Appliquez le contenu du fichier /etc/cgconfig.conf grâce à l'utilisation de la commande cgconfigparser :

root@debian9:~# cgconfigparser -l /etc/cgconfig.conf
root@debian9:~# cat /sys/fs/cgroup/memory/helloworld2/memory.limit_in_bytes
36864
root@debian9:~# cat /sys/fs/cgroup/cpu/helloworld2/cpu.shares
100

Présentation de Linux Containers

LAB #2 - Travailler avec LXC

2.1 - Installation

Les outils indispensables à l'utilisation des Linux Containers sous Debian sont inclus dans le paquet lxc :

root@debian9:~# apt update
root@debian9:~# apt install lxc

L'installation de ce paquet va créer les répertoires /usr/share/lxc/config contenant les fichiers de configurations des gabarits ainsi que le répertoire /usr/share/lxc/templates contenant fichiers de gabarits pour la création des conteneurs :

root@debian9:~# ls /usr/share/lxc
config	hooks lxc.functions lxc-patch.py __pycache__ selinux templates
root@debian9:~# ls /usr/share/lxc/config
alpine.common.conf centos.userns.conf debian.userns.conf	gentoo.userns.conf	oracle.common.conf	slackware.userns.conf	ubuntu-cloud.userns.conf
alpine.userns.conf common.conf	fedora.common.conf	nesting.conf	oracle.userns.conf	sparclinux.common.conf	ubuntu.common.conf
archlinux.common.conf common.conf.d	fedora.userns.conf	opensuse.common.conf plamo.common.conf	sparclinux.userns.conf	ubuntu.lucid.conf
archlinux.userns.conf common.seccomp	gentoo.common.conf	opensuse.userns.conf plamo.userns.conf	ubuntu-cloud.common.conf ubuntu.userns.conf
centos.common.conf debian.common.conf gentoo.moresecure.conf openwrt.common.conf	slackware.common.conf	ubuntu-cloud.lucid.conf userns.conf
root@debian9:~# ls /usr/share/lxc/templates
lxc-alpine lxc-archlinux lxc-centos lxc-debian lxc-fedora lxc-openmandriva lxc-oracle lxc-slackware	lxc-sshd lxc-ubuntu-cloud
lxc-altlinux lxc-busybox lxc-cirros lxc-download lxc-gentoo lxc-opensuse lxc-plamo	lxc-sparclinux lxc-ubuntu

2.2 - Création d'un Conteneur Simple

Créez un conteneur simple en utilisant la commande suivante :

root@debian9:~# lxc-create -n lxc-bb -t busybox
chmod: impossible d'accéder à '/var/lib/lxc/lxc-bb/rootfs/bin/passwd': Aucun fichier ou dossier de ce type
setting root password to "root"
Failed to change root password

Important - Notez l'utilisation de l'option -n qui permet d'associer un nom au conteneur ainsi que l'option -t qui indique le gabarit à utiliser. Notez aussi que le gabarit est référencé par le nom du fichier dans le répertoire /usr/share/lxc/templates sans son préfix lxc-.

Le backingstore ( méthode de stockage) utilisé par défaut est dir ce qui implique que le rootfs du conteneur se trouve sur disque dans le répertoire /var/lib/lxc/ :

root@debian9:~# ls /var/lib/lxc/
lxc-bb
root@debian9:~# ls /var/lib/lxc/lxc-bb/
config	rootfs
root@debian9:~# ls /var/lib/lxc/lxc-bb/rootfs
bin dev etc home lib lib64 mnt proc root sbin	selinux sys tmp usr	var

Il est à noter que LXC peut également utiliser des backingstores de type :

ZFS

Brtfs

LVM

Loop

rbd (CephFS)

2.3 - Démarrage d'un Conteneur Simple

Pour démarrer le conteneur, il convient d'utiliser la commande lxc-start :

root@debian9:~# lxc-start --name lxc-bb

2.4 - S'attacher à un Conteneur Simple

Pour s'attacher au conteneur démarré, il convient d'utiliser la commande lxc-attach :

root@debian9:~# lxc-attach --name lxc-bb
BusyBox v1.22.1 (Debian 1:1.22.0-19+b3) built-in shell (ash)
Enter 'help' for a list of built-in commands.
~ # passwd
/bin/sh: passwd: not found
~ # which passwd
~ #

Important - Notez l'absence de la commande passwd dans le conteneur, ce qui explique l'erreur lors de la création de celui-ci.

Pour sortir du conteneur, il convient d'utiliser la commande exit ou bien la combinaison de touches <Ctrl+d> :

~ # [Ctrl+d]
~ # root@debian9:~#

Le fait de sortir du conteneur ne l'arrête pas pour autant, comme il peut être constaté par l'utilisation de la commande lxc-ls :

~ # root@debian9:~# [Entrée]
root@debian9:~# lxc-ls --running
lxc-bb
root@debian9:~# lxc-ls -f --running
NAME STATE AUTOSTART GROUPS IPV4 IPV6
lxc-bb RUNNING 0 - - -

2.5 - Commandes LXC de Base

La Commande lxc-console

Pour lancer une console attachée à un TTY dans le conteneur, il convient d'utiliser la commande lxc-console :

root@debian9:~# lxc-console --name lxc-bb
Connected to tty 1
Type <Ctrl+a q> to exit the console, <Ctrl+a Ctrl+a> to enter Ctrl+a itself
lxc-bb login: root
Password:
Login incorrect
lxc-bb login: trainee
Password:
Login incorrect
lxc-bb login:

Important - Notez que pour des raisons évidentes, le conteneur BusyBox ne sait pas gérer de logins.

Pour sortir de la console, il faut utiliser la combinaison de touches <Ctrl+a> <q> :

lxc-bb login: [Ctrl+a] [q] root@debian9:~#

La Commande lxc-stop

Pour arrêter le conteneur, utilisez la commande lxc-stop :

root@debian9:~# lxc-ls --running
lxc-bb
root@debian9:~# lxc-stop --name lxc-bb
root@debian9:~# lxc-ls --running
root@debian9:~#

La Commande lxc-execute

La commande lxc-execute démarre un conteneur (qui doit être créé mais arrêté), exécute la commande passée en argument grâce aux caractères – puis arrête le conteneur :

root@debian9:~# lxc-execute -n lxc-bb -- uname -a
init.lxc.static: initutils.c: mount_fs: 36 failed to mount /proc : Device or resource busy
Linux lxc-bb 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 GNU/Linux
root@debian9:~# lxc-ls --running
root@debian9:~#

La Commande lxc-info

Cette commande donne des informations sur un conteneur :

root@debian9:~# lxc-info -n lxc-bb
Name: lxc-bb
State: STOPPED

La Commande lxc-freeze

La commande lxc-freeze met en pause tous les processus du conteneur :

root@debian9:~# lxc-start -n lxc-bb
root@debian9:~# lxc-ls --running
lxc-bb
root@debian9:~# lxc-info -n lxc-bb
Name: lxc-bb
State: RUNNING
PID: 3906
CPU use: 0.00 seconds
BlkIO use: 0 bytes
Memory use: 664.00 KiB
KMem use: 340.00 KiB
root@debian9:~# lxc-freeze -n lxc-bb
root@debian9:~# lxc-info -n lxc-bb
Name: lxc-bb
State: FROZEN
PID: 3906
CPU use: 0.00 seconds
BlkIO use: 0 bytes
Memory use: 664.00 KiB
KMem use: 340.00 KiB

La Commande lxc-unfreeze

La commande lxc-unfreeze annule l'effet d'une commande lxc-freeze précédente :

root@debian9:~# lxc-unfreeze -n lxc-bb
root@debian9:~# lxc-info -n lxc-bb
Name: lxc-bb
State: RUNNING
PID: 3906
CPU use: 0.00 seconds
BlkIO use: 0 bytes
Memory use: 664.00 KiB
KMem use: 340.00 KiB

Autres Commandes

Les autres commandes dont il faut avoir une connaissance sont :

Commande	Description
lxc-destroy	Permet de détruire complètement un conteneur
lxc-autostart	Permet de rebooter, tuer ou arrêter les conteneurs dont le drapeau lxc.start.auto est fixé dans le fichier /var/lib/<nom_conteneur>/config
lxc-cgroup	Permet de manipuler à chaud les CGroups pour un conteneur donné
lxc-device	Permet de rajouter à chaud les devices à un conteneur
lxc-usernsexec	Permet d'exécuter des commandes en tant que root dans un conteneur non-privilégié
lxc-wait	Permet d'attendre à ce qu'un conteneur ait atteint un certain état avant de continuer

2.6 - Création d'un Conteneur Non-Privilégié

User Namespaces

Un conteneur privilégié est un conteneur lancé par l'utilisateur root tandis qu'un conteneur non-privilégié est lancé par un utilisateur autre que root. Un conteneur privilégié est moins sécurisé qu'un conteneur non-privilégié mais ne nécessite pas la gestion du mappage d'UID.

Le mappage d'UID est une fonctionnalité du noyau Linux appelée user namespaces ou encore userns. Cette fonctionnalité permet de mapper une plage d'UID de la machine hôte vers un utilisateur dont l'UID est 0 dans un autre espace de noms.

Création d'un Utilisateur Dédié

Commencez par créer l’utilisateur lxcnp dédié à la gestion des conteneurs non-privilégiés :

root@debian9:~# useradd -c "Utilisateur LXC Non-Priviligié" -s /bin/bash -m lxcnp
root@debian9:~# passwd lxcnp
Entrez le nouveau mot de passe UNIX : trainee
Retapez le nouveau mot de passe UNIX : trainee
passwd: password updated successfully

Les informations concernant le mappage des UID et GID se trouvent dans les fichiers /etc/subuid et /etc/subgid :

root@debian9:~# grep lxcnp /etc/sub{uid,gid}
/etc/subuid:lxcnp:165536:65536
/etc/subgid:lxcnp:165536:65536

Important - Ces informations indiquent que nous avons 65 536 UID et 65 536 GID disponibles pour le mappage vers l'UID et le GID 165 536.

Création du Mappage

La valeur de kernel.unprivileged_userns_clone doit être 1, or actuellement elle est de 0 :

root@debian9:~# cat /proc/sys/kernel/unprivileged_userns_clone
0

Fixez donc la valeur à 1 et appliquez la modification avec la commande sysctl –system :

root@debian9:~# echo "kernel.unprivileged_userns_clone=1" > /etc/sysctl.d/80-lxc-userns.conf
root@debian9:~# cat /etc/sysctl.d/80-lxc-userns.conf
kernel.unprivileged_userns_clone=1
root@debian9:~# sysctl --system
* Applying /etc/sysctl.d/80-lxc-userns.conf ...
kernel.unprivileged_userns_clone = 1
* Applying /etc/sysctl.d/99-sysctl.conf ...
* Applying /etc/sysctl.conf ...

Connectez-vous ensuite en tant que l'utilisateur lxcnp :

root@debian9:~# su - lxcnp
lxcnp@debian9:~$

Créez le répertoire ~/.config/lxc :

lxcnp@debian9:~$ mkdir -p ~/.config/lxc

Créez trois entrées dans le fichier ~/.config/lxc/default.conf afin d'y inclure la configuration du fichier /etc/lxc/default.conf et mapper l'UID et le GID :

lxcnp@debian9:~$ echo "lxc.include = /etc/lxc/default.conf" >> ~/.config/lxc/default.conf
lxcnp@debian9:~$ echo "lxc.id_map = u 0 165536 65536" >> ~/.config/lxc/default.conf
lxcnp@debian9:~$ echo "lxc.id_map = g 0 165536 65536" >> ~/.config/lxc/default.conf
lxcnp@debian9:~$ cat ~/.config/lxc/default.conf
lxc.include = /etc/lxc/default.conf
lxc.id_map = u 0 165536 65536
lxc.id_map = g 0 165536 65536

Déconnectez-vous et reconnectez-vous en tant que l'utilisateur lxcnp :

lxcnp@debian9:~$ exit
déconnexion
root@debian9:~# su - lxcnp
lxcnp@debian9:~$

Création du Conteneur

Créez maintenant un conteneur non-privilégié appelé lxc-bb-np à partir du gabarit busybox :

lxcnp@debian9:~$ lxc-create -n lxc-bb-np -t busybox
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
chmod: impossible d'accéder à '/home/lxcnp/.local/share/lxc/lxc-bb-np/rootfs/bin/passwd': Aucun fichier ou dossier de ce type
setting root password to "root"
Failed to change root password
lxcnp@debian9:~$ ls -l /home/lxcnp/.local/share/lxc/lxc-bb-np/rootfs/
total 60
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 bin
drwxr-xr-x 4 165536 165536 4096 juil. 29 13:11 dev
drwxr-xr-x 3 165536 165536 4096 juil. 29 13:11 etc
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 home
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 lib
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 lib64
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 mnt
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 proc
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 root
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 sbin
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 selinux
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 sys
drwxr-xr-x 2 165536 165536 4096 juil. 29 13:11 tmp
drwxr-xr-x 7 165536 165536 4096 juil. 29 13:11 usr
drwxr-xr-x 3 165536 165536 4096 juil. 29 13:11 var

Contrôle du Mappage

Démarrez le conteneur :

lxcnp@debian9:~$ lxc-start -n lxc-bb-np
lxcnp@debian9:~$ lxc-ls -f --running
NAME STATE AUTOSTART GROUPS IPV4 IPV6
lxc-bb-np RUNNING 0 - - -

Attachez-vous au conteneur et contrôlez l'UID de l'utilisateur des processus dans le conteneur :

lxcnp@debian9:~$ lxc-attach -n lxc-bb-np
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
WARN: could not reopen tty: Permission denied
BusyBox v1.22.1 (Debian 1:1.22.0-19+b3) built-in shell (ash)
Enter 'help' for a list of built-in commands.
/ # ps aux
PID USER COMMAND
1 root init
4 root /bin/syslogd
7 root /bin/getty -L tty1 115200 vt100
8 root init
9 root /bin/sh
10 root ps aux
/ #

Détachez-vous du conteneur et sortez du compte lxcnp :

/ # exit
lxcnp@debian9:~$ exit
déconnexion
root@debian9:~#

Dernièrement, vérifiez l'UID de l'utilisateur des processus appartenant au conteneur :

root@debian9:~# ps aux | grep 165536
165536 3450 0.0 0.0 4832 256 ? Ss 13:17 0:00 init
165536 3462 0.0 0.0 4836 100 ? Ss 13:17 0:00 /bin/syslogd
165536 3465 0.0 0.0 4832 256 pts/0 Ss+ 13:17 0:00 /bin/getty -L tty1 115200 vt100
165536 3466 0.0 0.0 4832 108 pts/2 Ss+ 13:17 0:00 init
root 3485 0.0 0.0 12784 932 pts/0 S+ 13:22 0:00 grep 165536

2.7 - Création d'un Conteneur Éphémère

Par défaut les conteneurs LXC sont permanents. Il est possible de créer un conteneur éphémère, c'est-à-dire un conteneur où toutes les données sont détruites à l'arrêt de celui-ci, en utilisant la commande lxc-copy ainsi que l'option de cette commande –epheremal ou -e.

La Commande lxc-copy

Notez que le conteneur d'origine doit être arrêté lors de l'utilisation de la commande lxc-copy :

root@debian9:~# lxc-ls -f --running
NAME STATE AUTOSTART GROUPS IPV4 IPV6
lxc-bb RUNNING 0 - - -
root@debian9:~# lxc-copy -e -N lxc-bb-eph -n lxc-bb
lxc-copy: lxccontainer.c: do_lxcapi_clone: 3079 error: Original container (lxc-bb) is running

Arrêtez donc le conteneur lxc-bb puis créez la copie :

root@debian9:~# lxc-stop -n lxc-bb
root@debian9:~# lxc-ls -f --running
root@debian9:~# lxc-copy -e -N lxc-bb-eph -n lxc-bb
Created lxc-bb-eph as clone of lxc-bb

Attachez-vous au conteneur lxc-bb-eph :

root@debian9:~# lxc-attach lxc-bb-eph
lxc-attach: missing container name, use --name option
root@debian9:~# lxc-attach -n lxc-bb-eph
BusyBox v1.22.1 (Debian 1:1.22.0-19+b3) built-in shell (ash)
Enter 'help' for a list of built-in commands.
~ #

Créez un fichier de contrôle appelé testdata :

~ # ls -l
total 4
-rw-r--r-- 1 root root 51 Jul 28 13:47 hi.sh
~ # pwd
/root
~ # echo "test" > testdata
~ # ls -l
total 8
-rw-r--r-- 1 root root 51 Jul 28 13:47 hi.sh
-rw-r--r-- 1 root root 5 Jul 29 15:14 testdata
~ #

Déconnectez-vous du conteneur puis attachez-vous de nouveau :

~ # exit
root@debian9:~# lxc-attach -n lxc-bb-eph
BusyBox v1.22.1 (Debian 1:1.22.0-19+b3) built-in shell (ash)
Enter 'help' for a list of built-in commands.
~ # ls -l
total 8
-rw-r--r-- 1 root root 51 Jul 28 13:47 hi.sh
-rw-r--r-- 1 root root 5 Jul 29 15:14 testdata
~ #

Important - Notez que le fichier testdata est toujours présent.

Déconnectez-vous de nouveau et arrêtez le conteneur :

~ # exit
root@debian9:~# lxc-stop -n lxc-bb-eph
root@debian9:~# lxc-ls
lxc-bb
root@debian9:~# lxc-start -n lxc-bb-eph
lxc-start: log.c: log_open: 300 failed to open log file "/var/lib/lxc/lxc-bb-eph/lxc-bb-eph.log" : No such file or directory
lxc-start: tools/lxc_start.c: main: 317 Executing '/sbin/init' with no configuration file may crash the host

Important - Notez que le conteneur lxc-bb-eph a été détruit.

2.8 - Sauvegarde des Conteneurs

Un conteneur LXC peut être sauvegardé de trois façons différentes :

utiliser la commande tar ou cpio pour créer un archive du répertoire rootfs et du fichier config associés au conteneur

utiliser la commande lxc-copy sans l'option -e

utiliser la commande lxc-snapshot

La Commande lxc-snapshot

Cette commande permet de gérer des instantanées des conteneurs. A noter que les conteneurs doivent être arrêtés avant de prendre une instantanée :

root@debian9:~# lxc-ls -f --running
root@debian9:~# lxc-snapshot -n lxc-bb
lxc-snapshot: lxccontainer.c: do_lxcapi_snapshot: 3407 Snapshot of directory-backed container requested.
lxc-snapshot: lxccontainer.c: do_lxcapi_snapshot: 3408 Making a copy-clone. If you do want snapshots, then
lxc-snapshot: lxccontainer.c: do_lxcapi_snapshot: 3409 please create an aufs or overlayfs clone first, snapshot that
lxc-snapshot: lxccontainer.c: do_lxcapi_snapshot: 3410 and keep the original container pristine.

Les snapshots sont stockés dans le sous-répertoire snaps du répertoire /var/lib/lxc/<nom_conteneur>/. Le premier s'appelle snap0 :

root@debian9:~# ls -l /var/lib/lxc/lxc-bb
total 12
-rw-r--r-- 1 root root 1102 juil. 28 13:04 config
-rw-r--r-- 1 root root 0 juil. 28 13:14 lxc-bb.log
drwxr-xr-x 17 root root 4096 juil. 28 15:50 rootfs
drwxr-xr-x 3 root root 4096 juil. 29 17:34 snaps
root@debian9:~# ls -l /var/lib/lxc/lxc-bb/snaps/
total 4
drwxrwx--- 3 root root 4096 juil. 29 17:34 snap0
root@debian9:~# ls -l /var/lib/lxc/lxc-bb/snaps/snap0/
total 12
-rw-r--r-- 1 root root 1110 juil. 29 17:34 config
drwxr-xr-x 17 root root 4096 juil. 28 15:50 rootfs
-rw-r--r-- 1 root root 19 juil. 29 17:34 ts

L'horodatage de la création du snapshot est stocké dans le fichier ts :

root@debian9:~# cat /var/lib/lxc/lxc-bb/snaps/snap0/ts
2020:07:29 17:34:36root@debian9:~#

En comparant la taille du rootfs du conteneur d'origine ainsi que de son snapshot, on peut constater que les deux sont identiques :

root@debian9:~# du -sh /var/lib/lxc/lxc-bb/rootfs/
792K	/var/lib/lxc/lxc-bb/rootfs/
root@debian9:~# du -sh /var/lib/lxc/lxc-bb/snaps/snap0/rootfs/
792K	/var/lib/lxc/lxc-bb/snaps/snap0/rootfs/

Pour restaurer un conteneur identique à l'original, il convient d'utiliser de nouveau la commande lxc-snapshot :

root@debian9:~# lxc-snapshot -r snap0 -n lxc-bb -N lxc-bb-snap0
root@debian9:~# lxc-ls
lxc-bb lxc-bb-snap0
root@debian9:~# lxc-start -n lxc-bb-snap0
root@debian9:~# lxc-attach -n lxc-bb-snap0
BusyBox v1.22.1 (Debian 1:1.22.0-19+b3) built-in shell (ash)
Enter 'help' for a list of built-in commands.
~ # exit
root@debian9:~#

Copyright © 2022 Hugh Norris.