Installation et paramétrage d'un serveur avec conteneurs LXC chez Online.net/Dedibox

Nous allons décrire ici l'installation et la paramétrage d'un serveur dédié chez Online.net (offres Dedibox). La description de l'installation ne sera peut-être pas exhaustive et se concentrera sur les points clés, ceux qui par exemple ont été bloquants lors de notre déploiement.

Au niveau des technologies utilisées...

Nous allons déployer une version Debian stable (7.x à l'écriture de ces lignes) avec LVM2 (pour le découpage de l'espace disque) étant entendu que le RAID est géré matériellement et ne demande pas de paramétrage au niveau du système. La technologie LXC (LinuX Containers) sera utilisée pour séparer les servicse dans plusieurs conteneurs indépendants.

Pour le réseau, chaque conteneur disposera de sa propre IPv6 et sera donc accessible directement. En IPv4 en revanche, on déploiera un réseau local IPv4 avec un NAT pour répartir le trafic sur les différents conteneurs.

Paramétrage du réseau IPv6 chez Online.net

Chez Online.net, un bloc /48 est attribué avec chaque serveur dédié. Pour gérer l'IPv6 sur le serveur, il faudra installer le client Dibbler (un client DHCPv6) :

aptitude install dibbler-client

puis modifier la clé DUID dans le fichier /var/lib/dibbler/client-duid pour insérer celle attribuée par Online.net dans l'interface d'administration du système. Enfin, on modifiera le fichier de configuration /etc/dibbler/client.conf tel que suit :

log-level 7
iface br0 {
    pd
    option dns-server
    option domain
}

On modifie alors le fichier /etc/network/interfaces pour contenir les éléments suivants :

auto br0
iface br0 inet static
    address 88.123.123.123
    netmask 255.255.255.0
    gateway 88.123.123.1
    bridge_ports eth0

iface br0 inet6 static
    address 2001:abcd:abcd:abcd::
    gateway fe80::123:1234:1234:1234
    netmask 56

Vous aurez bien sûr pris le soin de remplacer 2001:abcd:abcd:abcd:: par l'adresse IPv6 correspondant au bloc /56 que vous avez décidé d'attribuer à votre serveur dédié et de spécifier la bonne passerelle (la passerelle par défaut est aussi l'adresse du routeur auquel est connecté votre Dedibox, vous pourrez trouver dans les logs de Dibbler l'adresse de ce routeur). Et remplacer 88.123.123.123 par l'adresse IPv4 qui vous a été attribuée (et spécifier la passerelle correspondante).

Ce paramétrage correspond à la mise en place d'un pont réseau (bridge) ce qui permettra à toutes les machines virtuelles de communiquer entre elles et de partager les communications réseau.

On redémarre alors le réseau :

/etc/init.d/networking restart

(si vous êtes connecté en SSH, il faudra peut-être se reconnecter en utiliser les nouvelles adresses spécifiées - pour forcer la connexion SSH en IPv6 il faudra utiliser ssh -6 et ssh -4 pour forcer l'IPv4)

puis on redémarre Dibbler par les commandes habituelles :

/etc/init.d/dibbler-client stop 
/etc/init.d/dibbler-client start

Une fois les conteneurs en place, nous reviendrons sur ce paramétrage pour y apporter quelques légères modifications.

Création de volumes virtuels avec LVM pour héberger les conteneurs

Chaque conteneur sera contenu dans un espace logique géré par LVM. Cela permettra notamment une manipulation aisée pour le redimensionnements, les sauvegardes...

Lors de l'installation initiale, nous avons donc pris le soin de garder une grosse partition /dev/sdaX non utilisée - c'est elle que nous allons déclarer comme volume physique pour LVM.

Il faut d'abord s'assurer que /dev/sdaX n'est pas mentionné dans /etc/fstab et le cas échéant commenter la ligne correspondante.

Puis on crée le volume physique :

pvcreate /dev/sdaX
vgcreate vg /dev/sdaX

et 2 volumes logiques de 50 Go :

lvcreate -n Nom1 -L 50g vg
lvcreate -n Nom2 -L 50g vg
mkfs.ext4 /dev/vf/Nom1
mkfs.ext4 /dev/vf/Nom2

Installation de LXC et déploiement du premier conteneur

aptitude install lxc lxc lxctl bridge-utils debootstrap unzip

installera les éléments nécessaires. Puis on modifiera /etc/fstab pour contenir :

cgroup        /sys/fs/cgroup        cgroup        defaults    0    0

La commande lxc-checkconfig permet de vérifier si tout est paré et donné des aides pour la résolution d'éventuels problèmes. Une fois que tous les paramètres de lxc-checkconfig sont au vert, on se lance pour de vrai !

A noter que le template Debian 7 inclus par défaut pour LXC dans Debian 7 est défectueux (cf. 'The Debian 7 template is broken' in [https://wiki.debian.org/LXC |https://wiki.debian.org/LXC] et la solution proposée ici par Rob van der Hoeven). Les lignes ci-dessous correspondent à la solution proposée par Rob.

On déploie un template fonctionnel :

cd /usr/share/lxc/templates/
wget http://freedomboxblog.nl/wp-content/uploads/lxc-debian-wheezy.gz
gzip -d lxc-debian-wheezy.gz
chmod u+x lxc-debian-wheezy

et on lance la création du premier conteneur :

lxc-create -n myfirstcontainer -t debian-wheezy

On déplace alors le conteneur dans le premier disque logique LVM que nous avions créé précédement :

cd /var/lib/lxc/
mv myfirstcontainer myfirstcontainer-tmp
mkdir myfirstcontainer
mount /dev/vg/Nom1 myfirstcontainer
cd myfirstcontainer-tmp
cp -R * ../myfirstcontainer/
cd ..
rm -Rf myfirstcontainer-tmp

et on paramètre le conteneur comme suit dans /var/lib/lxc/myfirstcontainer/config :

lxc.utsname = container1
lxc.network.type = veth
lxc.network.veth.pair = vethcontainer1
lxc.network.flags = up
lxc.network.link = br0
lxc.network.ipv4 = 192.168.0.101/24  #on attribue une adresse IPv4 de réseau local
lxc.network.ipv4.gateway = 192.168.0.1  #la passerelle, nous allons attribuer cette adresse ensuite à l'hôte physique
lxc.network.hwaddr = 00:11:D0:14:84:BE  #attention, à modifer par une valeur aléatoire si vous installez plusieurs machines pour qu'il n'y ait pas collision !
lxc.network.ipv6 = 2001:abcd:abcd:abcd::101/56  #une adresse appartenant au bloc /56 attribué au serveur dédié

et on modifie les paramétrages réseau au sein du conteneur dans /var/lib/lxc/myfirstcontainer/rootfs/etc/network/interfaces :

auto eth0
iface eth0 inet static
    address 192.168.0.101

iface eth0 inet6 static
    address 2001:abcd:abcd:abcd::101
    netmask 56
    post-up ip -6 route add default via 2001:abcd:abcd:abcd::

Sur la machine hôte, on modifie alors les paramètres tel que suit :

  • on indique à Dibbler de ne pas chercher à paramétrer l'interface virtuelle vethcontainer1 en ajoutant dans la configuration de Dibbler :
iface vethcontainer1 no-config
  • on met en place le réseau IPv4 par :
ip addr add 192.168.0.1 dev br0
ip route add 192.168.0.0/16 dev br0
iptables -t nat -A POSTROUTING -o br0 -j MASQUERADE
  • on met en place le réseau IPv6 par :
ip -6 route add 2001:abcd:abcd:abcd::101 dev br0
  • on modifie les paramétrages réseau du système en modifiant /etc/sysctl.conf :
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.forwarding = 1
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.all.accept_ra = 2

et sysctl -p pour prendre en compte ces paramétrages.

Si la connectivité IPv6 disparaît, alors il faudra se reconnecter en IPv4 et lancer les commandes suivantes :

ip -6 route add aa:bb:cc:dd:ee::/64 dev br0
ip -6 route add default via aa:bb:cc:dd:ee::1 dev br0
/etc/init.d/dibbler-client stop
/etc/init.d/dibbler-client start

en remplaçant aa:bb:cc:dd:ee::1 par l'adresse de la passerelle IPv6 (cette adresse est normalement communiquée par les Router Advertisements).

Tout semble alors prêt pour le démarrage du conteneur !

Lancement du conteneur

lxc-start -d -n myfirstcontainer

et on peut alors s'y connecter en console via :

lxc-console -n myfirstcontainer

Par défaut, le mot de passe root est root (c'est le paramétrage par défaut du template que nous avons utilisé - il va de soi que nous allons rapidement modifier ce paramétrage).

Pour quitter la console LXC, il faudra faire Ctrl+a puis d.

Dans le conteneur, on pourra vérifier que :

  • ping 192.168.0.1 fonctionne (ping de la machine hôte physique)
  • ping 8.8.8.8 fonctionne (ping vers l'extérieur, le web)
  • ping -6 2001:abcd:abcd:abcd:: fonctionne (ping de la machine hôte physique en IPv6)
  • ping -6 2001:4860:4860::8888 fonctionne (ping vers le web en IPv6)

Si tout fonctionne comme attendu, on peut alors poursuivre l'installation du système. On pourra par exemple :

  • créer des conteneurs additionnels (en adaptant quelque peu le paramétrage réseau afférent)
  • paramétrer iptables et ip6tables sur l'hôte physique et les conteneurs pour protéger les systèmes et rediriger le trafic IPv4 sur les conteneurs
  • installer Pound comme reverse proxy pour diriger le trafic HTTP/HTTPS IPv4 vers les différents conteneurs sous-jacents

Exemple de configuration iptables sur l'hôte physique

#!/bin/bash
IPTABLES='/sbin/iptables';

CT1_HOST="192.168.0.101";
CT2_HOST="192.168.0.102";
MONITORING_ONLINE="88.190.254.18";
LAN="192.168.0.0/24";
WAN_IFACE="br0";
WAN_IP="88.123.123.123";
# Flushing tables
$IPTABLES -F
$IPTABLES -X
$IPTABLES -t nat -F
# Define default policy
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT

$IPTABLES -A INPUT -j ACCEPT -d $LAN;
$IPTABLES -A INPUT -j ACCEPT -m state --state ESTABLISHED,RELATED

# Temporary - SSH access open to all IPs on port 22 but Fail2ban is working.$
$IPTABLES -A INPUT -j ACCEPT -p tcp --dport 22
# Opens to ping from online monitoring
$IPTABLES -A INPUT -j ACCEPT -p icmp -s $MONITORING_ONLINE

# Accepts connection to ports 80 and 443
$IPTABLES -A INPUT -j ACCEPT -p tcp --dport 80
$IPTABLES -A INPUT -j ACCEPT -p tcp --dport 443

# Rediriger le port 123 vers le container 1
$IPTABLES -t nat -A PREROUTING -p tcp --dport 123 -d $WAN_IP -j DNAT --to-destination $CT2_HOST:123

# Rediriger un port 456 vers le container 2
$IPTABLES -t nat -A PREROUTING -p tcp --dport 456 -d $WAN_IP -j DNAT --to-destination $PAB2_HOST:456

# Activating masquerade FROM local network
$IPTABLES -t nat -A POSTROUTING -o $WAN_IFACE -s $LAN -j MASQUERADE

Exemple de configuration de pound sur l'hôte physique

User		"www-data"
Group		"www-data"
RootJail	"/chroot/pound"

## Logging: (goes to syslog by default)
##	0	no logging
##	1	normal
##	2	extended
##	3	Apache-style (common log format)
LogFacility local0
LogLevel 1

## check backend every X secs:
Alive		180

## use hardware-accelleration card supported by openssl(1):
#SSLEngine	"<hw>"

# poundctl control socket
Control "/var/run/pound/poundctl.socket"

ListenHTTP
	Address 88.123.123.123
	Port	80

	## allow PUT and DELETE also (by default only GET, POST and HEAD)?:
	xHTTP		2

        #Les services à envoyer sur le premier conteneur
	Service
		HeadRequire "Host: .*(domaine1.fr|domaine2.fr|domaine3.fr).*"
		BackEnd
			Address	192.168.0.101
			Port	8080
		End
	End

        #Les services à envoyer sur le second conteneur
        Service
                HeadRequire "Host: .*(domaine4.fr|domaine5.fr).*"
                BackEnd
                        Address 192.168.0.102
                        Port    8080
                End
        End

End

ListenHTTPS
        Address 88.123.123.123
        Port    443
	Cert    "/path/to/certificate/pound.pem"

	HeadRemove "X-Forwarded-Proto"
        AddHeader "X-Forwarded-Proto: https"

        ## allow PUT and DELETE also (by default only GET, POST and HEAD)?:
        xHTTP           2

        #Les services à envoyer sur le premier conteneur
	Service
		HeadRequire "Host: .*(domaine1.fr|domaine2.fr|domaine3.fr).*"
		BackEnd
			Address	192.168.0.101
			Port	8080
		End
	End

        #Les services à envoyer sur le second conteneur
        Service
                HeadRequire "Host: .*(domaine4.fr|domaine5.fr).*"
                BackEnd
                        Address 192.168.0.102
                        Port    8080
                End
        End

End