Mettre en place un serveur Owncloud mutualisé

Dans le cadre de mon stage (toujours en cours à l’heure où j’écris ces lignes), une réflexion a été engagé sur la meilleure méthode pour proposer, de façon sécurisé, de l’Owncloud en mutualisé. Autrement dit, pouvoir héberger les données de plusieurs clients sur une même machine virtuelle Linux en cloisonnant les installations d’Owncloud.

Pour diverses raisons, le choix a été fait de rester sur un déploiement « classique » d’une couche LAMP sous CentOS

A travers ce billet, je vais détailler la mise en place d’un Owncloud mutualisé en s’appuyant sur Docker, un système de containers pour Linux à la mode. Je m’appuierais ici sur un Ubuntu virtualisé mais ce tutoriel est transposable à n’importe quelle distribution.

Présentation

Rappelons tout d’abord ce qu’est et implique un serveur mutualisé:

  • Plusieurs utilisateurs sont hébergés sur le même serveur => Importance d’isoler / cloisonner les comptes
  • Les ressources sont mutualisés => Un utilisateur qui « consomme » trop peut impacter ses voisins si des limites de ressources ne sont pas définies
  • Le piratage d’un compte utilisateur peut permettre au pirate, si le serveur n’est pas correctement sécurisé, d’accéder aux données des autres utilisateurs
  • Le piratage du serveur lui-même touche forcément l’ensemble des utilisateurs

Vous l’aurez compris, la sécurité est primordiale.

Plutôt que de partir sur une couche LAMP, nous utiliserons les technologies suivantes:

  • NginX, un serveur web léger, parfait pour répartir les requêtes vers nos containers (haproxy aurait aussi pu faire l’affaire)
  • MariaDB, un fork de MySQL offrant de meilleurs performances et quelques différences
  • Docker, un système de container simple à configurer et à déployer et s’appuyant sur LXC (LinuX Container)
  • LVM servira à limiter l’espace disque pour chaque Owncloud. D’autres solutions existent mais celle-ci a l’avantage d’être native.

Le fonctionnement va être le suivant:

  • Le serveur MariaDB / MySQL sera partagé pour l’ensemble des utilisateurs / clients. Une instance par client aurait été idéale mais il est bien trop gourmand en RAM et CPU.
  • NginX, servira à répartir les requêtes en fonction du nom de domaine vers le bon container.
  • Chaque container, un par installation d’Owncloud, exécutera Apache2 avec PHP en DSO.

Dans le cadre de ce tutoriel, notre machine virtuelle portera l’IP 192.168.134.128 et utilisera la version 14.04 LTS d’Ubuntu. La version d’Owncloud que nous installerons sera la 6.0.3 et nous en aurons deux exemplaires: cloud-1.sdujancourt.me et cloud-2.sdujancourt.me.

LNM

Commençons par installer notre couche LNM: Linux NginX MariaDB.

Chose particulièrement importante, le serveur doit être à l’heure. Il est donc important d’avoir un daemon NTP qui tourne pour la synchroniser au besoin:

apt-get install -y ntp

La version d’NginX inclut dans le repository d’Ubuntu fera parfaitement l’affaire:

apt-get install -y nginx

Nous allons par contre avoir besoin d’ajouter un nouveau repository pour MariaDB:

apt-get install -y software-properties-common
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
add-apt-repository 'deb http://ftp.igh.cnrs.fr/pub/mariadb/repo/5.5/ubuntu trusty main'

Ne reste qu’à installer le packet mariadb-server:

apt-get update
apt-get install mariadb-server mariadb-client

Nous en avons (déjà) fini pour NginX et MariaDB. Place au stockage.

LVM

Comme expliqué en introduction, nous allons placer les données de chaque client dans des volumes LVM. Ils ne pourront ainsi jamais dépasser l’espace disque qui leur ai alloué.

Dans le cadre de ce tutoriel, j’ai ajouté un second disque de 20 Go à ma machine virtuelle que je dédie aux données des clients.

J’ai écrit récemment un article sur LVM, que je vous invite évidemment à consulter, je me contenterais ici de vous donner les commandes en brut:

pvcreate /dev/sdb

# VG dédié aux clients
vgcreate vg-data /dev/sdb

# Premier compte client
lvcreate -L 2G -n lv-cloud-1 vg-data 
mkfs.ext4 /dev/vg-data/lv-cloud-1

# Deuxième compte client
lvcreate -L 2G -n lv-cloud-2 vg-data 
mkfs.ext4 /dev/vg-data/lv-cloud-2

Résultat: un groupe de volumes vg-data de 20G avec deux partitions logiques cloud-1 et cloud-2 de 2G chacune.

Il ne reste qu’à leurs trouver un point de montage (ce sera /data) et les monter:

mkdir -p /data/cloud-{1,2}
mount /dev/vg-data/lv-cloud-1 /data/cloud-1
mount /dev/vg-data/lv-cloud-2 /data/cloud-2

Docker

Docker est une application très facile à prendre en main pour créer des containers:

  1. Dans un premier temps, on décrit l’image dans un fichier Dockerfile:
    • La base de départ (une distribution ou une autre image)
    • Les changements à lui apporter à coup de RUN (exécuter une commande) et ADD (ajouter un fichier)
    • Les ports que le container va exposer, càd qui devront être accessibles en dehors à l’extérieur
    • LA commande à exécuter lorsque le container démarre. J’insiste sur ce dernier point car cette limitation va nous obliger à utiliser supervisord, un petit programme pour… lancer et surveiller d’autres programmes au sein de notre container
  2. Ce fichier Dockerfile est ensuite « compilé » pour donner place à une image que l’on va pouvoir reproduire à l’infini. Il y a cependant une grosse différence avec un template VMware (par exemple): l’espace disque n’est utilisée qu’une seule fois ! Grâce à un système de fichier dénommé AuFS, seules les différences avec l’image de référence (le modèle) sont enregistrées pour chaque container, un gain de place énorme !
  3. Il suffira ensuite de créer autant de containers que souhaités en utilisant à chaque fois notre image comme base.

Il mériterait à lui seul plusieurs tutoriels.

Docker est fourni sous Ubuntu dans le repository universe sous le nom docker.io. Installons-le:

# On se base sur la distribution Ubuntu Trusty (14.04)
FROM ubuntu:trusty

# Activation du repository universe d'Ubuntu
# Nous allons avoir besoin de ce repository pour supervisord (voir plus bas)
RUN echo "deb http://fr.archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list

# Met à jour Ubuntu
RUN apt-get update
RUN apt-get upgrade -y

# Ajout d'Apache2 et PHP
# RUN exécute la commande lors de la création de l'image
# DEBIAN_FRONTEND=noninteractive désactive les questions à la configuration
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y apache2 php5 php5-gd php-xml-parser php5-intl php5-sqlite php5-mysql smbclient curl libcurl3 php5-curl

### Configuration d'Owncloud

# Ajout d'Owncloud, extrait à partir de son archive
ADD owncloud /usr/share/owncloud

# Alias pour /usr/share/owncloud/{config,data} vers /data
# Cela nous permettra de mapper par la suite notre /data/cloud-X sur l'hôte vers le /data du container
RUN ln -sf /data/config /usr/share/owncloud/config
RUN ln -sf /data/data /usr/share/owncloud/data

# Ajout du fichier de configuration pour Apache
ADD owncloud.conf /etc/apache2/conf.d/owncloud.conf

# Redirection / vers /owncloud
ADD index.html /var/www/index.html

# On active le module version à Apache2
RUN a2enmod version

# On relance le service Apache2
RUN service apache2 reload

### Configuration de Supervisor

# Installation du package correspondant
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y supervisor

# On commence par créer un dossier pour qu'il place ses logs
RUN mkdir -p /var/log/supervisor

# On lui fournit ensuite son fichier de configuration
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf

# Expose le port 80 (Apache)
# Le fait que ce port soit déjà utilisé par NginX n'a pas d'importance car
# nous dirons à Docker de faire une translation de port. NginX pourra
# ainsi communiquer avec Apache via un autre port
EXPOSE 80

# Commande à exécuter au lancement du container
# Ce sera supervisord qui lancera par la suite Apache
CMD ["/usr/bin/supervisord"]

En utilisant l’instruction ADD, Docker va aller chercher dans le répertoire courant un fichier supervisord.conf pour le placer dans le /etc/supervisor/conf.d du container. Il va donc falloir le créer avec ce contenu:

[supervisord]
nodaemon=true

[program:apache2]
command=/bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2 -DFOREGROUND"

L’un des rôles de supervisord est également de surveiller si les programmes indiqués s’exécutent toujours. Si Apache2 plante, supervisor ira le relancer et le notifiera dans son fichier de log.

Faisons de même avec index.html:


        


Idem avec owncloud.conf qui va indiquer à Apache d’aller chercher Owncloud dans /usr/share/owncloud:

Alias /owncloud /usr/share/owncloud


    Options +FollowSymLinks
    AllowOverride All
    <IfVersion 
        order allow,deny
        allow from all
    
    = 2.3>
        Require all granted
    

Pour terminer, téléchargeons une archive d’Owncloud et décompressons-le pour qu’elle soit incluse par Docker dans /usr/share/owncloud:

wget http://download.owncloud.org/community/owncloud-6.0.3.tar.bz2
tar xf owncloud-6.0.3.tar.bz2

Nous aurons au final les fichiers suivants pour notre image:

Dockerfile
index.html
owncloud
owncloud.conf
supervisord.conf

Ne reste plus qu’à générer l’image:

docker build -t sdujancourt/owncloud .

Retenez simplement que la nomenclature pour le nom d’une image est nom-de-l’auteur/nom-de-l’image. J’ai (sdujancourt) donc créé une image owncloud. Ne reste plus qu’à patienter pendant que l’image soit générée.

Préparer les containers

Maintenant que notre image est prête, nous allons pouvoir nous attaquer à la mise en place de chaque container.

Commençons par préparer /data/cloud-X en y créant deux répertoires config et data avec les bons droits:

mkdir -p /data/cloud-1/{config,data}
cp owncloud/config/config.sample.php /data/cloud-1/config/config.php
chown 33:33 /data/cloud-1/config/config.php
chown 33:33 /data/cloud-1/data

Créons ensuite notre container avec la commande docker run:

docker run --publish=127.0.0.1:41080:80 --detach=true --volume=/data/cloud-1:/data sdujancourt/owncloud

Quelques explications:

  • publish va rendre accessible le port 80 du container sur le port 41080 de l’hôte en local (127.0.0.1)
  • detach=true va exécuter le container en arrière plan (sans interaction). En retirant cette option, vous verrez votre container démarrer et pourrez le quitter avec Ctrl+C.
  • volume va mapper le répertoire /data/cloud-1 vers le /data du container

Le container fonctionne à présent en arrière plan. Ne reste qu’à configurer notre nginX pour qu’il rende notre premier Owncloud accessible depuis l’extérieur. Créez un nouveau fichier /etc/nginx/sites-enabled/owncloud avec le contenu suivant:

server {
    listen 80;
    listen [::]:80 ipv6only=on;

    #ssl_certificate /etc/nginx/certs/demo.pem;
    #ssl_certificate_key /etc/nginx/certs/demo.key;

    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    server_name cloud-1.sdujancourt.me;

    location / {
        proxy_pass http://127.0.0.1:41080;
        include /etc/nginx/proxy_params;
    }
}

Seules deux lignes sont à changer pour chaque nouveau container:

  • server_name qui indique le nom de domaine
  • proxy_pass qui indique le port à lequel passer les requêtes

Appliquez ensuite la configuration:

service nginx reload

En se rendant sur http://cloud-1.sdujancourt.me/owncloud/, nous arrivons sur la page d’installation:
2014-06-10 12_15_21

Après avoir créer un utilisateur et sa base sur MariaDB / MySQL depuis l’hôte, saisissez-les sur cette page et modifiez le nom d’hôte à 172.17.42.1. Petite explication: chaque container a sa propre interface réseau et l’hôte est accessible depuis 172.17.42.1. A noter que selon votre configuration réseau, l’IP peut varier car Docker essaye de trouver une plage IP libre.

Le container est prêt La manipulation est à répéter pour chaque nouvelle installation d’Owncloud avec son port et sa partition LVM dédiée (ou pas).

Et après ?

Voici quelques idées:

  • Utiliser docker-gen pour générer automatiquement la configuration de NginX
  • Scripter la création des répertoires config et data dans /data/cloud-X
  • Scripter le lancement automatique des containers au démarrage via init.d

Concernant la gestion des mises à jour d’Owncloud, il suffit de mettre à jour le répertoire owncloud dans le répertoire où est placé Dockerfile, de re-générer l’image et de re-créer les containers. Aucune donnée ne sera perdue car les données sont stockées sur un volume externe au container (c’est son intérêt).

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s