Table des matières
LXC
Introduction
LXC est utilisé sur notre serveur dans le but de séparer les différents services que nous allons proposer. Cette documentation fait suite aux différents ateliers réalisés pour découvrir et se former sur LXC.
LXC signifie Linux Containers, en français, des conteneurs Linux. Plus d'informations peuvent être trouvées sur leur site Internet. Enfin, voici quelques pages de manuel utiles pour comprendre plus en détails ce sur quoi repose LXC et les fonctionnalités du noyau Linux utilisées :
- kernel namespaces(7)
- kernel capabilities(7)
- cgroups(7)
Installation
Sous Debian Stretch, il suffit d'installer le paquet lxc
.
apt install lxc
D'autres paquets peuvent être nécessaire en fonction du backend choisi, ce qui correspond en gros au système de fichier qui contiendra les conteneurs, ou à la configuration réseau.
Configuration par défaut
Il est possible de définir une configuration par défaut qui sera incluse dans chaque nouveau conteneur. Cela est particulièrement pratique pour la configuration réseau, souvent la même pour tous. Ce fichier en question est /etc/lxc/default.conf
.
Configuration réseau
Il y a plusieurs façon de configurer le réseau au sein des conteneurs.
La plus classique étant de passer par un bridge (ou pont en français) créé sur l'hôte spécifiquement pour les conteneurs. Par cette méthode, on peut également différencier 2 façons de faire :
- faire de la redirection de ports depuis l'hôte vers les conteneurs (plus communément appelé NAT),
On n'a pas fait ça. Ça serait bien de regrouper uniquement les procédures réalisées, et de séparer les idées non réalisées.
- coupler le bridge avec une interface réseau existante.
Elles ont toutes les deux leurs avantages et inconvénients, tout dépend de ce que l'on veut faire.
Bridge avec NAT
Intérêt
Cette méthode a l'avantage de ne pas exposer les conteneurs sur le réseau. Toutes les connexions arrivent d'abord sur l'hôte, qui sera en frontal, et où on aura donc pris le soin de mettre en place un pare-feu. Cela est intéressant quand chaque conteneur a une fonction bien spécifique, ou fournit un service différent.
Afin d'atteindre un conteneur, il faudra ajouter une règle pour rediriger tel port arrivant sur l'hôte vers le port de tel conteneur. Par exemple, si un conteneur est chargé de faire serveur Web, on redirigera les ports 80 et 443 arrivant sur l'hôte vers ce conteneur.
Mise en place
Activation de l'IP forward
Il faut tout d'abord activer l'IP forward sur l'hôte. Ceci permet d'activer la redirection d'une connexion, nécessaire pour la suite. Pour le faire de manière permanente (à noter que ce sera effectif qu'au rechargement de sysctl), on peut le faire avec la commande :
echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-local-ip-forward.conf
Celle-ci va créer le fichier 99-local-ip-forward
dans le dossier /etc/sysctl.d
, une bonne pratique pour étendre les différentes configurations. On peut également l'activer immédiatement (à noter qu'au prochain redémarrage, la valeur par défaut sera réutilisé), avec la commande :
echo '1' > /proc/sys/net/ipv4/ip_forward
Création du pont
Pour créer une nouvelle interface réseau virtuelle, le pont (ou bridge, pour varier), sous Debian, on peut se limiter à créer le fichier /etc/network/interfaces.d/local-bridge-lxc
avec le contenu suivant :
auto lxcbr0 iface lxcbr0 inet static bridge_ports none bridge_fd 0 bridge_maxwait 0 address 192.168.100.1 netmask 255.255.255.0
L'adresse IP de l'interface est définie par address
, et caractérisera la plage IP utilisée pour ce réseau. Elle est donc à adapter en fonction des réseaux déjà existants. Il reste plus qu'à activer cette nouvelle interface, en exécutant :
ifup lxcbr0
Exemples de règles iptables NAT
Première règle de NAT pour que nos conteneurs sur le réseau 10.0.3.0/24 puissent se connecter à internet via l'interface eth0 sur l'hôte :
iptables -t nat -A POSTROUTING -s 10.0.3.0/24 -o eth0 -j MASQUERADE
Ensuite on aimerait rediriger les bon ports en fonction du service correspondant. Par exemple, 80 et 443 vers le conteneur qui fait du web en 10.0.3.10 :
iptables -t nat -A PREROUTING -j DNAT -i eth0 -p tcp --dport 80 --to-destination 10.0.3.10:80 iptables -t nat -A PREROUTING -j DNAT -i eth0 -p tcp --dport 443 --to-destination 10.0.3.10:443
Jetons maintenant un oeil à nos règles de NAT:
iptables -t nat -L
TODO
→ règle iptables POSTROUTING
→ configuration par défaut LXC pour cette interface
lxc-net
lxc-net
est un script se présentant sous la forme d'un service, qui automatise la configuration réseau comme vu précédemment en offrant en plus du DHCP et un DNS pour les conteneurs, en se basant sur dnsmasq. Il se charge donc de créer l'interface bridge, configurer son adresse, et en plus de configurer dnsmasq
afin de faciliter l'adressage et l'accès aux conteneurs. Il n'y a cependant pas énormément de documentation là-dessus, voir par exemple le wiki Debian.
Intérêt
Même si on pourrait être tenté de n'utiliser que lxc-net
vu ce que cela semble simplifier, son usage est néanmoins à modérer ! Il faut avoir conscience qu'avec ce script, on délègue un bon nombre de configurations réseaux vitales pour l'accès au conteneur. En d'autres termes, il ne vaut mieux pas que ce script se casse la figure ou que son comportement change du jour au lendemain, sinon on risque de perdre gros ! Pour relativiser ce qu'il semble simplifier, on se rend compte que créer son interface bridge avec une bonne documentation n'est pas si insurmontable. Cette étape est d'ailleurs à réaliser qu'une seule fois, et permets une plus grande maîtrise et souplesse.
Enfin, une fois de plus, il est bon de se questionner sur ce que l'on veut faire avant tout, afin de voir s'il est adapté et nécessaire. Pour une utilisation sur son poste personnel, orientée développement par exemple, ce script apporte un bon nombre d'avantages et de facilités, notamment en ce qui concerne le DHCP et le DNS (création et accès à des conteneur à la volée). Par contre, dans le cas d'un serveur en production, comme à Mycélium, le DHCP est inutile voir dangereux : on préférera donner à chaque conteneur une IP fixe, afin d'être sûr de l'atteindre !
Mise en place
1. Créer un fichier /etc/default/lxc-net
, contenant les variables suivantes adaptées à vos envies et besoins :
# Active l'utilisation de lxc-net USE_LXC_BRIDGE="true" # Nom de l'interface bridge qui sera créé LXC_BRIDGE="lxcbr0" # IP de l'interface bridge LXC_ADDR="10.0.3.1" # Masque de sous-réseau de l'interface bridge LXC_NETMASK="255.255.255.0" # Adresse du réseau, utilisé pour les règles iptables LXC_NETWORK="10.0.3.0/24" # Plage d'IP servies par le DHCP LXC_DHCP_RANGE="10.0.3.11,10.0.3.254" # Nombre d'IP au sein de la plage définie ci-dessus LXC_DHCP_MAX="244" # Extension de la configuration de dnsmasq LXC_DHCP_CONFILE="" # Domaine des conteneurs sur le réseau LXC_DOMAIN=
Pour information, ce fichier contient tous les paramètres offerts par lxc-net
pour personnaliser ses fonctionnalités. Il est en cherché et sourcé s'il existe par /etc/default/lxc
.
2. Redémarrer le service lxc-net
pour prendre en compte les modifications, ou juste créer l'interface si elle n'existait pas encore :
systemctl restart lxc-net.service
… et l'activer si besoin, pour les futurs (re)démarrage :
systemctl enable lxc-net.service
3. On peut désormais vérifier le bon fonctionnement du script et ce qu'il est censé configurer :
- est-ce que l'interface bridge a bien été créé ?
ip addr
- est-ce que le serveur DNS a bien été lancé et écoute sur la bonne interface ?
ps aux | grep dnsmasq netstat -ntlp
- est-ce que le service s'est bien exécuté ?
systemctl status lxc-net.service
4. Enfin, il reste à adapter la configuration par défaut des conteneurs (dans /etc/lxc/default.conf
) pour s'attacher à cette nouvelle interface bridge, avec au moins :
lxc.network.type = veth lxc.network.link = lxcbr0 lxc.network.flags = up
Utilisation
Création d'un conteneur
Pour créer un conteneur, cela se fait avec la commande lxc-create
. Un man lxc-create
vous apportera toutes les informations nécessaires sur l'utilisation des différents paramètres et options.
Si l'on veut créer un conteneur nommé pouet, en Debian Jessie, et en utilisant le backend par défaut :
lxc-create -n pouet -t debian -- -r jessie
Le conteneur est désormais créé, il est stocké par défaut dans le dossier /var/lib/lxc/pouet
. On y trouve principalement un dossier rootfs
, contenant le système de fichier du conteneur (c'est à ça qu'on se rapproche du chroot), et un fichier config
. C'est ce dernier qu'il va faudra modifier pour adapter sa configuration, comme lui définir une adresse IP par exemple. Pour connaître l'ensemble des valeurs possibles, un man lxc.container.conf
apportera encore beaucoup d'informations.
Optimisations
Par défaut, le conteneur sera crée avec une interface réseau eth0
, configurée en DHCP. Si la configuration réseau est définie de manière statique (dans le fichier de configuration du conteneur par exemple), il est bon de modifier la configuration de eth0
pour éviter qu'il cherche inutilement du DHCP. Pour ce faire, avant de démarrer le conteneur, il faudra modifier le fichier /var/lib/lxc/pouet/rootfs/etc/network/interfaces
et remplacer dhcp
par manual
dans la ligne définissant eth0
. On devrait donc avoir au final :
iface eth0 inet manual
Accès à un conteneur
Une fois le conteneur créé, il va falloir le démarrer avec la commande lxc-start
. Dans l'exmple du conteneur toto :
lxc-create -n toto
Par défaut, à partir de LXC 2.0, le conteneur se lance en arrière plan. Si ce n'est pas le cas, il faudra passer l'option -d
, et au contraire, si vous voulez voir le démarrage au premier-plan, il faudra passer l'option -F
(attention, vous allez atterrir sur une console).
L'un des façons rapides de s'attacher à un conteneur, sans avoir besoin de s'identifier, comme une sorte de chroot au final, se fait avec la commande lxc-attach
:
lxc-attach -n toto
Attention, vous serez néanmoins dans un environnement restreint. Pour se connecter au conteneur, comme on le ferait pour n'importe quelle machine physique, il y a toujours le SSH, s'il est configuré, ou alors la commande lxc-console
:
lxc-console -n toto