PROJET AUTOBLOG


Sam & Max: Python, Django, Git et du cul

Site original : Sam & Max: Python, Django, Git et du cul

⇐ retour index

Mise à jour

Mise à jour de la base de données, veuillez patienter...

Le déploiement par conteneurs avec Docker

jeudi 15 mai 2014 à 21:10

Mettre son projet en production, c’est la galère. Tellement que mille méthodes ont vu le jour pour automatiser tout ça. Chef, salt, fabric, des script bash, virtualenv, git hooks, etc.

Après, il y a ceux qui utilisent des VM, qui elles, ont leur propres outils d’automatisation type Vagrant.

Et comme ça ne suffit pas, des services ce sont mis en place pour faciliter la mise en prod dans le cloud comme Heroku, Gondor, dotCloud…

Malgré ça, Max fait encore beaucoup de trucs à la main parce que “ça marche jamais comme prévu”. Pas très scalable.

Dernièrement, grâce à notre cher Cortex, j’ai découvert un projet écrit en Go nommé Docker, qui propose encore une autre approche du problème.

J’ai été intrigué après avoir visionné une conf sur le sujet car le principe est très cool, mais aussi parce que j’ai bossé à une époque avec un des mecs de chez docker. Et ce gars est un monstre. Mais vraiment. Une brute. Le genre qui n’a pas besoin de souris ni de gestionnaire de fenêtre, mais qui peut vous régler votre problème en tapant d’une main tout en vous expliquant ce qu’il fait dans votre domaine d’expertise alors que ce n’est pas le sien. Je l’ai vu faire. C’est énervant.

Pour le moment, je dois dire que Docker est vraiment sympa. Petit tour du propriétaire.

C’est comme si chaque process avait sa mini VM

Pour faire simple, docker, c’est de la virtualisation légère.

Ça marche comme cela : on prend une image d’un Linux de base qu’on fait tourner dans docker, on lui installe de quoi faire tourner un process – par exemple redis – et on obtient une nouvelle image qui contient juste la différence avec l’image précédente. On fait ça avec plein d’autres process, et quand on a besoin de l’un d’entre eux, on lance l’image qui contient l’install de ce celui-ci.

Ce sont des images très légères, on peut en lancer 100 sur une même machine si on le souhaite. Mais elles sont parfaitement isolées : elles ont leur propre système de fichier, leurs propres arbres de processus, utilisateurs, permissions, ports… Donc si par exemple je fais un nginx compilé avec des extensions exotiques et une config zarb, je peux en faire une image puis l’utiliser sur n’importe quel serveur qui contient Docker.

Le but, c’est de créer plein de petits conteneurs légers et isolés de votre machine. Et au lieu de configurer chaque serveur, on envoie juste les conteneurs dont on a besoin, et on est certain qu’ils marchent partout pareil, peu importe la config à l’arrivée. On virtualise des services, qu’on combine, et non une machine complète.

Quand je vous dis que c’est léger, c’est VRAIMENT léger. A peine plus gourmand que le process sans la VM. En fait, un conteneur docker démarre presque instantanément, il n’y a pas de “boot” comme pour une vraie VM. Mais on en a les avantages car votre redis dockerisé marchera pareil sur une Fedora et une Ubuntu.

Docker ne marche que sur Linux pour le moment, et encore, sur un Linux pas trop vieux car il utilise une technologie récente, dont vous avez probablement peu entendu parlé : LXC.

Détail amusant : Docker est pas mal utilisé dans la communauté des devs sous Mac, qui du coup ont une VM Ubuntu dans laquelle ils font tourner Docker pour travailler. N’est-ce pas merveilleux ?

La démonstration obligatoire

Je ne vais pas vous laisser comme ça et vous demander de vous la mettre derrière l’oreille, donc exemple d’utilisation sous Bubuntoune.

Je suis en 14.04, mais je pense que ça marche pareil depuis la 12.04.

Installation :

$ sudo apt-get install docker.io

Cela va mettre la commande docker.io à votre disposition, mais sous d’autres systèmes, elle s’appelle juste docker. Perso je fais un

alias docker="sudo docker.io"

puisque de toute façon il faut toujours lancer cette commande avec les droits admin.

Ensuite, on va télécharger une image de base sur laquelle baser toutes nos images :

$ docker pull ubuntu

Docker.io, ce n’est pas juste un software, c’est aussi un service qui héberge les images. Vous pouvez bien entendu créer vos propres images de base, et héberger votre dépôt personnel d’images, mais on ne va pas se faire chier à faire ça ici. Prévoyez quelques gigas de place, Docker ne prend pas beaucoup de ressources CPU/RAM, mais par contre ça bouffe en espace disque.

Donc là, je demande la récupération des images “ubuntu”, qui vont nous servir d’images de base. Elles sont toutes faites et prêtes à l’emploie, que demande le peuple ?

Ça va downloader pendant pas mal de temps, puis vous aurez plusieurs images à votre disposition, que l’on peut lister ainsi :

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ubuntu              12.04               8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              12.10               b750fe79269d        5 months ago        24.65 kB (virtual 180.1 MB)
ubuntu              latest              8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              precise             8dbd9e392a96        4 months ago        131.5 MB (virtual 131.5 MB)
ubuntu              quantal             b750fe79269d        5 months ago        24.65 kB (virtual 180.1 MB)

Vous faites votre marché : quelle image de base voulez-vous utiliser ?

La 12.04 est une LTS qui est déjà bien field testée, donc je vais prendre celle là.

Ensuite, pour lancer une commande avec, il faut faire docker run id_image commande. Ceci va lancer l’image, lancer la commande, et dès que la commande se termine, arrêter l’image :

$ docker run 74fe38d11401 echo 'YEAHHHHHHHHHHHHHH'
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
YEAHHHHHHHHHHHHHH

Mesurons le temps pris en tout pour faire cela :

$ time -f "%e seconds" sudo docker.io run 74fe38d11401 echo 'YEAHHHHHHHHHHHHHH'
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
YEAHHHHHHHHHHHHHH
0.45 seconds

Comme vous le voyez, démarrer un conteneur, c’est vraiment rapide. Mais faire un

echo

, ça ne sert pas à grand chose :)

Faisons quelque chose de plus utile : lançons un terminal bash et demandons un accès à stdin/stdout (-i) ainsi qu’un tty (-t) :

$ docker run -i -t 74fe38d11401 bash
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
root@8195e92a5e62:/#

Et hop, comme le process ne se termine pas tant qu’on est connecté au tty, on a le conteneur qui continue de tourner, mais on a un terminal dessus, nous permettant d’entrer n’importe quelle commande.

Si on installait 0bin ?

D’abord, on a besoin de pip dans le conteneur:

# apt-get install python-pip

Notez qu’on est toujours root dans son conteneur. Après tout, c’est virtuel et isolé, donc pas de raison de se faire chier.

Ensuite, on tape dans pypi :

# pip install zerobin

Pas besoin de virtualenv, on est déjà dans un environnement isolé.

Faisons un petit fichier de config. On va avoir besoin de vim :

# apt-get install vim
# cd /home
# vi settings.py

On met des settings perso pour zerobin, histoire de montrer le principe de faire un conteneur avec un setup sur mesure (on peut, bien entendu, faire 1000 fois plus compliqué, c’est un exemple bande de bananes) :

# on le fait ecouter sur l'exterieur
HOST = "0.0.0.0"
# on change le menu de la page d'accueil
MENU = (
    ('Home', '/'),
    ('Contact', 'mailto:mysupermail@awesomesite.com')
)

Et on lance notre petit zerobin :

# zerobin --settings-file=settings.py

Et voilà, on a un zerobin qui tourne dans notre conteneur isolé.

On va sauvegarder tout ça. Sur notre machine hôte (donc pas dans le conteneur), on va sauvegarder notre nouvelle image. D’abord, on va trouver l’ID du conteneur qui tourne :

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                     NAMES
8195e92a5e62        ubuntu:12.04        bash                37 minutes ago      Up 37 minutes                                 boring_mccarthy

Ensuite on commit ce conteneur pour obtenir une nouvele image. Pour faire simple, on va l’appeller “zerobin” :

$ docker commit 8195e92a5e62 zerobin

On peut alors tranquillement arrêter notre conteneur :

$ docker stop 8195e92a5e62

Maintenant on peut pusher notre image tout neuve sur un repo distant avec docker push pour pouvoir la puller plus tard. Il faut ouvrir un compte sur leur service ou créer son propre depot, je vous laisse trouver comment faire. Plus simplement, on peut juste dumper l’image avec docker save id_image > nom_image.tar, la copier sur une clé USB, et la recharger avec docker load < nom_image.tar.

Dans tous les cas, une fois sur le serveur, vous pouvez lancer votre image "zerobin", ici encore une fois avec la commande bash:

# docker run -t -i -p 7777:8000 zerobin bash

Cette fois, on rajoute une option de plus : -p 7777:8000 dit à docker de relier le port 7777 de ma machine au port 8000 (port de 0bin par défaut) de mon conteneur. Ainsi, si une app va sur le port 7777 de ma machine, elle va en fait parler au port 8000 du conteneur sans s'en rendre compte.

Du coup, je peux lancer mon petit zerobin depuis mon contenur :

# cd /home
# zerobin --settings-file=settings.py

Et voilà ! J'ai un zerobin qui marche, qui est préconfiguré, isolé et portable. Si je change de serveur, ou même d'OS, je peux juste reprendre le même conteneur et le relancer tel quel. Et je peux faire ça avec plein de process et les faire communiquer entre eux.

Capture d'écran de zerobin

J'accède à 7777 sur la machine, mais ça tape sur 8000 dans mon conteneur

Docker est un outil très riche, et vous vous doutez bien que je ne vous ai montré que le début.

Par exemple, vous voulez sans doute ne pas avoir à lancer bash, puis un cd, puis zerobin. Ça peut s'automatiser avec un dockerfile. Vous voulez aussi peut être lancer le conteneur en arrière plan, ça se fait avec l'option -d. Ou peut être voulez-vous un dossier partagé entre tous les conteneurs ? C'est possible avec l'option volume.

Parmi les usages vraiment intéressants de dockers : packager les services très custos comme les nginx ou ffmpeg compilés avec des options cryptiques, deployer son app django avec toutes les libs Python et les settings qui vont bien, remplacer une app à chaud en redirigeant juste le load balancer sur le nouveau conteneur, ou encore fournir un env de test à un client. Perso, rien que pour tester des nouveaux logiciels sans pourir ma machine, je trouve ça pratique : on a bien moins peur de faire un make install.

Je vous laisse prendre en main le nouveau joujou, j'ai des serveurs à planter.

flattr this!

Error happened! 0 - count(): Argument #1 ($value) must be of type Countable|array, null given In: /var/www/ecirtam.net/autoblogs/autoblogs/autoblog.php:428 http://ecirtam.net/autoblogs/autoblogs/sametmaxcom_a844ada43a979e3b1395ab9acb6afafb84340999/?Le-d%C3%A9ploiement-par-conteneurs-avec-Docker #0 /var/www/ecirtam.net/autoblogs/autoblogs/autoblog.php(999): VroumVroum_Blog->update() #1 /var/www/ecirtam.net/autoblogs/autoblogs/sametmaxcom_a844ada43a979e3b1395ab9acb6afafb84340999/index.php(1): require_once('...') #2 {main}