P24 Nuage pour sites Web

De Wiki d'activités IMA


Cahier des charges

Présentation générale du projet

Contexte

Objectif du projet

Installer une infrastructure infonuagique pour la création de sites Web école.

Description du projet

Le but est d'installer une infrastructure infonuagique sur des machines de la plate-forme informatique permettant la création aisé d'un site Web pour un usager de l'école.

Docker-logo.jpg

La couche de supervision peut être openstack installé avec un noeud contrôleur et un noeud réseau dans deux machines virtuelles.

La solution de virtualisation sera à base de conteneurs pour limiter la consommation mémoire et CPU. Vous pouvez commencer par étudier la solution Docker.

Une image de processus serveur Web avec une configuration standard (incluant PHP) doit être fournie.

L'architecture proposée ne doit consommer qu'une adresse IPv4 routée pour l'ensemble des sites Web et permettre des accès IPv4 et IPv6 et implanter HTTP comme HTTPS. La configuration du nom du site Web doit être très facile.


Avancement du Projet

Semaine 1 (14/09/2015)

  • Entretien avec M.Redon
  • Recherches sur la virtualisation, LXC, Docker et Openstack
  • Analyse de la portée du projet : 900 sites existant au total, moins de 200 qui sont actifs
  • Aucun matériel a acheter !

Semaine 2 (21/09/2015)

  • Premiers essais avec Docker
    • Création d'un processus isolé contenant linux
    • Test de sauvegarde et manipulation des images générées

Semaine 3 (28/09/2015)

  • Contact avec un intervenant extérieur : Alexandre chojnacki
  • Suite des tests avec Docker
  • Début des recherches sur le serveur Apache
  • Familiarisation avec les Dockerfiles

Semaine 4 (05/10/2015)

  • Suite des recherches et tests sur le serveur Apache
  • Architecture réseau des containers de docker
    • La première interface virtuelle "docker0" qui reçoit toutes les adresses en 172.17.0.0/16
    • Les paquets sont envoyés vers l'interface de l'adresse en question "veth7fe8a26"
    • Cette deuxième interface envoie les paquets vers l'interface "eth0" du container
  • Pause des recherches sur OpenStack
    • A confirmer avec A.Chojnacki, mais Docker peut suffire pour notre utilisation

Semaine 5 (12/10/2015)

  • Utilisation d'OpenStack qui semble ne pas être indispensable --> on met cet outil de côté
  • Recherches sur la para virtualisation et l'utilisation de l'hyperviseur xen.
  • Idée : lancer des dockers dans des machines virtuelles xen (à méditer)
  • DELL poweredge 2950 (specs)
    • Réparation d'un dissipateur (Images à venir)
    • Machine à priori opérationnel, attente de plus d'infos pour sa mise en route (où, comment...)

Semaine 6 (19/10/2015)

Résultat des discussion avec A.Chojnacki
hardware > hypervisor > Docker host > container
  • Machine DELL opérationnelle mais en attente (anciennes données encore dessus)
  • Prise en main de xen

Semaine 7 (26/10/2015)

How a VM works
How docker works

Semaine 8 (02/11/2015)

  • Remise en question du modèle précédent : lourdeur inutiles. Juste Docker suffit.
  • Installation de Debian (Jessie) sur la machine Dell PowerEdge
  • Installation des services utiles (ssh, Docker)

Semaine 9 (09/11/2015)

Mise en place du serveur, opérationnel.

172.26.64.13

Création des 10 VM qui nous seront nécessaires

VM XEN
IP addr
jinx 172.26.79.230
thresh 172.26.79.231
fizz 172.26.79.232
nidalee 172.26.79.233
vayne 172.26.79.234
teemo 172.26.79.235
rengar 172.26.79.236
ezreal 172.26.79.237
ziggs 172.26.79.238
shaco 172.26.79.239

Semaine 10 (16/11/2015)

Comment fonctionne notre système ?

Notre serveur rift en 172.26.64.13 Sur ce serveur :

  • Une petite dizaine de machines virtuelles xen dans la fourchette 172.26.79.230 à 172.26.79.239
  • Bridge Summoner : interface eth0 du serveur avec les interfaces virtuelles (vif) de nos machines xen


Sur chacune des machines :

  • Les vif du serveur correspondent à chacune des eth0 des machines, qui sont configurées de cette façon :
address 172.26.79.230 
netmask 255.255.240.0 
gateway 172.26.79.254
  • On configure la VM pour qu'elle ait accès à internet et puisse apt-get
  • On active le ssh pour ne plus être obligé d'utiliser xl console
  • On installe docker-engine et docker.io
  • A l'installation de docker, une interface docker0 est crée avec comme IP 172.17.0.1
  • Lorsqu'on va créer un conteneur, une nouvelle interface sera créée de la forme veth54205179. Pour le premier conteneur créé, son adresse IP sera 172.17.0.2. On a donc un sous réseau 172.17.0.0/16 qui nous permet donc de potentiellement donner 65 000 IP à 65 000 conteneurs différents.

(de 172.17.0.2 à 172.17.255.254) --> 2¹⁶

Semaine 11 (23/11/2015)

Semaine 12 (30/11/2015)

On regarde combien de conteneurs au maximul peuvent être créés sur un Vm pour un mémoire donnée :

Memory Containers
256 Mo 30
512 Mo 180
2048 Mo 600

Sachant que notre serveur possède 4Go de mémoire, nous optons pour l'instant pour 7 VM d'une mémoire de 512 Mo chacune. Nous pourrons ainsi créer environ 150 conteneurs docker par VM.

Suite à l'entretien avec Mr. Redon du 1er décembre :

  • Maquette réseau (disponible en lien externe)
  • Mettre à plat : Bridger les interface des conteneurs (veth......) avec eth0 (fait)
  • Pour 10 VM : 1 associations, 3 enseignants, 6 étudiants séparés dans 3 VLAN différents (cf schéma)
  • Se renseigner sur le reverse DNS pour que les requêtes soient redirigées vers les bon conteneurs.

Semaine 13 (07/12/2015)

Architecture réseau de notre projet


Objectif pour semaine prochaine : Maquette du site (Wireframe)

Semaine 14 (14/12/2015)

Préparation pour soutenance

Maquette du site web de notre projet

Semaine 15 (04/01/2016)

Nous nous attelons durant cette semaine à la confection du site web. Cette interface est dans un premier temps hébergée sur notre VM de PRA.
Nous avons choisi de créer une seule et unique page afin de ne pas avoir plusieurs pages à charger et naviguer sur le site plus rapidement et facilement. Pour cela, nous avons choisi d'utiliser le framework AngularJS qui nous permet d'obtenir un site dynamique et bien rangé. Les différentes rubriques (création, suppression, gestion, etc) sont accessibles via un menu qui permet de naviguer avec fluidité. Pour l’esthétique, nous avons opté pour bootstrap.
Comme prévu, notre interface web permettra l'exécution de 2 scripts principaux :

  • création d'un conteneur
  • suppression d'un conteneur

L'exécution de ces script se fait par un appel à une page php qui se connecte en ssh à notre serveur physique Rift via une clé RSA. La page php exécute ensuite le script avec les information nécessaire : Par exemple le Login, le VLAN et le nom de domaine en pramaètre du script de création.

Semaine 16 (11/01/2016)

Nous réunissons ici des informations importantes qui seront utiles pour la confection des scripts par la suite.

Création d'un bridge

Pour changer le réseau par défaut de Docker, on doit dans un premier temps détruire toute la configuration existante. En effet, bien que le bridge par défaut soit paramétrable entièrement, il est recommandé pour notre utilisation de créer et gérer son propre bridge. "While they are still available to you as techniques, it is better to avoid them and define your own bridge networks instead." [1]

service docker stop
ip link set docker0 down
brctl delbr docker0
iptables -t nat -F POSTROUTING

On peut ensuite créer un nouveau bridge qui correspond à nos attentes.

brctl addbr dockerBridge
ip addr add 10.0.0.1/8 dev dockerBridge
ip link set dev dockerBridge up
systemctl daemon-reload
service docker restart

On peut alors vérifier que notre configuration a bien été prise en compte avec les commandes suivantes :

ifconfig
iptables -t nat -L -n

Configuration Docker

Quelques informations pour la configuration réseau

vim /lib/systemd/system/docker.service

Il faut indiquer à Docker qu'il faut regarder le fichier de configuration /etc/default/docker. En effet, docker ne gère pas les distributions linux basée sur systemd, comme la Debian 8 que nous utilisons. Cette erreur, particulièrement difficile à détecter, ne survient pas sous Ubuntu ou d'autres distributions utilisant upstart ou SysVInit. Pour contourner le problème, il faut effectuer les modifications suivantes :

EnvironmentFile=-/etc/default/docker
ExecStart=/usr/bin/docker -d $DOCKER_OPTS -H fd:// 

On modifie ensuite le fichier de configuration référencé, pour y ajouter la ligne suivante :

echo 'DOCKER_OPTS="-b=dockerBridge"' >> /etc/default/docker

Semaine 17 (18/01/2016)

  • Exploration du dossier : /var/lib/docker/ qui contient :
    • Les fichiers de configurations servant à créer un conteneur
    • Les volumes servant de racine pour les conteneurs
  • Résolution d'un problème au niveau du réseau de la machine Xen
  • Réseau en 10.0.0.0/8 pleinement fonctionnel

Voici la configuration réseau d'une machine xen :

# The loopback network interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual
 up ip link set eth0 up
 down ip link set eth0 down

# The primary network interface
auto br0
iface br0 inet static
 bridge_ports eth0
 address 10.2.0.1
 netmask 255.0.0.0
 gateway 10.0.0.1

Ce masque de sous-réseau pose un autre problème. Lors de sa création, un conteneur choisi une adresse dans le réseau du bridge indiqué en ayant préalablement vérifier sa disponibilité. Voici la fonction qu'utilise Docker pour vérifier si une adresse IP a déja été allouée. Plus précisément, voici la fonction Go qui permet cela. Le problème est que le premier conteneur va prendre une adresse 10.0.0.3 au lieu de 10.2.0.2. Heureusement, on peut simuler un réseau plus contraignant en spécifiant à la création un masque sous-réseau plus petit.

docker run -ti --fixed-cidr=10.2.0.0/16 --name dock1 /bin/bash

Semaine 18 (25/01/2016)

On essaie durant cette semaine de donner accès à internet à nos conteneurs pour pouvoir y installer ssh. En parallèle nous essayons d'utiliser le système de reverse ssh pour pouvoir se connecter à un conteneur en ssh.

Nous avons également fini l'interface web disponible à l'adresse suivante :

http://projet.zegbicho.lol/

Utilisation de la commande iptables pour établir une mascarade.

iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -j MASQUERADE

On ajoute ensuite une interface tap avec une adresse dans le sous réseau 172.26.0.0/20. Cette interface permet la mascarade sans risquer de perdre la liaison ssh sur eth0. De plus, l'interface tap est nécessaire plutôt qu'un tunnel car la liaison se fait sur la couche OSI de niveau 2 (ethernet). Cette configuration nous permet aussi d'autoriser au conteneur l'accès à internet, ce qui nous débloque pour la suite.

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  10.0.0.0/8           anywhere 

On a accès à internet depuis la machine virtuelle Xen :

root@jinx:~# ping 193.48.57.48
PING 193.48.57.48 (193.48.57.48) 56(84) bytes of data.
64 bytes from 193.48.57.48: icmp_seq=1 ttl=62 time=0.538 ms
64 bytes from 193.48.57.48: icmp_seq=2 ttl=62 time=0.542 ms

Et de même sur un conteneur Docker :

root@5c909f8a8617:/# ping 193.48.57.48
PING 193.48.57.48 (193.48.57.48): 56 data bytes
64 bytes from 193.48.57.48: icmp_seq=0 ttl=62 time=0.501 ms
92 bytes from 10.2.0.1: Redirect Host
64 bytes from 193.48.57.48: icmp_seq=1 ttl=62 time=1.542 ms
92 bytes from 10.2.0.1: Redirect Host

Semaine 19 (01/02/2016)

On vérifie tout d'abord la configuration du démon (/etc/default/docker) fixed-cidr donne la plage d'adresse à utiliser lors de la création d'un conteneur br0 est notre bridge configuré manuellement

DOCKER_OPTS="-b=br0 --fixed-cidr=10.2.0.0/16 --ip-forward=true"

Voici maintenant les commandes à exécuter afin de lancer un conteneur avec un serveur web nginx fonctionnel à partir d'une image debian :

# Création d'un conteneur avec un serveur web fonctionnel
# Jérémie Denéchaud - Thibaut Scholaert
# 02/02/2016
 
# On récupère l'image de debian (Jessie, 8.3)
 docker pull debian

# On construit une image personnalisée à partir de Debian
# Les instructions suivies sont dans ./Dockerfile
docker build -t monserveur .

# On crée une instance de cette image
# -ti permet de lier les stdin et stdout
# bash est la commande à executer lors de la création
 docker run -ti --name dock0 --hostname jdenecha monserveur


Voici le contenu du fichier de configuration Dockerfile :

# Jeremie Denechaud - Thibaut Scholaert
# Example de Dockerfile

FROM debian
RUN apt-get update -y; apt-get upgrade -y
RUN apt-get install -y nginx ssh

RUN echo "/usr/sbin/service nginx start" >> /etc/bash.bashrc
RUN echo "/usr/sbin/service ssh start" >> /etc/bash.bashrc

#ADD id_rsa /root/.ssh/id_rsa
#RUN chmod 700 /root/.ssh/id_rsa

COPY template /var/www/html

Suite à une erreur, une réinstallation complète du serveur physique (rift) est nécessaire. La réinstallation a duré beaucoup moins de temps que la première fois dû à une meilleure connaissance du système. Nous avions également mis de coté les scripts résumant les installations essentiels pour une VM xen.

Semaine 20 (08/02/2016)

Suite à la réinstallation, nous avons changé de paquet docker (docker-engine au lieu de docker.io)

Voici les changements qui s'en suivent
Résolution du problème de dépôt https, puisque docker-engine se trouve dans les backports de debian officiel.
La configuration se fait maintenant dans le fichier /lib/systemd/system/docker.service
L'option --default-gateway est disponible et résout notre problème de Redirect Host en mettant la bonne gateway a tous les conteneurs (10.0.0.1)
Résultat d'un ping depuis un conteneur
root@be292d35df14:/# ping 193.48.57.48
PING 193.48.57.48 (193.48.57.48): 56 data bytes
64 bytes from 193.48.57.48: icmp_seq=0 ttl=62 time=0.642 ms
64 bytes from 193.48.57.48: icmp_seq=1 ttl=62 time=0.565 ms
64 bytes from 193.48.57.48: icmp_seq=2 ttl=62 time=0.570 ms

Nous avons créé une base de données sqlite pour stocker les associations nom de domaine <-> ip du conteneur. Cette base nous servira pour établir le fichier de configuration du proxy inverse.

 login       vlan        docker_ip   domain            
----------  ----------  ----------  ------------------
jdenecha    3           10.1.0.2    denechaud.plil.net
tscholae    3           10.1.0.3    scholaert.polytech
eestec      2                       eestec.plil.net  

Création du script de création d'un conteneur. Ce script peut se lancer depuis notre interface Le script se connecte en ssh (clés asymétriques) a une vm puis lance un conteneur avec le nom demandé. Pour l'instant la gestion du vlan n'est pas prévue. Une première version du script est disponible ici ainsi que dans la section "Fichiers rendus". Nous avons également créé un script de suppression de conteneur qui va supprimer le conteneur associé au nom de domaine fourni par l'utilisateur. Ce script est également exécutable depuis notre interface web de la même manière que pour la création.

Nous avons rencontré un soucis au niveau de l'allocation dynamique des adresses IP aux conteneurs créés. En effet, si un des conteneurs déjà créé s'arrête, à son redémarrage une nouvelle adresse IP lui sera allouée dynamiquement par le docker daemon. Lors de l'arret, l'adresse IP qui était occupée est libérée, il y a donc un risque qu'un autre conteneur l'utilise. Pour vérifier que notre base de donnée contienne toujours les bonnes adresses IP associées aux noms de domaines, nous avons donc pensé à un script qui vérifierait ceci en tâche de fond.


Avancement : Un utilisateur peut
* Peut créer depuis l'interface Web jusque 3 conteneurs avec le nom de domaine qu'il souhaite
* A la liste de ses conteneurs actifs
* Peut supprimer le conteneur qu'il souhaite


Reverse Proxy

Résultat d'une connexion directe par nc

Nous continuons aussi la partie Reverse Proxy qui permettra de rediriger un nom de domaine donné vers son adresse IP de notre sous réseau 10.x.x.x/8 correspondante. Le nom de domaine sera alors associé à son conteneur qui porte le site Web.

Notre problème principal est que nous n'arrivons pas à utiliser curl pour faire une requête depuis Rift vers un conteneur. Cependant, en se connectant directement grâce à la commande netcat nous arrivons à récupérer la page html du conteneur.



Semaine 21 (15/02/2016)

Depuis le début du projet, nous utilisons l'outil curl pour tester l'accessibilité de nos serveur web. Il semblait efficace, surtout de par sa possibilité de préciser un header HTTP. Cependant, un long debug nous a fait réaliser que dans certains cas un comportement étrange apparaissait. Lorsque nous essayons depuis l'hyperviseur Rift d'accéder à un conteneur, dans le même sous réseau, le ping indiquait que la route était bonne, mais curl ne trouvait rien.

root@rift:~# curl 10.1.0.5 -v
* Rebuilt URL to: 10.1.0.5/
* Hostname was NOT found in DNS cache
*   Trying 193.48.57.41...
* Connected to proxy.polytech-lille.fr (193.48.57.41) port 3128 (#0)
> GET HTTP://10.1.0.5/ HTTP/1.1
[...]

Avec l'option verbose, on voit apparaitre le comportement étrange : curl considère l'adresse 10.1.0.5 comme un nom de domaine. Il essaye donc naturellement de le résoudre, alors qu'il devrait s'y connecter directement. L'erreur est d'autant plus piégeuse que la même commande depuis une vm Xen donne un résultat correct :

Test du reverse proxy avec nc
root@jinx:~# curl 10.1.0.5 -v
* Rebuilt URL to: 10.1.0.5/
* Hostname was NOT found in DNS cache
*   Trying 10.1.0.5...
* Connected to 10.1.0.5 (10.1.0.5) port 80 (#0)
> GET / HTTP/1.1
[...]

Cette erreur une fois trouvée nous a confirmer que l'architecture réseau était bel et bien fonctionnelle. Nous avons utilisé l'outil netcat et wget pour valider notre architecture. Ceci nous a aussi permis de tester notre proxy inverse Nginx. Un script construit les règles de ce proxy en fonction de la base de données.

Test du reverse proxy depuis zabeth15

Livrable

Nous avons réalisé un petit récapitulatif des commandes et actions à faire pour reproduire notre système sur une machine Debian (Jessie 8) avec un noyau Linux 3.16.0-4-amd64 :
Reconstruction pas à pas de notre architecture

Semaine 22 (22/02/2016)

Rapport + préparation soutenance finale.

Reverse SSH

Nous nous sommes renseigné sur le SSH inverse pour qu’un utilisateur puisse déposer des fichiers sur son site via SSH/SCP/SFTP... La difficulté majeure réside dans la complexité de notre réseau --> Une connexion extérieure doit passer par le proxy de l’école, par notre hyperviseur, pour ensuite atteindre un conteneur. Nous avons donc testé sur une machine du réseau (titus10).
Nous avons réussi à créer un tunnel entre un conteneur classique dock0 en 10.1.0.2 et titus10.

  • Connexion de dock0 à notre hyperviseur en créant un pont sur un port choisi, ici 10100.
    • ssh -R 10100:10.1.0.2:22 root@172.26.64.13
  • Connexion de titus10 à notre hyperviseur
    • ssh root@172.26.64.13
  • Connexion de titus10 au pont créé précédemment
    • ssh -p 10100 user@10.1.0.2

Fichiers Rendus

Script de création d'un conteneur
Script de suppression d'un conteneur
Script vérification de l'association IP/nom de domaine des conteneurs
Livrable semaine du 15 février
Fichier:PFE DENECHAUD SCHOLAERT.pdf

Liens externes