Archives par étiquette : VPS

LXC – virtualisation/conteneur

Un petit article pour décrire le fonctionnement de LXC (LinuX Containers) et son utilisation sur une Debian Wheezy.

J’avais commencé ce blog en parlant de Linux Vserver, un système de « virtualisations au niveau du système d’exploitation ».

Ça m’a bien rendu service, mais vserver n’est plus intégré à la Debian Wheezy, il a été remplacé par LXC, hors il fallait bien que je fasse la mise à jour de mes Squeeze.

Je vais faire court car il existe de nombreuses docs sur LXC.

On commence par mettre à jour la Debian (sauf exceptions, il vaut mieux utiliser aptitude que apt-get) :

aptitude update && aptitude full-upgrade

On installe le paquet LXC :

aptitude install lxc

Je rajoute aussi le paquet bridge-utils, mais il n’est pas obligatoire.

Dans /etc/fstab, on ajoute un point de montage pour gérer les ressources :

cgroup /sys/fs/cgroup cgroup defaults 0 0

Attention, il y a un bug dans le script de création des premières Wheezy (corrigé en 7.4 de mémoire).

Le plus simple est de créer un nouveau fichier de modèle, je me suis librement inspiré de celui proposé ici.

Voici mon template /usr/share/lxc/templates/lxc-debian-wheezy :

#!/bin/bash

#Debian Wheezy LXC template
configure_debian()
{
    rootfs=$1
    hostname=$2
    
    # squeeze only has /dev/tty and /dev/tty0 by default,
    # therefore creating missing device nodes for tty1-4.
    for tty in $(seq 1 4); do
    if [ ! -e $rootfs/dev/tty$tty ]; then
        mknod $rootfs/dev/tty$tty c 4 $tty
    fi
    done
    
    # configure the inittab
    cat <<EOF > $rootfs/etc/inittab
    id:3:initdefault:
    si::sysinit:/etc/init.d/rcS
    l0:0:wait:/etc/init.d/rc 0
    l1:1:wait:/etc/init.d/rc 1
    l2:2:wait:/etc/init.d/rc 2
    l3:3:wait:/etc/init.d/rc 3
    l4:4:wait:/etc/init.d/rc 4
    l5:5:wait:/etc/init.d/rc 5
    l6:6:wait:/etc/init.d/rc 6
    # Normally not reached, but fallthrough in case of emergency.
    z6:6:respawn:/sbin/sulogin
    1:2345:respawn:/sbin/getty 38400 console
    c1:12345:respawn:/sbin/getty 38400 tty1 linux
    c2:12345:respawn:/sbin/getty 38400 tty2 linux
    c3:12345:respawn:/sbin/getty 38400 tty3 linux
    c4:12345:respawn:/sbin/getty 38400 tty4 linux
    EOF
    
    # disable selinux in debian
    mkdir -p $rootfs/selinux
    echo 0 > $rootfs/selinux/enforce
    
    # configure the network
    cat <<EOF > $rootfs/etc/network/interfaces
    auto lo
    iface lo inet loopback
    EOF
    
    # set the hostname
    cat <<EOF > $rootfs/etc/hostname
    $hostname
    EOF
    
    # reconfigure timezone
    echo "Europe/Paris" > $rootfs/etc/timezone
    chroot $rootfs dpkg-reconfigure -f noninteractive tzdata
    
    # reconfigure language
    sed -i "s/^# en_US.UTF-8/en_US.UTF-8/" $rootfs/etc/locale.gen
    chroot $rootfs locale-gen
    
    # remove pointless services in a container
    chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove
    chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove
    chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove
    
    echo "root:root" | chroot $rootfs chpasswd
    echo "Root password is 'root', please change !"
    
    return 0
}

download_debian()
{
    packages=
    ifupdown,
    locales,
    libui-dialog-perl,
    dialog,
    netbase,
    net-tools,
    iproute,
    vim,
    bash-completion,
    locales,
    iputils-ping,
    aptitude
    
    cache=$1
    arch=$2
    
    # check the mini debian was not already downloaded
    mkdir -p "$cache/partial-$arch"
    if [ $? -ne 0 ]; then
        echo "Failed to create '$cache/partial-$arch' directory"
       return 1
    fi
    
    # download a mini debian into a cache
    echo "Downloading debian minimal ..."
    debootstrap --verbose --variant=minbase --arch=$arch
    --include $packages
    wheezy $cache/partial-$arch http://ftp.debian.org/debian
    if [ $? -ne 0 ]; then
        echo "Failed to download the rootfs, aborting."
        return 1
    fi
    
    mv "$1/partial-$arch" "$1/rootfs-$arch"
    echo "Download complete."
    
    return 0
}

copy_debian()
{
    cache=$1
    arch=$2
    rootfs=$3
    
    # make a local copy of the minidebian
    echo -n "Copying rootfs to $rootfs..."
    cp -a $cache/rootfs-$arch $rootfs || return 1
    return 0
}

install_debian()
{
    cache="/var/cache/lxc/debian-wheezy"
    rootfs=$1
    mkdir -p /var/lock/subsys/
    (
        flock -n -x 200
        if [ $? -ne 0 ]; then
            echo "Cache repository is busy."
            return 1
        fi
        
        arch=$(arch)
        if [ "$arch" == "x86_64" ]; then
            arch=amd64
        fi
        
        if [ "$arch" == "i686" ]; then
            arch=i386
        fi
        
        if [ "$arch" == "armv5tel" ]; then
            arch=armel
        fi
        
        echo "Checking cache download in $cache/rootfs-$arch ... "
        if [ ! -e "$cache/rootfs-$arch" ]; then
            download_debian $cache $arch
            if [ $? -ne 0 ]; then
                echo "Failed to download 'debian base'"
                return 1
            fi
        fi
        
        copy_debian $cache $arch $rootfs
        if [ $? -ne 0 ]; then
            echo "Failed to copy rootfs"
            return 1
        fi
        
        return 0
    
    ) 200>/var/lock/subsys/lxc
    
    return $?
}

copy_configuration()
{
    path=$1
    rootfs=$2
    name=$3
    
    cat <<EOF >> $path/config
    lxc.tty = 4
    lxc.pts = 1024
    lxc.rootfs = $rootfs
    lxc.cgroup.devices.deny = a
    # /dev/null and zero
    lxc.cgroup.devices.allow = c 1:3 rwm
    lxc.cgroup.devices.allow = c 1:5 rwm
    # consoles
    lxc.cgroup.devices.allow = c 5:1 rwm
    lxc.cgroup.devices.allow = c 5:0 rwm
    lxc.cgroup.devices.allow = c 4:0 rwm
    lxc.cgroup.devices.allow = c 4:1 rwm
    # /dev/{,u}random
    lxc.cgroup.devices.allow = c 1:9 rwm
    lxc.cgroup.devices.allow = c 1:8 rwm
    lxc.cgroup.devices.allow = c 136:* rwm
    lxc.cgroup.devices.allow = c 5:2 rwm
    # rtc
    lxc.cgroup.devices.allow = c 254:0 rwm
    
    # mounts point
    lxc.mount.entry=proc $rootfs/proc proc nodev,noexec,nosuid 0 0
    lxc.mount.entry=devpts $rootfs/dev/pts devpts defaults 0 0
    lxc.mount.entry=sysfs $rootfs/sys sysfs defaults  0 0
    
    # networking
    
    lxc.utsname = $name
    lxc.network.type = veth
    lxc.network.flags = up
    lxc.network.link = br0
    lxc.network.ipv4 = 10.1.1.2/24
    lxc.network.ipv4.gateway = 10.1.1.1
    lxc.network.hwaddr = 00:1E:$(hex):$(hex):$(hex):$(hex)
    EOF
    
    if [ $? -ne 0 ]; then
        echo "Failed to add configuration"
        return 1
    fi
    
    return 0
}

# nice trick from: http://mindref.blogspot.com/2011/01/debian-lxc-create.html
hex()
{
    echo "`tr -dc A-F0-9 < /dev/urandom | head -c 2 | xargs`"
}

clean()
{
    cache="/var/cache/lxc/debian-wheezy"
    
    if [ ! -e $cache ]; then
        exit 0
    fi
    
    # lock, so we won't purge while someone is creating a repository
    (
    flock -n -x 200
    if [ $? != 0 ]; then
        echo "Cache repository is busy."
        exit 1
    fi
    
    echo -n "Purging the download cache..."
    rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
    exit 0
    
    ) 200>/var/lock/subsys/lxc
}

usage()
{
    cat <<EOF
    $1 -h|--help -p|--path=<path> --clean
    EOF
    return 0
}

options=$(getopt -o hp:n:c -l help,path:,name:,clean -- "$@")
if [ $? -ne 0 ]; then
    usage $(basename $0)
    exit 1
fi
eval set -- "$options"

while true
do
    case "$1" in
        -h|--help)      usage $0 && exit 0;;
        -p|--path)      path=$2; shift 2;;
        -n|--name)      name=$2; shift 2;;
        -c|--clean)     clean=$2; shift 2;;
        --)             shift 1; break ;;
        *)              break ;;
    esac
done

if [ ! -z "$clean" -a -z "$path" ]; then
    clean || exit 1
    exit 0
fi

type debootstrap
if [ $? -ne 0 ]; then
    echo "'debootstrap' command is missing"
    exit 1
fi

if [ -z "$path" ]; then
    echo "'path' parameter is required"
    exit 1
fi

if [ "$(id -u)" != "0" ]; then
    echo "This script should be run as 'root'"
    exit 1
fi

rootfs=$path/rootfs

install_debian $rootfs
if [ $? -ne 0 ]; then
    echo "failed to install debian"
    exit 1
fi

configure_debian $rootfs $name
if [ $? -ne 0 ]; then
    echo "failed to configure debian for a container"
    exit 1
fi

copy_configuration $path $rootfs $name
if [ $? -ne 0 ]; then
    echo "failed write configuration file"
    exit 1
fi

if [ ! -z $clean ]; then
    clean || exit 1
    exit 0
fi

Attention à la ligne 65, il faut bien évidemment changer le mot de passe, soit dans le template lui-même, soit dans le conteneur une fois déployé.

Pour le reste, libre à vous d’adapter le script, en particulier les lignes 74 à 85 (paquets installés par défaut) et les lignes 179 à 212 qui contiennent le paramétrage du conteneur, en particulier la configuration réseau :

lxc.network.type = veth #type réseau pour le conteneur (empty/veth/vlan/macvlan/phys)
lxc.network.flags = up #la carte monte au démarrage
lxc.network.link = br0 #elle est attachée à l'interface br0 de l'hôte
lxc.network.ipv4 = 10.1.1.2/24 #son IP/masque
lxc.network.ipv4.gateway = 10.1.1.1 #le routeur par défaut
lxc.network.hwaddr = 00:1E:$(hex):$(hex):$(hex):$(hex) #une adresse physique aléatoire

Le paquet LXC vient avec toute une panoplie d’outils de gestion des conteneurs, entre autre :

  • lxc-create – déployer un conteneur
  • lxc-ls – lister les conteneurs déployés
  • lxc-list – lister le status des conteneurs
  • lxc-start – démarrer un conteneur
  • lxc-stop – arrêter un conteneur
  • lxc-console – « entrer » dans un conteneur
  • lxc-destroy – supprimer un conteneur
  • Par exemple pour créer un conteneur :
lxc-create -n mon.premier.conteneur -t debian-wheezy
  • On peut modifier sa configuration en éditant le fichier :
/var/lib/lxc/mon.premier.conteneur/config
  • On démarre le conteneur avec :
lxc-start -n mon.premier.conteneur
  • On se connecte à la console avec :
lxc-console mon.premier.conteneur

Pour quitter la console il faut faire CTRL+a, q

  • On arrête le conteneur avec :
lxc-stop -n mon.premier.conteneur
  • On le supprime avec :
lxc-destroy -n mon.premier.conteneur
  • Pour qu’un conteneur démarre avec l’hôte, il suffit de créer un lien vers son fichier « config » dans /etc/lxc/auto/ :
ln -s /var/lib/lxc/mon.premier.conteneur/config /etc/lxc/auto/mon.premier.conteneur

Quelques recommandations pour terminer :

  • l’utilisation de LVM est fortement recommandée, ne serait ce que pour faire des sauvegardes à chaud;
  • il vaut mieux laisser les conteneurs dans l’emplacement par défaut (/var/lib/lxc),
  • donc il est recommandé de faire un point de montage sur ce dossier
Sources :

VPS – Installation de Linux-VServer

Comme je vous l’ai expliqué dans mon précédent article, je suis entrain de faire l’installation d’une petite architecture à base de Linux-VServer pour le travail, en parallèle je fais la même chose à titre perso, c’est l’objet de cet article.

En quelques mots, vserver est un système de virtualisation en espace utilisateur, c’est à dire qui fonctionne directement sur le noyau de la machine hôte, ce qui assure d’excellentes performances. En contre partie, ce type de virtualisation ne permet de faire tourner que du Linux sur du Linux. On appelle aussi cela des conteneurs.

Voici comment installer Linux-VServer sur une Debian Squeeze 64bits, ça sera très rapide car il n’y a pas grand chose à dire pour l’installation à proprement parler, pour ce qui est de l’utilisation, c’est autre chose, mais pas nécessairement compliqué, c’est surtout une histoire de bon sens.

Au travail, pour installer un serveur, j’utilise des modèles, sinon je fais toujours l’installation en mode expert avec le minimum de paquets et en UTF-8 US (clavier fr).

Pour les serveurs destinés à la production, j’utilise toujours les paquets Debian de la branche main avec aptitude. Les branches contrib et non-free sont rarement nécessaires. Pour mes tests ou mes usages perso, je suis moins strict (dotdeb, backport, …).

Pour la suite, je fais tout avec un utilisateur qui a les droits root (c’est mal).

Si vous ne l’avez pas fait pendant l’installation, il faut maintenant remplacer le noyau par sa version patchée avec vserver, on en profite pour ajouter les outils de gestion :

aptitude install linux-image-vserver-amd64 util-vserver vserver-debiantools

En ce qui me concerne, je ne souhaite pas que mes vservers soient directement accessibles depuis le réseau, je préfère utiliser une interface « dummy » et faire du routage avec la machine hôte.
Mes vservers sont totalement isolés du monde extérieur, c’est Netfilter (avec du snat et du dnat) qui va décider de qui peut communiquer avec qui.

echo 'dummy' >> /etc/modules
echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/ipv4_forward.conf
echo '#interface dummy pour les vservers' >> /etc/network/interfaces
echo 'auto dummy0' >> /etc/network/interfaces
echo 'iface dummy0 inet static' >> /etc/network/interfaces
echo 'address 10.1.1.1' >> /etc/network/interfaces
echo 'netmask 255.255.255.0' >> /etc/network/interfaces

A ceci j’ajoute une règle de SNAT dans mon fichier /etc/iptables.up.rules (table nat) :

-A POSTROUTING -s 10.1.1.0/24 ! -d 10.1.1.0/24 -j SNAT --to-source LA_VRAI_IP_DU_SERVEUR

Notez que les sockets réseau sont partagés entre l’hôte et les vservers, il faut donc veiller à bien configurer chaque programme pour qu’il écoute sur la bonne adresse, dit autrement, il faut éviter de laisser les paramètres « listen » sur any (ou équivalent) à moins de savoir ce que l’on fait.

En gros, un

netstat -luntp | awk '{print $4}' | egrep '127.0.0.1|0.0.0.0'

ne devrait rien retourner.

Par exemple si vous laisser Apache faire, il utilisera le port 80 sur toutes les interfaces (celles de l’hôte comme celles des vservers).

Attention à la sécurité tout de même, pensez à jouer un peu avec iptables pour demander à netfilter de protéger tel ou tel socket des méchants du dehors.

On redémarre sur le nouveau noyau et c’est fini.
On vérifie qu’on est bien sur le bon noyau avec

uname -r

2.6.32-5-vserver-amd64

Pour ma part je ne change rien à la configuration de vserver, je préfère faire mes propres scripts de déploiement. J’initialise simplement le numéro de contexte des vservers à 100 afin de pouvoir m’en servir dans un script d’automatisation.

echo ‘100’ > /etc/vservers/.defaults/context.next

Créer un vserver de type Debian sur une Debian est très simple, notez simplement qu’un certain nombre de paramètres sont hérités de la machine hôte, entre autre le fichier resolv.conf, donc si vous avez « nameserver 127.0.0.1 » vous allez avoir un problème.
Vous pouvez créer des vservers depuis plusieurs distributions, vous trouverez plus d’informations ici.
Les commandes sont très simple, mais pour gagner en temps et éviter les oublis, je préfère faire des scripts.
Commençons par créer un script de création de modèle, modèle qui servira de base à nos futurs vservers.

#!/bin/bash
if [[ ($1 == "") ]]
then
    echo "Syntaxe : $0 nom_du_vserver"
    echo "Exemple : $0 template-squeeze"
    exit
fi

VSERVER_ROOT='/home/vservers'
VSERVER_NET='10.1.1'
VSERVERS_IFACE='dummy0'

DEBIAN_MIRROIR='http://ftp.fr.debian.org/debian'
DEBIAN_DIST='squeeze'

CONTEXT_NEXT=`cat /etc/vservers/.defaults/context.next`
newCONTEXT_NEXT=$(($CONTEXT_NEXT+1))

VSERVER_TEMPLATE_NAME="$1-$CONTEXT_NEXT"
VSERVER_TEMPLATE_IP="$VSERVER_NET.$CONTEXT_NEXT"
VSERVER_TEMPLATE_PATH="$VSERVER_ROOT/$VSERVER_TEMPLATE_NAME"

vserver $VSERVER_TEMPLATE_NAME build --hostname $VSERVER_TEMPLATE_NAME --interface $VSERVERS_IFACE=eth0:$VSERVER_TEMPLATE_IP/24 --rootdir $VSERVER_ROOT -m debootstrap -- -d $DEBIAN_DIST -m $DEBIAN_MIRROIR

echo $CONTEXT_NEXT > /etc/vservers/$newVSERVER_NAME/context
echo $newCONTEXT_NEXT > /etc/vservers/.defaults/context.next

cat /etc/apt/apt.conf > $VSERVER_TEMPLATE_PATH/etc/apt/apt.conf
cat /etc/apt/sources.list > $VSERVER_TEMPLATE_PATH/etc/apt/sources.list

vserver $VSERVER_TEMPLATE_NAME start
vserver $VSERVER_TEMPLATE_NAME exec apt-get -y remove --purge isc-dhcp-client isc-dhcp-common
vserver $VSERVER_TEMPLATE_NAME exec apt-get update
vserver $VSERVER_TEMPLATE_NAME exec apt-get -y dist-upgrade
vserver $VSERVER_TEMPLATE_NAME exec apt-get -y install locales
echo 'en_US.UTF-8 UTF-8' >> $VSERVER_TEMPLATE_PATH/etc/locale.gen
vserver $VSERVER_TEMPLATE_NAME exec /usr/sbin/locale-gen
vserver $VSERVER_TEMPLATE_NAME exec apt-get -y autoremove
vserver $VSERVER_TEMPLATE_NAME exec apt-get -y autoclean
vserver $VSERVER_TEMPLATE_NAME exec apt-get -y clean
vserver $VSERVER_TEMPLATE_NAME stop
exit

Vous pouvez configurer votre modèle afin d’y inclure les logiciels qui vous servent systématiquement, adapter certaines configurations, … Le principe d’un modèle est que tout ce qui est fait n’est plus à refaire. Il ne faut donc pas hésiter à y passer du temps.

Maintenant qu’on a notre modèle, on va pouvoir créer des vservers bon à l’usage.
Je recommande de faire des scripts d’automatisation par type de vserver (web, mysql, xmpp, …), c’est plus facile à manipuler et ça permet de les réutiliser à la manière de classes dans un programme.

A titre d’exemple, voici la version super allégée de celui que j’utilise pour déployer un vserver avec Apache2 et PHP5 :

#!/bin/bash
if [[ $1 == "" ]]
then
    echo "Syntaxe : $0 nom_du_vserver"
    echo "nom_du_vserver doit être unique"
    echo "Exemple : $0 apache2-php5"
    exit
fi

#Pensez à adapter cette variable
VSERVER_TEMPLATE_NAME='template-squeeze'

HOST_FQDN=`hostname -f`

VSERVER_ROOT='/home/vservers'
VSERVER_NET='10.1.1'

CONTEXT_NEXT=`cat /etc/vservers/.defaults/context.next`
newCONTEXT_NEXT=$(($CONTEXT_NEXT+1))

newVSERVER_NAME="$1-$CONTEXT_NEXT"
newVSERVER_PATH="$VSERVER_ROOT/$newVSERVER_NAME"
newVSERVER_IP="$VSERVER_NET.$CONTEXT_NEXT"

PKG_DEBIAN='apache2 libapache2-mod-php5'
CMD_POST_INST='/etc/init.d/apache2 stop'
#
echo "Copie du template"
dupvserver --from $VSERVER_TEMPLATE_NAME --to $newVSERVER_NAME --ip $newVSERVER_IP --vsroot $VSERVER_ROOT
echo "Copie terminée, configuration du nouveau vserver"

#######NAME
echo "127.0.0.1 localhost" > $newVSERVER_PATH/etc/hosts
echo "$newVSERVER_IP $newVSERVER_NAME" >> $newVSERVER_PATH/etc/hosts
echo "$newVSERVER_NAME" > $newVSERVER_PATH/etc/hostname

#######AUTOSTART
echo "default" > /etc/vservers/$newVSERVER_NAME/apps/init/mark
#Mise à jour des contextes
echo $CONTEXT_NEXT > /etc/vservers/$newVSERVER_NAME/context
echo $newCONTEXT_NEXT > /etc/vservers/.defaults/context.next
#
echo "Démarrage du vserser $newVSERVER_NAME"
vserver $newVSERVER_NAME start
vserver $newVSERVER_NAME exec apt-get update
vserver $newVSERVER_NAME exec apt-get -y dist-upgrade
vserver $newVSERVER_NAME exec apt-get -y install $PKG_DEBIAN
vserver $newVSERVER_NAME exec $CMD_POST_INST

echo "!! Pensez à configurer les paramètres d'écoute d'Apache !!"
echo "Ici j'utilise toute une batterie de .patch pour modifier les fichiers de configuration d'apache et de php"

exit

Pour manipuler vos vservers, vous avez 2 méthodes.

  1. depuis l’hôte en modifiant directement les fichiers (le / des vservers se trouve dans /home/vservers/NOM/) et en lançant des commandes avec vserver NOM exec commande, c’est ce que je fais dans mon script.
  2. dans le vserver en vous y connectant en ssh (si vous l’avez installé) ou en entrant dedans avec vserver NOM enter (vous arrivez directement en root à la racine)

A vous de jouer, pour ma part je suis entrain de cloisonner tous les sites et services que j’ai sur ma Dedibox perso dans des vservers, celui qui héberge ce site est le numéro 3.

VPS – Serveur dédié virtuel

Comme je ne sais pas par où commencer dans mon rangement, je vais donc noter ici ce sur quoi je travaille en ce moment : vserver

Dans le cadre de mon travail, on m’a demandé d’étudier les différentes solutions d’hébergement « vite fait et pas cher ». L’objectif est d’offrir à certains utilisateurs la possibilité, d’avoir leur propre espace Web perso, accessible de partout et surtout sans que ça nécessite des ressources de support, en gros du clefs en main.

La suite est une petite histoire qui n’intéressera probablement que ceux qui travaillent dans un métier d’administration système ou de support IT.

Quelques points de détails font qu’on ne peut pas décemment leur dire d’aller chez le premier hébergeur venu :

  • ces sites sont à vocation professionnelle
  • ces utilisateurs sont des VIP (tout est relatif…)

Actuellement, quand l’un des ces utilisateurs veut un tel espace, il y a en gros 3 cas de figure, qui s’enchainent (de 1 vers 3 et de 3 vers 1) :

  1. il fait ça dans son coin (sur un hébergement perso la plupart du temps, parfois sur du semi pro)
  2. il demande un espace sur un coin de serveur
  3. il se plaint qu’on ne lui propose pas d’office un tel outil de travail

Dans tous les cas ça nous (service info) pose des problèmes de sécurité et/ou de ressources en support à plus ou moins court terme : l’utilisateur demande une intégration de son site aux sites internes, il souhaite avoir une URL @corp, il n’arrive pas à déménager son site chez un autre hébergeur, on ne peut pas lui laisser toute la latitude qu’il souhaite sur nos serveurs (question de sécurité), nous sommes des incompétents …

J’ai donc fait une étude rapide sur les offres d’hébergement du marché (OVH, 1&1, Online, Amen …).

Sur beaucoup de points ces offres semblaient répondre aux besoins, mais elles avaient toutes le même talon d’Achille, elles nous auraient couté très chez en temps de support (gestion des comptes, création des bases SQL, configuration DNS, sauvegardes, …). Il aurait donc fallut acheter un hébergement par utilisateur (et là c’est le cout administratif qui aurait explosé).

En gros les offres d’hébergement mutualisé c’est bien quand ce n’est pas mutualisé.

J’ai donc regardé la possibilité de le faire en interne. La problématique est la suivante :

  1. pour chaque utilisateur qui en fait la demande, on doit offrir un espace de 1Go (donc avec une gestion des quotas), une base de donnée, un serveur Web, un interpréteur PHP et un accès en FTP
  2. l’adresse doit être du type http://serveur.domaine.tld/LOGIN (domaine étant ici l’un de nos noms de domaines)
  3. le déploiement d’un espace totalement opérationnel et configuré ne doit pas prendre plus de 5min (donc ça doit être scriptable)
  4. le service doit être simple à l’usage pour les utilisateurs (le plus proche possible ce que l’on trouve chez un hébergeur grand public)
  5. l’utilisateur doit pouvoir déployer les outils classiques (wordpress, joomla, drupal, sugar, …) de manière autonome
  6. le système doit être sécurisé, un utilisateur ne doit pas pouvoir accéder aux données d’un autre (pondéré par la sécurité du mot de passe)
  7. la mise en place du système (documentations et backups compris) ne pas pas prendre plus de 2 jours d’ingénierie
  8. le tout sur un seul serveur avec une seule IP et dans une DMZ public dédiée

Indépendamment les uns des autres, ces points sont simples à respecter, mais les mettre tous ensemble relève du casse tête.

Pour le 1, pas de problèmes pour le serveur Web (il suffit de l’installer) ni pour le FTP (on peut facilement chrooter les utilisateurs), mais PHP pose un sérieux problème de sécurité en environnement mutualisé. En quelques lignes, on accède (au moins) à tout ce qui est accessible par le serveur Web, à commencer par les données des autres utilisateurs, ce qui entre en conflit avec le point 6. Si on sécurise d’avantage PHP (open_basedir, disable_functions, …), le point 5 ne peut pas être respecté.

J’ai donc cherché une autre approche, virtualiser tout ça, sur un seul serveur avec un reverse proxy et un peu de SNAT.

Il existe plusieurs types de virtualisation, on dispose d’ailleurs d’une ferme ESX, mais le point 8 en réduit l’utilité.Je suis donc partie sur une solution indépendante, autonome et bien plus efficace en terme de ressource : le VPS.

J’ai évalué 3 techno de VPS :

  • LXC : plein de promesses, mais j’ai eu un bug et mon délai de mise en place de la solution était limité
  • OpenVZ : trop long à configurer, j’aurai passé trop de temps à faire une documentation d’exploitation pour mes collègues
  • Linux-VServer : moins puissant que les deux précédent, mais très simple et très rapide à mettre en place

J’ai donc opté pour Linux-VServer dans l’architecture suivante :

  • une Debian Squeeze avec le noyau vserver
  • nginx en reverse proxy
  • un peu d’iptables pour la sécurité et le SNAT
  • un vserver dédié à MySQL
  • un modèle de vserver avec Apache2 et PHP5 configurés
  • un système de déploiement du modèle

La mise en place de l’architecture (installation, configuration, backup, logs, template, scripts de déploiement, …) peut se faire en 2 heures, plus environ autant pour la documentation d’exploitation.

Il me reste encore à peaufiner quelques points pour l’automatisation totale du déploiement, notamment mettre une interface devant mon script de déploiement et ajouter un petit module de stats propre à chaque utilisateur, mais je pense que c’est une technologie que je vais faire rentrer de plus en plus dans notre DataCenter.

Pour le détail de l’installation, c’est un autre article.