Journal Migration d'une infra lamp vers docker

Posté par  . Licence CC By‑SA.
Étiquettes :
43
17
fév.
2015

Sommaire

Intro

Lecteur de linuxfr depuis un bon bout de temps, voici ma première contribution.
Dans cet article, je vous montrerai comment j'ai migré un site web qui tournait sur un serveur dédié vers docker en isolant chaque service dans un container

L'infra

Elle est constituée d'un serveur web avec quelques sites web et d'un serveur mysql.
Pour coller avec la philosophie docker, j'ai isolé chaque site web dans un container.
L'idée est de facilement pouvoir migrer un site web sans impacter le reste.

l'infra est constituée de :

  • un container reverse-proxy Apache qui va orienter les requêtes vers les différents sites web
  • un container apache qui va servir le WordPress
  • un container data où le contenu du WordPress sera stocké
  • un container Mysql où sera hébergée la base de données schema docker ## Le reverse proxy

Pourquoi utiliser un reverse proxy ?

il est nécessaire de lier un port d'un container à un port de la machine hôte pour que le container soit joignable de l’extérieur.
Si je décide de lancer deux containers de site web, seul le premier pourra être lié au port 80 (port standard pour le HTTP).
Le second devra être lié à un autre port.

C'est techniquement faisable mais très peu pratique.
Pour remédier à cela, j'ai créé un container jouant le role de reverse-proxy.
Ce container est lié au port 80 de la machine hôte et il va jouer le rôle de "passe plat".
Il va rediriger les requêtes sur les container adéquat grâce au nom de serveur demandé (directive servername) dans les requêtes http.

Le reverse proxy n'existait pas dans ma précédente infra car tous les sites étaient sur le même Apache.

DockerFile

FROM ubuntu:14.04
MAINTAINER Alban Garrigue <aban@garrigue.me>

RUN apt-get update
RUN apt-get install -y apache2

RUN a2enmod proxy
RUN a2enmod proxy_http

ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ADD ./alban.garrigue.me.conf /etc/apache2/sites-available/
RUN a2ensite alban.garrigue.me.conf
ENV APACHE_PID_FILE /var/run/apache2.pid
ENV APACHE_RUN_DIR /var/run/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2

RUN mkdir -p $APACHE_RUN_DIR $APACHE_LOCK_DIR $APACHE_LOG_DIR

ADD ./alban.garrigue.me.conf /etc/apache2/sites-available/
RUN a2ensite alban.garrigue.me.conf
RUN a2dissite 000-default.conf

ENTRYPOINT ["/usr/sbin/apache2"]
CMD ["-D", "FOREGROUND"]

la conf Apache

<VirtualHost *:80> 
  ServerName alban.garrigue.me
  ProxyPreserveHost On
  ProxyRequests off
  ProxyPass / http://alban.garrigue.me/
  ProxyPassReverse / http://alban.garrigue.me/
</VirtualHost>

Le apache "Wordpress"

DockerFile

FROM ubuntu:14.04
MAINTAINER Alban Garrigue <aban@garrigue.me>

#RUN apt-get update
RUN apt-get update && apt-get install -y apache2 php5 php5-mysql

ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ENV APACHE_PID_FILE /var/run/apache2.pid
ENV APACHE_RUN_DIR /var/run/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2

RUN mkdir -p $APACHE_RUN_DIR $APACHE_LOCK_DIR $APACHE_LOG_DIR

ADD ./alban.garrigue.me.conf /etc/apache2/sites-available/
RUN a2ensite alban.garrigue.me.conf
RUN a2dissite 000-default.conf
RUN a2enmod rewrite
RUN a2enmod expires
RUN a2enmod headers
RUN a2enmod cgi

EXPOSE 80
ENTRYPOINT ["/usr/sbin/apache2"]
CMD ["-D", "FOREGROUND"]

la conf apache

La conf apache est assez standard

<VirtualHost *:80>
  DocumentRoot /var/www/alban.garrigue/
  ServerName alban.garrigue.me
  <Directory /var/www/alban.garrigue>
                Options  FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                allow from all
        </Directory>

<Directory /var/www/alban.garrigue/blog>
        Options FollowSymLinks
        AllowOverride All
</Directory>
</VirtualHost>

Ce que j'ai du changer dans les fichiers de configuration du WordPress:

  • L'adresse de la base de données dans le wp-config.php
    • changer 127.0.0.1 par dbalban (à voir dans le fig.yaml)

Data only container

Le concept de container de données est relativement simple.
On ajoute des données à l'image, puis on les expose avec un volume.
L'avantage de ce type de container est qu'ils n'ont pas besoin de tourner pour que les autres aient accès à leur données.
Cependant il ne bénéficie pas du système de fichier unionfs et les données ne sont pas incluses dans la sauvegarde du container.

Pour sauvegarder ces données:

sudo docker run -rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data

Pour restaurer les données:

sudo docker run -rm --volumes-from DATA2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar

source: Stackoverflow

Vous voyez ci dessous qu'il n'y a rien de compliqué.

DockerFile

FROM stackbrew/busybox:latest
MAINTAINER Tom Offermann <tom@offermann.us>

# Create data directory
#RUN mkdir /var/www/
ADD alban.garrigue /var/www/alban.garrigue
# Create /data volume
VOLUME /var/www/

Mysql

Je me suis basé sur ce dépôt github

Ce que j'ai modifié dans le DockerFile:

  • Ajout dump sql pour charger la base
  • Ajout du login/mot de passe du compte wordpress en variables d'environnement
  • Ajout du path de mon dump sql pour l'import

DockerFile

ADD wordpress-alban.sql /tmp/wordpress-alban.sql
# Exposed ENV
ENV MYSQL_USER <user>
ENV MYSQL_PASS <mot de passe>
ENV STARTUP_SQL /tmp/wordpress-alban.sql

Fig

Fig.sh permet d'orchestrer le lancement des containers et de les lier entre eux
il va résoudre les liens de dépendances pour trouver le bon ordonnancement.
Les links vont servir de liens entre les containers en utilisant les fichiers /etc/hosts.
Ainsi il faut faire abstraction des adresses IP et raisonner en nom de container.
Le fichier fig.yaml permet de lancer clairement des containers avec des options spécifiques.
Personnellement je trouve ça plus clair qu'une ligne de commande à rallonge.

fig.yaml

reverse:
  image: reverse-proxy
  ports:
    - "80:80"
  links:
    - webalban:alban.garrigue.me

webalban:
  image:  alban-garrigue-apache
  volumes_from:
    - webalbanstockage
  links:
    - dbalban

dbalban:
  image: alban-garrigue-mysql

webalbanstockage:
  image: alban-garrigue-data

Résumé :

Ça serait vous mentir si je vous dis que tout cela est tombé sous le sens du premier coup.
J'ai eu du mal à comprendre la persistance des données, les concepts d'images et de containers.
Les containers sont le résultat de l'instanciation d'une image.
Les données à l’intérieur sont aussi pérennes que le container.
Le container est arrêtable et redémarrable, si votre docker plante tout n'est pas perdu.
Cependant si vous ré-instanciez l'image, vous ne bénéficierez pas des données du conteneur précédent.
Les topics de stack overflow sont une source d'information précieuse.
Tout ce petit monde avance très vite et de nombreux outils se développent.

Je vais prochainement tester :

weave qui permet de gérer la partie réseau inter container et multi host (intéressant)
consul qui fait de la découverte de service

  • # Intéressant

    Posté par  . Évalué à 4.

    Merci, c'est sympa d'avoir un cas d'utilisation de Docker pour se faire la main, je vais finir par me laisser tenter. Par contre, une première lecture rapide me chipote un peu : pourquoi est-ce qu'on a l'impression que tu fais des trucs en double dans le premier Dockerfile? Genre les lignes suivantes :

    ADD ./alban.garrigue.me.conf /etc/apache2/sites-available/
    RUN a2ensite alban.garrigue.me.conf
    
    • [^] # Re: Intéressant

      Posté par  (site web personnel) . Évalué à 2.

      sous debian, le fait de mettre ton fichier de conf dans /etc/apache2/sites-available/ en signifie pas qu'il est actif, a2ensite crée un lien symbolique dans /etc/apache2/sites-enabled vers ton fichier de conf

      • [^] # Re: Intéressant

        Posté par  . Évalué à 3.

        Je crois qu'il voulait surtout dire que ces 2 lignes sont présentes 2 fois dans le premier DockerFile.

        • [^] # Re: Intéressant

          Posté par  . Évalué à 1.

          ceci est bien un trop rapide copier coller, par contre je n'ai pas trouvé comment éditer un journal

  • # Mise à jour

    Posté par  . Évalué à 7.

    Merci pour l'article il est très intéressant.
    As-tu regardé l'aspect mise à jour ?
    Par exemple si demain une faille Apache est découverte, peut-on tout upgrader d'un coup grâce à docker, ou faut-il traiter chaque container individuellement ?

    • [^] # Re: Mise à jour

      Posté par  . Évalué à 3.

      si le paquet apache est mis à jour dans les dépots,
      il faudra reconstruire l'image docker:
      L'avantage de docker permet de séparer les programmes (apache) et les données.
      il est facilement possible de supprimer le container et de le ré-instancier dans la version mise à jour sans avoir à toucher aux données.
      exemple:

      #reconstruire l'image docker:
      docker build -t alban-garrigue-apache ./
      #supprimer le container:
      fig stop webalban
      fig rm webalban
      #puis le reinstancier
      fig up

      nous voila avec un apache tout neuf.
      Si l'image est instanciée X fois, il faudra faire cette manipulation X fois ou utiliser un outil pour industrialiser le tout sur des architectures plus grande.

      Grâce à la portabilité des images, on peut tester en local, s'assurer que tout fonctionne bien et pousser tout ça en prod sans trop de problème avec une interruption de service minime.

      • [^] # Re: Mise à jour

        Posté par  (site web personnel) . Évalué à 0.

        si le paquet apache est mis à jour dans les dépots,
        il faudra reconstruire l'image docker:

        Quel système utilises-tu pour être notifié des mises à jour à effectuer dans ton conteneur ? J'imagine que tout se fait depuis l'hôte à coup de docker exec CMD_CHECK_UPDATE pour le remonter au système de supervision ? Je suis intéressé par des retours sur ce type de sujet.
        J'en avais discuté un jour avec quelqu'un à une conférence sur Docker, et eux appliquaient une politique de livraison continue en reconstruisant 1 fois /jour les conteneurs, et c'est vrai que Docker facilite grandement cette approche (même si on peut en faire tout autant avec Ansible+LXC).

  • # A quoi ça sert ?

    Posté par  . Évalué à 7.

    Bonjour,

    Dans les faits, ça t'apporte quoi ? Que ce soit en terme de fonctionnalités, de sécurité… ?

    Ca me semble plus complexe et forcément plus lourd à administrer (2 apaches au lieu d'un, l'archi Docker en plus) et je ne vois pas trop où est le gain réel.

    Autant je comprend Docker quand on a des besoins forts en isolation des services, autant pour ce genre de choses, je zappe. Mais je passe peut-etre à coté de quelque chose.

    Après, si c'est juste pour la démarche, pour apprendre et mettre en pratique, rien à redire ! :)

    • [^] # Re: A quoi ça sert ?

      Posté par  (site web personnel) . Évalué à 3.

      Merci bien pour ton use case.

      Oui, je suis d'accord.

      Pourtant grand fan de Docker et auteur de multiples docs, malgré tout, je n'aurais pas fais ce choix d'architecture.
      A moins qu'il y ait un besoin réel de séparer les sites, je pense que pour des petites utilisations, on s'en sort et avec moins de complexité avec un Apache et des Virtualhosts.

    • [^] # Re: A quoi ça sert ?

      Posté par  . Évalué à 5.

      J'ai fais ça pour le fun et mieux comprendre la technologie
      Pour une archi perso, ça apporte peu de chose au quotidien:
      - la facilité de migration.
      - la non-adhérence au système: tu peux déployer une infra en une ligne de commande et la supprimer en une autre
      - pour tester des services (exemple: owncloud 8, tu récupères le dockerfile qui va bien, c'est opérationnel tout de suite et quand tu veux arrêter: tu supprimes le container et tu n'as pas de dépendance qui reste installée

      • [^] # Re: A quoi ça sert ?

        Posté par  (site web personnel) . Évalué à 2.

        OK.
        Alors pour les tests, je suis d'accord, c'est génial de ne pas avoir à manipuler toute une VM ou à polluer sa "vraie" machine.
        A la conférence sur Docker, Jérôme Petazzoni, un des créateurs disais que c'était pas à but de remplacer les VMs, mais la vocation est plutôt de déployer très rapidement des environnements de dév ou de tests.

        Personnellement, j'attend une meilleure gestion du réseau (adressage IP, bridging) pour mettre des containers en prod.

  • # Par rapport à LXC

    Posté par  (site web personnel) . Évalué à 2.

    Salut,

    c'est très intéressant effectivement. Merci du retour.
    J'ai mis en place à peu près la même architecture sur mon home serveur, mais avec des conteneurs LXC.

    Mais autant j'ai bien pigé LXC qui s'apparente à une VM dont le noyau n'est pas virtualisé mais issu de celui de l'hôte et soumis aux restrictions des cgroups, et donc fournissant une arborescence système linux classique ainsi qu'une gestion des daemon comme on en a l'habitude ; autant Docker, j'arrive vraiment pas à comprendre la subtilité par rapport à ça (et donc pas trop l'intérêt non plus dans un cas d'usage comme celui-ci - même si visiblement ça fait très bien le boulot ! :D)

    Il me semble que j'avais déjà posé la question dans un précédent journal causant de Docker, je m'en vais de ce pas essayer de retrouver ça, mais malgré tout, si quelqu'un pouvait m'expliquer la nuance dans ce cas précis, j'apprécierais. ;)

    There is no spoon...

    • [^] # Re: Par rapport à LXC

      Posté par  (site web personnel) . Évalué à 2.

      Docker se pose en surcouche par rapport à LXC, pour faciliter les déploiements, les imports/exports, les partages (docker Hub associé à Github ou Bitbucket), la gestion des containers.

      • [^] # Re: Par rapport à LXC

        Posté par  . Évalué à 2.

        Selon ma compréhension, Docker ne se pose plus en surcouche de LCX mais en remplacant de LXC.
        La librairie lxc n'est plus utilisée, Docker utilise la sienne.

        Autrement, je serais intéressé pour voir comment le tout s'articule dans une infra avec du load-balancing, fail-over, réplication, …
        Il me semble qu'il y a une librairie Docker qui va arriver pour traiter le fail-over: swarm ?

        • [^] # Re: Par rapport à LXC

          Posté par  . Évalué à 1.

          Docker n'utilise plus la librairie LXC, il utilise par défaut leur propre librairie écrite en go qui s'appelle libcontainer (il est possible d'utiliser docker avec un backend lxc (--exec-driver=lxc) ).

          Niveau fonctionnalité on est a peut près au meme niveau entre docker et LXC. Il manque encore deux ou trois petits truc à la libcontainer tels que le namespace uid (avoir l'uid 0 du containeur mappé sur un uid user de la machine hôte). Pour la petite histoire ce manque était surtout du à un manque dans l'implémentation de syscall de go, depuis qui ceci à été fixé dans go 1.4 ça devrait arriver rapidement dans docker.

          Docker vs lxc ? Docker à un eco-system beaucoup plus grand (intégration Google Kubernetes, Mesos, Amazon EC2, et meme bientot Microsoft…). Moins de configuration manuelle, plus de documentation, plus d'examples, plus de recettes (ansibles,puppet,…). Après effectivement si on aime ce la jouer barbu fana des script maison en ligne de commande docker est moins sexy que lxc , pour tous les autres y a pas photos.

        • [^] # Re: Par rapport à LXC

          Posté par  . Évalué à 1.

          Je n'ai pas encore testé swarm.
          il y a la méthode lvs/keealived qui pourrait marcher.
          De plus avec fig, on peut dynamiquement changer le nombre container d'un service.

  • # Compose

    Posté par  . Évalué à 1.

    Bonjour,
    Merci pour ton article : ça éclaire ma lanterne sur à quoi peut servir docker.
    Une question concerne l'orchestration : docker-compose n'est-il pas dédié à cela? (Ou docker-machine, je ne sais pas trop…)

    • [^] # Re: Compose

      Posté par  . Évalué à 1.

      Fig a été déprécié et il a été remplacé par docker-compose. Mais pour le moment, c'est le même code.
      Il y a pas mal de changement dans l’écosystème docker en ce moment et ça peut être vite troublant :)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.