Kimsufi : la conteneurisation via LXD

Rédigé par Alexandre il y a 3 mois

#auto-hébergement #debian #loisir

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.