Virtualisation légère avec Docker

Date: 2/06/2014 | Catégories: Developpement,Open-source,Planet-libre,Reseau,Systeme | Tags: ,,

Dans le petit monde des DevOps, la solution de virtualisation Docker a le vent en poupe. Nous allons dans ce billet essayer de décrypter ce qui ce cache derrière ce nouvel outil et proposer un tutoriel sur l'installation et les premiers pas pour une utilisation souple et efficace.Sélection_178

C'est quoi donc ?

Docker est un logiciel open-source (sous licence Apache 2.0) et un service en ligne optionnel (Docker.io) permettant de gérer des conteneurs ("dockers").

Contrairement aux machines virtuelles classiques qui comprennent un système hôte ("guest OS") et les librairies/applications, les conteneurs ne contiennent, au maximum, que les applications/librairies.

 Sélection_179

Quand je dis au maximum c'est qu'une copie d'un conteneur qui ne change que la partie application ne contiendra que les différences par rapport au conteneur initial.

Sélection_181

Le système hôte est ainsi géré directement par le Docker Engine (en vert dans le premier schéma). On a ainsi une mutualisation qui permet de lancer les conteneurs de manière très rapide: le temps de lancement d'un conteneur est presque le même que le temps de lancement des applications qu'il contient. En effet, le système d'exploitation est déjà lancé. Donc pas de phase de démarrage ni d'initialisation de cette couche. Il faut quand même avoir à l'esprit que même si l'on est pas dans une machine virtuelle, on dispose tout de même d'un environnement isolé (processus, système de fichier, ports réseau). L'utilisateur n'a qu'à se préoccuper que de ce qu'il veut virtualiser (les applications/services) et ne s'occupe pas du reste.

L'autre gros avantage de cette technologie est la portabilité. En effet, il est tout à fait possible de concevoir un conteneur sur son PC portable puis ensuite de le déployer sur son infrastructure de production physique ou virtuelle. La taille des conteneurs étant relativement réduite, on peut donc imaginer un workflow de déploiement basée sur un repo central (type Git) et des Docker Engine installés sur les machines qui font elle même tourner des conteneurs. Il n'y a pas vraiment de limite au nombre de conteneurs qu'une machine puisse faire tourner. La limite vient de l'occupation mémoire/CPU/réseau de vos applications.

Si vous avez encore des questions sur la différence entre Docker et VM, je vous conseille la lecture de cette question sur StackOverflow: "How is Docker.io different from a normal virtual-machine ?".

Installation de Docker

Note (merci à @jb_barth pour le commentaire): jusqu'à la version 0.9, Docker se basait sur la technologie LXC ("Linux Containers") du noyau Linux et ne fonctionnait donc que sur des distributions GNU/Linux avec un noyau >= 2.6.24. La dépendance stricte à LXC a sauté depuis la v0.9.0, le driver par défaut est maintenant libcontainer, une lib pur go produite par le projet pour accéder de façon propre aux APIs dispos dans le kernel. C'est ce qui a permis de supporter des noyaux aussi vieux d'ailleurs, au début c'était >= 3.8

Voici les étapes à suivre pour installer Docker sur une distribution Ubuntu 14.04 LTS. A noter, pour les miséreux développeurs sous Windows ou Mac OS, il est est toujours possible de faire tourner une VM Ubuntu (par exemple avec VirtualBox) et de suivre cette installation.

Docker est directement disponible dans les repositories d'Ubuntu, donc un simple:

suffit pour effectuer l'installation complète de Docker sur notre machine comprenant:

  • le Docker Engine (ou service Docker)
  • le Docker Client (permettant de discuter avec le Docker Engine)

Cependant si vous souhaiter travailler avec une version plus ressente il faut utiliser les commandes suivantes:

Comme les conteneurs vont utiliser les serveurs DNS de la machine hôte, il est nécessaire de configurer les adresses des serveurs DNS dans le fichier /etc/default/docker.io (par exemple avec les serveurs OpenDNS):

Pour que la configuration soit prise en compte, il faut relancer le service Docker avec la commande:

Un petit ps permet de voir que le service est bien lancé:

Récupération des images système

Nous allons commencer par récupérer des images qui vont servir de de bases à notre conteneur. Une liste assez conséquente d'images sont disponibles sur le site officiel du projet. Vous pouvez ainsi récupérer celle qui est le plus proche de l'environnement que vous recherché. Un moteur de recherche est disponible à l'adresse https://index.docker.io/ pour trouver des images conçues par les développeurs du projet et par des contributeurs.

On retrouve ainsi des distributions GNU/Linux minimales comme Ubuntu, CentOS, BusyBox pour ne siter que les images officiellement supportées par le projet Docker.io (il existe également des repos non officiels avec Fedora, RH, Arch...).

Petit mention spéciale pour les images BusyBox qui sont vraiment très légère (moins de 10 Mo) pour un système fonctionnel !

Même si il est possible de directement télécharger l'image au lancement du conteneur, je préfère avoir sur ma machine les images des différentes versions de l'OS que j'utilise le plus: Ubuntu.

Pour récupérer l'ensemble des images du repo Ubuntu qui contient les versio  minimale d'Ubuntu de la version 10.04 à 14.04), il faut saisir la commande suivante:

Note: le téléchargement initial des images peut prendre un peu de temps selon la vitesse de votre liaison Internet.

Il est également possible de faire de même avec les autres distributions citées ci-dessus:

Une fois le téléchargement terminé, on peut demandé à Docker un status de son état actuel:

ainsi que la liste des images disponibles:

Comme alternative du moteur de recherche https://index.docker.io/, il est bien sûr possible d'utiliser la ligne de commande. Par exemple pour trouver toutes les images Ubuntu disponibles sur le repo central:

A noter qu'il est tout à fait possible, si vous ne trouvez pas votre bonheur de concevoir "from scratch" votre propre image système en suivant cette documentation sur le site officiel (la procédure se base sur DebootStrap).

Création de son premier conteneur

Bon assez de préliminaires, nous allons maintenant pourvoir créer notre premier conteneur qui va se limiter à exécuter la commande 'ls' (si c'est pas du conteneur de compétition):

Arrêtons-nous un peu sur la commande: sudo docker.io run ubuntu:latest /bin/ls -alF

On demande donc le lancement (run) d'un conteneur basée sur la dernière version d'Ubuntu (ubuntu:latest qui est un lien vers l'image minimale de la version 14.04) qui va exécuter la commande ls (/bin/ls -alF). Comme vous pouvez le voir dans le résultat de la commande, on est dans un environnement isolé avec son propre système de fichier.

Première constatation, la vitesse d’exécution de notre environnement virtuel est vraiment impressionnante. Sur une petit commande,on peut voir que l'overhead de lancement du conteneur est négligeable:

Puis un conteneur persistant

Passons maintenant à la création d'un conteneur persistant, c'est à dire un conteneur  qui va faire tourner une tache pendant un temps indéterminé (je prends par exemple un pin infini vers le site Google).

Noter le -d dans la ligne de commande pour détacher le conteneur et ainsi lui permettre de tourner en tache de fond.

En retour on obtient le numéro d'identifiant unique du conteneur qui va nous permettre de le contrôler.

On commence donc par vérifier qu'il tourne bien:

On peut ainsi, l'arrêter:

Le démarrer:

Le redémarrer (l'équivalent d'un stop/start):

Lui envoyer des signaux:

Ensute on supprime le conteneur avec la séquence stop/rm:

Un Shell dans un conteneur

Pour accéder à un shell dans le conteneur, il faut utiliser les options suivantes dans la ligne de commande:

  • -t: Allocate a pseudo-tty
  • -i: Keep STDIN open even if not attached

Structurer la création des conteneurs avec les Dockerfiles

Les Dockerfiles sont des fichiers textes décrivant les différentes étapes pour la création d'un conteneur. Idéalement, ce sont ces fichiers que vous aller gérer en configuration et que vous aller partager avec les différentes personnes utilisatrices de votre projet. Pour illustrer mes dires, je vais prendre l'exemple d'un dockerfile qui va permettre aux contributeurs du projet Glances de tester simplement la branche de développement du logiciel.

En gros, le dockfile doit:

  1. utiliser un OS de base (Ubuntu 14.04 LTS)
  2. installer les pré-requis système
  3. télécharger la dernière version de Glances sous Github

Le dockfile glances_develop_install correspondant est alors le suivant:

Voyons un peu en détail le contenu du fichier.  On commence donc par définir l'OS de base:

FROM ubuntu

On peut bien sûr utiliser l'image/tag que l'on souhaite.

Ensuite on passe aux commandes que l'on souhaite exécuter:

RUN apt-get -y update

RUN apt-get install -y python-dev python-pip git lm-sensors

RUN pip install psutil bottle batinfo https://bitbucket.org/gleb_zhulik/py3sensors/get/tip.tar.gz

RUN ln -s /proc/mounts /etc/mtab

RUN git clone -b develop https://github.com/nicolargo/glances.git

Rien de bien compliqué, il suffit de faire précéder la commande Unix par le mot clé RUN...

Il ne reste plus qu'à lancer la construction du conteneur et son exportation vers une nouvelle image (nommé ubuntu:glances_develop) à partir de la ligne de commande:

ou alors directement depuis un repos (par exemple GitHub) ou vos Dockers files sont gérés en configuration:

On vérifie ensuite que l'image a bien été créée:

Puis on lance Glances depuis ce conteneur (en le metant à jour par un pull avant le lancement):

Et hop c'est magique:

Glances in a docker

Un des trucs fun avec Docker c'est que si l'on souhaite modifier un conteneur en ajoutant par exemple l'installation d'un nouveau logiciel, il suffit de modifier le Docker file puis de refaire la commande de build. L'installation ne se fera que par delta par rapport au premier conteneur.

Controler la CPU et la mémoire de ses conteneurs

Une fonction intéressante de Docker est sa capacité de contraindre un conteneur en terme de CPU et de MEM. Par exemple on peut limiter le conteneur à 512 Mo de RAM et donner un priorité moins forte en terme de CPU à ce conteneur par rapport aux autres. Il faut cependant que le hôte qu héberge Docker soit compatible avec ces options ce qui n'est pas mon cas:

Pour activer ces options sous Ubuntu, il faut modifier la configuration du Kernel via GRUB. Pour cela, il est nécessaire de suivre cette procédure.

Conclusion

L'approche est vraiment différente des solutions de virtualisation classiques mais si vous cherchez un outil simple pour valider vos applications Linux dans un environnement controlé alors Docker est définitivement une solution à envisager. Sa souplesse et sa légéreté en font une solution idéale à embarquer sur son PC portable ou à mettre en production sur son infrastructure.

Je vous conseille de vous plonger dans la documentation officielle qui est vraiment complète et très bien faite.

Des expériences à nous faire partager sur l'utilisation de Docker ?

Quelques références:

  • Pingback: Virtualisation légère avec Docker...()

  • jb_barth

    Sympa l’article, enfin un post complet en français que je pourrai faire passer à mes collègues 😉

    Deux petites précisions:

    – la dépendance stricte à LXC a sauté depuis la v0.9.0, le driver par défaut est maintenant libcontainer, une lib pur go produite par le projet pour accéder de façon propre aux APIs dispos dans le kernel. C’est ce qui a permis de supporter des noyaux aussi vieux d’ailleurs, au début c’était >= 3.8

    – pour le message de fin tu peux regarder http://docs.docker.io/installation/ubuntulinux/#memory-and-swap-accounting, probable qu’avec un ou deux paramètres de boot en plus tu puisses faire ce que tu veux ; ça a marché pour moi sur du Ubuntu 13.x

    Bonne continuation

  • Flemzord

    Exactement le même principe que OPENVZ, sauf que OPENVZ lui est totalement stable 🙂

  • olivierlm

    Chouette mise en bouche.
    AMHA il manque une intro aux directives CMD et ENTRYPOINT dans les Dockerfile qui permettent d’éviter d’alourdir la commande ‘docker run’ avec des arguments.
    Par ailleurs, il reste possible de lancer ‘/sbin/init’ ou ‘supervisord’ pour faire tourner plusieurs applis ou services dans un conteneur. Perso, j’aime bien avoir un sshd dans chaque conteneur, même si j’ai appris à me passer de crond et syslogd.
    Le plus dur est de « concevoir » le Dockerfile qui va bien afin de pouvoir reconstruire les conteneurs en préservant les données. Pour cela la directive VOLUME s’avère indispensable…
    Merci pour cette belle intro, je vais la faire tourner !

    • jb_barth

      Question ouverte, as-tu essayé nsenter ou nsinit en remplacement de sshd ? http://jpetazzo.github.io/2014/03/23/lxc-attach-nsinit-nsenter-docker-0-9/ ; c’est un choix d’archi qui me pose question en ce moment aussi…

      • olivierlm

        Mon besoin : me connecter de l’extérieur directement dans mes conteneurs (pour éditer des fichiers avec emacs et tramp par exemple :))
        – nsinit : compil pas triviale (plusieurs dépôts github à récupérer), requiert d’être root, de se placer dans le répertoire d’exécution du conteneur => trop contraignant
        – nsenter : compil (car debian) triviale, pas de changement de répertoire requis, mais besoin d’être root pour accéder au namespaces
        – lxc-attach : changement de moteur de natif à lxc requis => dommage de se priver des performances de libcontainer
        Conclusion : un serveur ssh dans chaque conteneur me va très bien et n’est pas vraiment couteux…

        Merci de ta question (j’ai attrapé deux ou trois références intéressantes au vol, comme asciinema ;))

  • tuxplanet

    Salut, il y a un truc que je pige pas avec Docker. C’est marqué partout que ce concept permet de s’affranchir de l’OS, on virtualise uniquement l’application.

    Jusque là, je trouve ça bien, mais quand on déclare un dockerfile, on précise l’OS avec le mot clé FROM. Pour moi, cela revient à mettre dans un conteneur à la fois le Guest OS et l’application. Et du coup je vois plus très bien la différence avec une VM…

    • jb_barth

      Ton process tourne dans un environnement dont tu choisis le système, mais c’est juste pour avoir les lib et les utilitaires de base présents. Quand le conteneur est lancé ton application tourne comme un process (isolé, certes) sur le système hôte, en partageant le kernel et les appels systèmes avec ton système hôte. Bref tu ne « gères » pas ce système dans le conteneur, il n’y a aucun démon qui tourne hormis ton application, et il n’y a aucun « coût » d’initialisation (choisir un hostname, attribuer une IP, tailler des disques, etc). A comparer avec de la virtualisation classique, où chaque VM se gère indépendamment et doit être maintenue, administré indépendamment, etc.

      • tuxplanet

        1/ Il reste quand même des actions systèmes à gérer pour moi. Par exemple, si je veux que mon conteneur soit « uptodate », il faut y activer les mises à jour automatique au niveau de l’OS…

        2/ Sinon tu indiques qu’il n’y a pas de hostname ou d’IP à gérer. Du coup j’ai du mal à comprendre comment les utilisateurs accèdent aux applications. Aujourd’hui, par exemple, nous avons une architecture de 30 VM qui hébergent des applications JAVA. Devant sont positionnés des frontaux Apache qui assurent l’accès (notion de virtualhost, dns, cache, acl…). Comment sera cette architecture si on devait la reconstruire sous docker ? J’imagine un conteneur « Tomcat+Java » par application, mais j’ai du mal à imaginer l’aspect accès web/frontaux pour les utilisateurs…

        3/ Pour les accès par les développeurs, j’ai également du mal à imaginer le truc. Toujours en reprenant mon architecture d’applications Tomcat/Java par VM cité ci-dessus, Aujourd’hui chaque devs à des accès SSH à une liste de VM. Avec docker, cela revient à tout mettre tous les conteneurs au même endroits. Du coup comment on fait ? Car visiblement il n’y a plus de notion de SSH, ce qui revient à donner des accès à tous les développeurs à l’ensemble de la plateforme (= l’ensemble des conteneur). Ca va vite être le bordel ?

        4/ Concernant la haute disponibilité : les systèmes actuels de virtualisation sont capable de basculer une VM d’une hote vers un autre en cas de problème. J’ai rien vu de tel pour docker. J’imagine que cela doit être facilement réalisable ? un système ou les conteneurs sont automatiquement migrés entre des machines physiques. Mais pour l’instant, tant que ça n’existe pas, je pense que ce sera un gros frein pour l’adoption de cette technologie en entreprise.

        Bref, une techno intéressante, mais qui suscite encore beaucoup de questions dans mon esprit.

        • olivierlm

          1/ Si ton Dockerfile est bien conçu, tu peux supprimer un conteneur, le reconstruire (donc up-to-date) et retrouver ton service en quelques seconde

          2/ L’accès aux conteneurs peut s’organiser de différentes façons, mais généralement en utilisant la directive EXPOSE et l’argument publish de la commande ‘docker run’

          3/ Soit les dev accèdent au conteneurs via ssh par rebonds en contrôlant les accès par la publication des clés, soit tu construis leur conteneur directement avec les Dockerfile qu’ils te fournissent, ou encore tes Dockerfile inclut un ‘git pull’ de leur dépôt applicatif

          4/ Pour la HA, voir shipyard. Nativement tu peux exporter un conteneur sous la forme d’une archive et évidemment importer une archive pour générer un conteneur.

          PS : Nos 75 VM Linux sont toutes des conteneurs LXC (réparties sur 4 hôtes) et nous devrons migrer vers Docker dans le cadre du passage envisagé vers OpenStack. Toutefois, ça risque d’être douloureux, la philosophie Docker étant assez éloignée da celle du sysadmin traditionnel.

          • tuxplanet

            Pour le 1 : effectivement si on reconstruit le conteneur on est uptodate. L’utilisation de docker implique donc de programmer un reboot periodique des conteneurs pour être au top niveau sécurité. Je suis pas contre le principe, on essaye d’ailleurs de mettre en place le reboot périodique des VM chez nous pour avoir des OS à jour. C’est une autre vision de l’administration, peut-être à mettre plus en avant.

            Pour le 2 : j’ai bien vu la directive EXPOSE. Ça reste toujours flou dans ma tête. Imaginons, j’ai une plateforme de 100 conteneurs, si ils ont tous un expose 80, il y a un moment ou ça coince. Natter toutes les connexions ça doit pas être la joie à gérer. Bref, j’ai toujours des doutes sur la gestion à ce niveau.

            Pour le 3 : ok.

            Pour le 4 : ok, mais avec des solutions comme VMware, c’est plutôt simple à mettre en oeuvre et ne coute quasiment rien en temps d’administration. Là, à mon avis, le produit est trop jeune de ce coté, la preuve, tu décris une méthode manuelle.

            Sinon de façon générale, je suis assez avide d’un retour d’expérience sur la migration d’une infra de VM vers des conteneurs. Comme tu le dit, ça va être douloureux et c’était mon sentiment de départ. Ne doit-on pas attendre que le produit évolue et règle certains problèmes ? En tous les cas, si tu as des choses à faire partager, n’hésite pas 🙂

          • jb_barth

            Pour le 2 sur des applis HTTP, chez moi on va laisser sur l’hôte des vhosts nommés (apache/nginx) qui redirigeront vers des ports internes. On dit à docker d’exposer son 80 à l’extérieur sur chaque conteneur, il prend des ports dans des tranches hautes pour les mapper sur le host, et mon apache local fait du ProxyPass / http://localhost:49123/ ou équivalent nginx.

          • tuxplanet

            Tu fait tourner le service Apache sur la machine phisyque ? Pourquoi ne pas en faire un conteneur aussi ?

          • jb_barth

            C’est possible aussi, pas encore décidé.

          • jb_barth

            olivierlm a quasiment tout dit 🙂

            Pour la HA, soit c’est géré au niveau applicatif (applis http stateless avec un load balancer devant, et bases de données en réplication ; ou artefacts systèmes type heartbear/pacemaker/corosync…), soit (un jour) ça se gérera au niveau de docker en mode « migration de conteneur d’une machine à une autre ». Voir http://criu.org/Main_Page un projet qui vise à sauvegarder un process ou un conteneur et le restaurer ailleurs. Mais à mon avis c’est pas encore prod-ready.

  • Pingback: Virtualisation légère avec Docker...()

  • Kromak7

    ça a l’air absolument génial !

    est-il possible de faire discuter les instances entre elles ? Pour être plus clair, est-il possible de simuler une architecture client/serveur, en mettant plusieurs clients en place et un serveur ? Parce que faire ça avec des VM, c’est long… et ça bouffe des ressources !!

  • Adminrezo

    Merci pour l’article.
    J’ai pas mal bossé sur Docker ces derniers temps et j’ai écrits quelques articles dessus si ça peut en intéresser certains :
    http://blog.adminrezo.fr/tag/docker

  • Effectivement ce genre de technos a le vent en poupe ! Il y a aussi Vagrant qui fait beaucoup parler de lui 🙂

  • Matthieu

    Quand je lis, heureusement pas ici, la comparaison de Docker avec du Vmware ou du Hyper-V, ca fait peur! Docker est vraiment fait pour des développeurs et non pour l’infrastructure!
    Très bel article! et très beau produit!

  • Patrice Oliver

    Très bel article. Merci Nico.
    Pouvons-nous dire que nous approchons la bulle applicative ?

    Bonne journée.

    • Docker ne fait que démocratiser des technologies déjà utilisées dans les solutions PaaS, mais au final, cela permet de trouver de nouveaux usage notamment au niveau des workflows de développement.

  • Tommy Sawyer

    Interessant ce sujet! Pour les nuls comme, ca revient donc à voir un structure comme Fedora qui tourne sur le noyau d’ubuntu, c’est ça? Et je peux avoir un conteneur pour les db, un pour http ou soit fusionner sur un conteneur les deux comme sur Virtualbox par exemple?

  • Pingback: Projet Docker LEMP : Réalisation - Mon pense bête()

  • Maxime @ Camptocamp

    Bonjour,

    Camptocamp, expert IT Open Source depuis 2001, propose dorénavant une formation Docker sur-mesure de 2 jours :

    http://www.camptocamp.com/formation/formation-docker-open-source/

    Bien cordialement, Maxime @ Camptocamp

  • Pingback: Installation et quelques tricks autour de Docker sur Debian – Theg's Tricks()

  • Pingback: Dockers Conteneurs | Pearltrees()

  • Pingback: Conteneur | Pearltrees()

  • Pingback: Virtualisation | Pearltrees()

  • Pingback: DÉCOUVERTE DE DOCKER – ATOMIT()

  • Pingback: Docker | Pearltrees()