Kimsufi : la conteneurisation via LXD
Rédigé par Alexandre le 2020-06-13
Avant de louer mon premier serveur dédié, je me suis posé la question du cloisonnement des différents services que je souhaitais héberger. N'ayant pas les moyens de louer un serveur performant pour faire de la virtualisation, je me suis intéressé à la conteneurisation. A l'époque, j'ai fait la découverte de Proxmox VE qui m'a permis d'apprendre, de façon simple, la conteneurisation via OpenVZ, puis LXC.
Quelques mois après avoir acquis un mini-ordinateur Rock64, je me suis naturellement tourné vers Proxmox VE. Malheureusement, le projet ne supporte pas (encore ?) l'architecture arm64 ou armhf. Je me suis alors tourné vers une autre solution, LXD. D'abord testé sur mon Rock64, j'ai finalement décidé de louer un serveur dédié encore moins onéreux et performant pour y déployer LXD.
Cet article documente l'installation et la configuration de LXD sur un serveur Kimsifu KS-3.
Installation
LXD n'est pas disponible dans les paquets Debian et comme je n'ai pas franchement envie de passer sur Ubuntu, je choisis l'installation via le paquet snap.
La version de snapd fournie dans Buster ne supporte pas les dernières versions du paquet lxd, pour contourner le problème, j'ajoute le dépôt testing :
sudo tee /etc/apt/sources.list.d/testing.list <<EOF
deb http://ftp.fr.debian.org/debian/ testing main
EOF
Configurer le système pour ne pas prendre automatiquement les paquets depuis testing :
sudo tee /etc/apt/preferences.d/testing.pref <<EOF
Package: *
Pin: release a=testing
Pin-Priority: 10
EOF
Appliquer la configuration :
sudo apt update
Installer le gestionnaire de paquets :
sudo apt install -t testing snapd
Installer LXD :
sudo snap install lxd
Permettre à l'utilisateur courant d'utiliser LXD :
sudo adduser $(whoami) lxd
Redémarrer :
sudo reboot
Configuration
Installer le paquet permettant de créer une interface de type pont :
sudo apt -y install bridge-utils
On va devoir modifier la configuration de notre serveur pour créer deux interfaces de type pont. La première permettra aux conteneurs d'utiliser l'IPv6, la seconde d'utiliser l'hôte comme passerelle IPv4.
Le fichier final devrait ressembler à ceci (adapter les IP !) :
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
auto eno0
iface eno0 inet manual
# Bridge interface for LXD (WAN)
auto lxdbr0
iface lxdbr0 inet static
address 151.80.XXX.XXX/24
gateway 151.80.XXX.254
dns-nameservers 80.67.169.12 80.67.169.40
bridge_ports eno0
bridge_stp off
bridge_fd 0
iface lxdbr0 inet6 static
address 2001:41d0:e:XXX::1/64
dns-nameservers 2001:910:800::40 2001:910:800::12
post-up /sbin/ip -f inet6 route add 2001:41d0:e:XXXf:ff:ff:ff:ff dev lxdbr0
post-up /sbin/ip -f inet6 route add default via 2001:41d0:e:XXXf:ff:ff:ff:ff
pre-down /sbin/ip -f inet6 route del default via 2001:41d0:e:XXXf:ff:ff:ff:ff
pre-down /sbin/ip -f inet6 route del 2001:41d0:e:XXXf:ff:ff:ff:ff dev lxdbr0
# Bridge interface for LXD (LAN)
auto lxdbr3
iface lxdbr3 inet static
address 192.168.3.254
netmask 255.255.255.0
dns-nameservers 192.168.3.1
post-up sysctl -w net.ipv6.conf.$IFACE.disable_ipv6=1
bridge_ports none
bridge_stp off
bridge_fd 0
Redémarrer le réseau :
sudo systemctl restart networking
Configurer le pare-feu afin de masquer les adresses IPv4 des conteneurs :
sudo tee --append /etc/nftables.conf <<EOF
table ip nat {
chain prerouting {
type nat hook prerouting priority 0;
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
# Allow CT to WAN
ip saddr 192.168.3.0/24 oifname lxdbr0 masquerade
}
}
EOF
NB : La chaîne de prerouting
permet de rediriger des ports vers les conteneurs.
Redémarrer le pare-feu :
sudo systemctl restart nftables
L'IPv6 nécessite l'installation d'un démon afin de découvrir automatiquement les voisins :
sudo apt install ndppd
Configurer le démon (adapter l'IP !) :
sudo tee /etc/ndppd.conf <<EOF
proxy lxdbr0 {
rule 2001:41d0:e:XXX::/64 {
iface lxdbr0
router no
}
}
EOF
Redémarrer le démon :
sudo systemctl restart ndppd
La configuration terminée, il est nécessaire d'activer deux fonctionnalités au noyau :
- IP forwarding : permet de transformer l'hôte en passerelle
- proxy NDP : permet à l'hôte de faire suivre les paquets à la passerelle IPv6
sudo tee /etc/sysctl.d/100-ipforwarding.conf <<EOF
# IP forwarding
net.ipv4.ip_forward=1
net.ipv6.conf.default.forwarding=1
net.ipv6.conf.all.forwarding=1
# proxy NDP
net.ipv6.conf.default.proxy_ndp=1
net.ipv6.conf.all.proxy_ndp=1
EOF
Activer les options :
sudo sysctl -p /etc/sysctl.d/100-ipforwarding.conf
NB : les ports utilisés en entrée par les conteneurs doivent également être ouverts sur le pare-feu de l'hôte
Stockage
Créer un sous-volume pour LXD :
sudo btrfs subvol create /mnt/lxd
Créer un sous-volume pour les sauvegardes :
sudo btrfs subvol create /mnt/backup
Initialisation
Avant de créer un premier conteneur, il est nécessaire d'initialiser LXD :
lxd init
Voici comment j'ai répondu aux questions :
Would you like to use LXD clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (btrfs, dir, lvm, ceph) [default=btrfs]:
Would you like to create a new btrfs subvolume under /var/snap/lxd/common/lxd? (yes/no) [default=yes]: no
Create a new BTRFS pool? (yes/no) [default=yes]: no
Name of the existing BTRFS pool or dataset: /mnt/lxd
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]: no
Would you like to configure LXD to use an existing bridge or host interface? (yes/no) [default=no]: yes
Name of the existing bridge or host interface: lxdbr3
Would you like LXD to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes] no
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:
Ajouter la seconde interface de type pont :
lxc profile device add default eth1 nic name=eth1 nictype=bridged parent=lxdbr0
Configuration par défaut
Afin de s'économiser du travail lors de la création d'un nouveau conteneur, j'édite le profil par défaut :
- désactiver le démarrage automatique
- un seul vCPU
- 512 Mo de RAM
- disque dur de 1Go
lxc profile set default boot.autostart=false limits.cpu=1 limits.memory=512MB && lxc profile device set default root size=1GB
Optimisation
Si toutefois on peut parler d'optimisation puisqu'il s'agit ici d'appliquer ce qui me semble logique lors de l'utilisation de virtualisation ou conteneurisation.
Utiliser plus souvent la mémoire vive que l'espace d'échange (SWAP) :
sudo tee /etc/sysctl.d/100-swappiness.conf <<EOF
vm.swappiness=10
vm.vfs_cache_pressure=50
EOF
Activer les options :
sudo sysctl -p /etc/sysctl.d/100-swappiness.conf
Sauvegarde
Changer les droits du sous-volume créé plus haut :
sudo chown -R $(whoami) /mnt/backup
Mettre en place le dépôt :
git clone http://gitea.ykn.fr/pulsar/backup.git /mnt/backup/
Planifier la sauvegarde en éditant la crontab
du super-utilisateur :
sudo crontab -e
Ajouter la ligne qui suit à la fin du fichier :
@daily /mnt/pumbaa/backup/fullBackup.bash
Épilogue
Exécuter la commande suivante...
lxc list
...qui liste les conteneurs :
+------+-------+------+------+------+-----------+----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | LOCATION |
+------+-------+------+------+------+-----------+----------+
Il est maintenant temps de créer un conteneur servant de modèle.