Lorsque l'on veut compartimenter ses services sans trop d'impact sur les performances, on pense à la virtualisation par conteneurs. Souvent, on pense OpenVZ.
On peut se demander quelles différences existent entre OpenVZ et LXC. Comme je ne suis pas un expert, je me contente de reprendre les réponses que l'on peut lire n'importe où sur le web :
- LXC n'a pas besoin d'un noyau spécial contrairement à OpenVZ.
- LXC aurait une gestion du réseau beaucoup plus simple qu'OpenVZ.
- OpenVZ a été supprimé des packages officiels Debian.
Je vous propose d'installer et d'utiliser LXC sur un Kimsufi d'OVH équipé d'une Debian stable 64 bits. Le sujet ayant été abordé de nombreuses fois, ce billet ne sera finalement qu'une compilation des différentes sources avec une correction de ce qui ne marche pas chez moi.
Table des matières
Installer LXC
Pour éviter quelques problèmes, nous allons installer la version 0.8 présente dans les backports pour Squeeze.
Pour utiliser les backports, il faut ajouter cette ligne à votre fichier /etc/apt/sources.list :
deb http://backports.debian.org/debian-backports squeeze-backports main
|
Installation :
apt-get update && apt-get -t squeeze-backports install lxc
|
Dans l'interface de configuration semi-graphique, laissez le répertoire proposé.
Compiler un noyau utilisant les cgroups + grsec
Le kernel compilé par OVH n'a pas le support des cgroups qui est requis par LXC.
Je pense qu'installer un noyau Debian standard (apt-get -t squeeze-backports install linux-image-amd64 linux-headers-amd64) doit résoudre le problème sans rien casser.
Mais ici nous voulons activer les cgroups et conserver grsec qui est activé sur les noyaux OVH.
Afin de réduire le temps de compilation, il faut envisager de compiler sur votre desktop, pas sur votre KS. Comptez 1h sur un KS 2G contre 15 minutes sur une machine récente ...
On vérifie que l'on a bien tous les outils nécessaires à la compilation :
apt-get install make gcc libncurses5-dev lzma dpkg-dev
|
On se prépare un dossier de travail :
mkdir /usr/src/kernel && cd /usr/src/kernel
|
On récupère les sources du dernier 3.2 :
wget -c https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.2.31.tar.bz2
|
On les décompresse :
tar jxf linux-3.2.31.tar.bz2
|
On récupère le dernier patch grsec :
wget -c https://grsecurity.net/stable/grsecurity-2.9.1-3.2.31-201210111928.patch
|
On applique le patch grsec :
cd linux-3.2.31 && patch -p1 < ../grsecurity-2.9.1-3.2.31-201210111928.patch
|
On récupère la config OVH + grsec :
wget "https://www.dguillem.fr/dokuwiki/_export/code/public/ovh/kernel-3.2.13-grs-config?codeblock=0" -O ".config"
|
ÉDIT du 17/02/2014 à 11h10 : L'url ci-dessus est cassée. Je mets mon .config à votre disposition (3.2.45, amd64, grsec et les options nécessaires à LXC déjà activées, issu du lien ci-dessus) :
wget "http://www.guiguishow.info/wp-content/uploads/2014/02/config-linux-3.2.45-amd64-ovh-grsec-lxc" -O ".config"
|
Il marche bien avec la version 3.2.54 aussi ... normal, c'est du 3.2.X.
Fin de l'édit
ÉDIT du 24/05/2014 à 14h32 : Toujours valide pour la version 3.2.58. Il suffit de laisser les réponses par défaut pour les nouveaux choix. Fin de l'édit
ÉDIT du 23/07/2015 à 15h50 : Toujours valide pour la version 3.2.69. Il suffit de laisser les réponses par défaut pour les nouveaux choix. Mais pour ceux qui veulent directement le bon fichier :
wget "http://www.guiguishow.info/wp-content/uploads/2014/02/config-linux-3.2.69-amd64-ovh-grsec-lxc" -O ".config"
|
Fin de l'édit
On configure notre noyau :
Dans l'interface semi-graphique, voici les options à activer en supplément :
General setup -> Control Group Support -> Memory Resource Controller Swap Extension
General setup -> Control Group Support -> Memory Resource Controller Swap Extension enabled by default
General setup -> Control Group Support -> Enable perf_event per-cpu per-conteneur group (cgroup) monitoring
General setup -> Control Group Support -> Group CPU scheduler -> CPU bandwidth provisioning for FAIR_GROUP_SCHED
General setup -> Control Group Support -> Group CPU scheduler -> Group scheduling for SCHED_RR/FIFO
General setup -> Namespace support -> User namespace
General setup -> Namespace support -> PID Namespaces
Networking support -> Networking options -> GVRP (GARP VLAN Registration Protocol) support
Device Drivers -> Network device support -> MAC-VLAN support
Device Drivers -> Network device support -> MAC-VLAN based tap driver
Device Drivers -> Network device support -> Virtual ethernet pair device
Device Drivers -> Character devices -> Support multiple instances of devpts
Security options -> Grsecurity -> Customize Configuration -> Sysctl Support -> Sysctl support
Security options -> Grsecurity -> Customize Configuration -> Sysctl Support -> Turn on features by default
|
Vous pouvez également donner un suffixe au nom de votre kernel afin de l'identifier. Cela se fait dans General Setup -> Local version - append to kernel release
lxc-checkconfig permet de vérifier que l'on a bien activé toutes les options requises par LXC :
CONFIG=/usr/src/kernel/linux-3.2.31/.config lxc-checkconfig
|
Normalement, vous devriez obtenir un "enabled" à chaque ligne. "File capabilities" peut être marqué comme "missing", ce n'est pas bloquant.
On lance la compilation :
Si vous compilez sur votre desktop, vous pouvez profiter du multithreading (sous Debian, il vous faudra alors le package supplémentaire gcc-4.7-plugin-dev) :
make deb-pkg -j <nombre de coeurs + 1>
|
En version automatique (et avec du bashisme inside ) :
make deb-pkg -j $((`nproc`+1))
|
Pour nproc, voir ici.
Une fois la compilation terminée, vous pouvez installer votre nouveau noyau :
cd .. && dpkg -i linux-image-3.2.31-grsec_3.2.31-grsec-1_amd64.deb linux-headers-3.2.31-grsec_3.2.31-grsec-1_amd64.deb
|
Note : si vous avez compilez sur votre desktop, pensez à transférer les deux paquets Debian sur votre KS via SCP ...
Normalement, votre kernel se placera en premier dans le menu de boot et donc, votre KS démarrera automatiquement sur votre kernel. Néanmoins, pour en être sûr, il suffit de désactiver l'entrée du menu boot créée pour le kernel OVH :
mv /etc/grub.d/06_OVHkernel . && update-grub2
|
Il ne vous reste plus qu'à faire démarrer votre KS sur votre kernel ...
Partitionner
Le but du jeu est de se créer une partition dédiée à nos conteneurs. Pour cela, nous allons prendre de l'espace sur la partition /home. Par la même occasion, nous allons augmenter la taille du swap.
Chacun ses goûts mais moi j'utilise parted :
Lister les partitions :
Normalement, vous avez une première partition primaire en ext4 sur lequel se trouve Debian. La deuxième partition (la plus grande), est montée sur /home. La dernière, de 512Mo est le swap. Si ce n'est pas le cas, réfléchissez avant de continuer et remplacez mes commandes par les commandes adaptées à votre situation !
Nous allons :
- Écraser la partition 2 pour en faire deux partitions : une pour stocker les conteneur, l'autre pour vos données.
- Détruire le swap pour le recréer avec une taille de 1Go.
Suppression des deux partitions :
Création de la partition pour les conteneurs (environ 100Go) :
mkpart
primary
ext2 (entrée)
21,5GB
125GB
|
Création de la partition pour les données (le reste moins 1Go) :
mkpart
primary
ext2 (entrée)
125GB
999GB
|
Création du swap (-1 = tout l'espace restant)
mkpart
primary
ext2 (entrée)
999GB
-1
|
Le travail est finit, on quitte parted.
Formatage des partitions :
mkfs.ext4 -L CONT /dev/sda2
mkfs.ext4 -L DATA /dev/sda3
mkswap /dev/sda4
|
Nous allons corriger /etc/fstab :
/dev/sda2 /home ext4 defaults,relatime 0 2
|
devient :
/dev/sda3 /home ext4 defaults,relatime 0 2
|
Utilisation de LVM
Chaque système de fichiers de chacun de nos conteneurs LXC sera stocké dans un volume logique indépendant.
Création du volume physique :
Création du groupe de volumes (appelez-le comme vous voulez, dans le cadre de ce billet, ça sera CONT ...) :
Création d'un premier volume logique destiné à notre premier conteneur (appelez-le comme vous voulez, dans le cadre de ce billet, ça sera CONT1 et adaptez la taille, pour moi, ça sera 25Go ...) :
lvcreate -n CONT1 -L 25G CONT
|
Formatage de ce premier volume logique :
mkfs.ext4 -L CONT1 /dev/CONT/CONT1
|
Préparation de LXC
Installation du nécessaire :
apt-get install bridge-utils debootstrap libvirt-bin
|
Ajout de deux lignes au fstab :
cgroup /sys/fs/cgroup cgroup defaults 0 0
/dev/CONT/CONT1 /var/lib/lxc/CONT1 ext4 defaults 0 2
|
Montage :
mkdir /var/lib/lxc/CONT1 && mount /dev/CONT/CONT1
mount cgroup
|
Lors de la création d'un conteneur, LXC vérifie que le dossier portant le nom de la machine n'existe pas. Or, comme nous voulons un volume logique/conteneur, nous sommes obligé de monter le volume logique avant la création du conteneur et donc ... le répertoire existe. De manière plus claire : LXC n'appréciera pas l'existence de /var/lib/lxc/CONT1. Il faut bypasser ce comportement en modifiant le fichier /usr/bin/lxc-create. Il faut répérer le code suivant :
if [ -d "$lxc_path/$lxc_name" ]; then
echo "'$lxc_name' already exists"
exit 1
fi
|
Et commenter, au minimum, la ligne contenant le exit.
Création d'un premier conteneur LXC
D'abord, désactivons temporairement certaines fonctions de grsec :
echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_mount
echo 0 > /proc/sys/kernel/grsecurity/chroot_caps
|
Si vous ne le faites pas, alors, vous aurez une erreur de ce type lors du lxc-create :
W: Failure trying to run: chroot /var/cache/lxc/debian/squeeze_amd64.partial mount -t proc proc /proc
|
Le fichier /var/cache/lxc/debian/squeeze_amd64.partial/debootstrap/debootstrap.log contiendra une erreur de ce type :
Et dmesg vous retournera un message du type "use of CAP_SYS_ADMIN in chroot denied"
Création du conteneur :
lxc-create -n CONT1 -t debian
|
Vous voici dans une interface smi-graphique.
Preseed file : laissez vide
Debian Squeeze
64 bits PC
Archives : laissez comme ça
Miroir : ftp://mirror.ovh.net/debian/ (autant prendre le plus proche 😀 )
Laissez les autres miroires tels quels
Choisissez uniquement la distribution main
Packages : iputils-ping traceroute iptables wget nano rsyslog bash-completion (cela permet d'installer d'office les commandes ping/traceroute/iptables/wget/nano, d'avoir un rsyslogd comme démon de logging et d'activer un minimum d'autocompletion)
Mot de passe root : à choisir avec attention 😉
On n'oublie pas de réactiver les fonctionnalités de grsec :
echo 1 > /proc/sys/kernel/grsecurity/chroot_deny_mount
echo 1 > /proc/sys/kernel/grsecurity/chroot_caps
|
Configuration réseau
Pour cette partie, je vous renvoie sur un autre tuto dans lequel les différentes possibilités sont bien expliquées : Linux conteneurs sur KIMSUFI OVH.
Prêt pour le lancement
Il faut créer les fichiers spéciaux correspondant à chaque console virtuelle :
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty1 c 4 1
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty2 c 4 2
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty3 c 4 3
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty4 c 4 4
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty5 c 4 5
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty6 c 4 6
|
Si vous ne le faîtes pas, vous n'aurez pas de prompt avec lxc-console.
Pour que SSH fonctionne, il faut générer les clés du serveur :
ssh-keygen -t rsa -f /var/lib/lxc/CONT1/rootfs/etc/ssh/ssh_host_rsa_key
ssh-keygen -t dsa -f /var/lib/lxc/CONT1/rootfs/etc/ssh/ssh_host_dsa_key
|
Pour que le conteneur utilise le fuseau horaire local :
echo "Europe/Paris" > /var/lib/lxc/CONT1/rootfs/etc/timezone
cp /var/lib/lxc/CONT1/rootfs/usr/share/zoneinfo/Europe/Paris /var/lib/lxc/CONT1/rootfs/etc/localtime
|
Lancement
Obtenir une console :
Éteindre le conteneur en douceur (la manière brutale se fait avec lxc-stop) :
Connaître l'état du conteneur
Démarrage automatique d'un (ou plusieurs) conteneur(s)
Pour démarrer un ou plusieurs conteneur au boot, il suffit simplement de placer un lien symbolique pointant vers le fichier de configuration du(des) conteneur(s) à démarrer dans le dossier /var/lib/lxc/auto. Exemple :
ln -s /var/lib/lxc/CONT1/config /etc/lxc/auto/CONT1.conf
|
Et pour chaque nouveau conteneur ?
Pour chaque nouveau conteneur, il suffira de créer son volume logique, de le formater, de le monter et d'ajouter la ligne "kivabien" dans /etc/fstab.
Il faudra désactiver les 2 fonctionnalités de grsec, créer le conteneur (lxcreate quoi) et réactiver les fonctionnalités de grsec.
Il faudra configurer l'accès au réseau du conteneur puis il faudra faire les modifications pré-lancement (création des tty, génération des clés SSH, ...).
Tout cela doit s'automatiser facilement avec un script mais je n'ai pas étudié la question.
Note
Normalement, depuis sa version 0.8, LXC est capable d'automatiser la création et l'utilisation de volumes logiques. Ainsi, une commande comme celle-ci "lxc-create -t debian -n test -B lvm --vgname CONT --fssize 5G --fstype ext4" doit créer un conteneur et son volume logique associé. Mais la création échoue. Cela semble être un bug reproductible : http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg1062961.html.
J'ai essayé de comprendre et sans être un expert, voici où j'en suis arrivé :
Dans le fichier lxc-debian, ligne 484, en plein dans la fonction Copy_system (), on copie un dossier de la forme /var/cache/lxc/squeeze_amd64 dans le dossier /var/lib/lxc/NOM_CONT/rootfs/squeeze_amd64. On essaye ensuite d'accéder à/ou de monter des dossiers de la forme /var/lib/lxc/NOM_CONT/rootfs/etc/apt/sources.d/debian/list. Mais il n'y a rien ici, tout est dans le dossier squeeze_amd64.
Ce problème n'est pas réparé avec la version de LXC présente dans le dépôt unstable. Je ne sais pas si la version actuelle (via git) corrige ce problème.
Si vous voulez absolument utiliser cette fonctionnalité, voilà une solution qui semble marcher :
Remplacer la ligne 484 de /usr/share/lxc/templates/lxc-debian par
cp -Ra "${_CACHE}/${_DISTRIBUTION}_${_ARCHITECTURE}" "${_ROOTFS}"/* || return 1
|
Procéder à la création normale du conteneur.
Modifier ensuite le fichier de configuration (ex : /var/lib/lxc/NOM_CONT/config) afin que le paramètre lxc.rootfs contienne la bonne valeur (/var/lib/lxc/NOM_CONT/rootfs). Si vous ne faîtes pas cela, alors vous aurez une erreur "unable to determine your tty name" lors du login via lxc-console.
N'oubliez pas d'ajouter une ligne dans /etc/fstab pour que le conteneur puisse démarrer tout seul. Exemple :
/dev/CONT/test /var/lib/lxc/test/rootfs ext4 defaults 0 0
|
Puis monter ce volume logique comme d'habitude. Vous pouvez ensuite utiliser lxc-start.
Cette méthode me paraît vraiment "bricolage". Je préfère créer/monter moi-même le volume logique ...
Sources