> Tech > Voyage au pays des Containers, étape 2

Voyage au pays des Containers, étape 2

Tech - Par iTPro.fr - Publié le 04 mai 2017
email

Après les concepts et les principaux composants, poursuivons sur l'étape 2 de ce Voyage au pays des Containers avec Antonin D'Enfert, Consultant Cloud et Infrastructure chez Avanade France et découvrons le cycle de vie et l'écosystème.

Voyage au pays des Containers, étape 2

   1 – Les Containers à l’ordre du DevOps

Pour rappel, l’un des éléments clés du ‘renouveau’ de la containerisation d’applications s’explique par son intégration naturelle dans le paysage informatique actuel, en particulier l’approche DevOps qui vise à fluidifier et accélérer le cycle de vie des applications par différentes pratiques affectant tout autant les outils et les processus de développement et d’opérations que la gouvernance et la culture des développeurs et des opérationnels.

En effet, l’un des leviers de cette approche vise notamment à briser les barrières culturelles historiques qui séparent les Dev et les Ops.

Les Containers, et en particulier Docker, facilitent l’approche DevOps car ils proposent de standardiser différents niveaux du cycle de vie d’une application.

1 – Les Containers sont les mêmes quels que soient le langage, la plateforme ou l’application qu’ils contiennent

2 – Ils se créent, se stockent et se déploient de la même manière quels que soient l’OS, l’environnement ou la phase du cycle de vie de l’application

3 – Les commandes et les APIs pour les manipuler ainsi que le vocabulaire associé sont les mêmes pour les Dev et les Ops

A cela, s’ajoutent leur isolation mais surtout leur indépendance vis-à-vis de l’environnement, grâce à la gestion transparente des dépendances.

Ces deux éléments sont clés pour fiabiliser les déploiements et faciliter le Continuous Delivery.

   2 – Cycle de vie des Containers

Containers pour les ‘Dev’

Pour les Dev, les Containers s’intègrent au cycle de développement, en particulier itératif, durant toutes ses phases, de l’écriture du code à la release, en passant par le build et le test.

La containerisation avec Docker peut s’effectuer de plusieurs manières dont le résultat reste inchangé.

– Création d’une Container Image ou Image contenant l’application et ses dépendances

– Mise à disposition de cette Image au sein d’un Registry on premise ou cloud

Création ‘manuelle’ d’Image

La première méthode consiste simplement à instancier un Container à partir d’une Image contenant les prérequis nécessaires, d’intégrer ensuite l’application ou le service souhaité puis de ‘capturer’ le contenu du Container ainsi modifié pour produire une Image dans le Registry local de l’hôte sur lequel le Container a été lancé. L’Image sera ensuite uploadée sur un Registry pour y être publiée.

Voici un exemple de containerisation d’une application web basée sur le serveur web Nginx. Toutes les commandes sont lancées depuis le Docker CLI (Command Line Interface) et passées au Docker Engine local ou d’un hôte distant :

1. docker pull nginx : téléchargement de l’Image officielle contenant le serveur web Nginx ainsi que ses dépendances, en l’occurrence un empilement d’Images dont la Base Image n’est autre que la distribution Linux Alpine. A noter que de l’empilement d’Images téléchargées, seules le seront celles qui n’existent pas déjà dans le cache/Registry local du Container host.

2. docker run –it nginx : instanciation de l’Image Nginx sous forme de Container. Les paramètres –i et –t (ici concaténé –it) permettent de lancer le Container en mode interactif pour pouvoir lui passer des commandes directement. A l’inverse un Container peut être lancé en arrière-plan comme un service ou un ‘deamon’ en remplaçant –it par –d. A noter qu’avec la commande run, si l’Image Nginx n’existe pas déjà en local, la commande pull est implicite et exécutée automatiquement.

3. ‘modification’ : modification du Container pour y intégrer le contenu souhaité, il s’agit ici de copier une application web depuis le repo contenant le code source vers le répertoire correspondant au sein du Container soit à l’aide de la commande docker cp soit à l’aide de commandes passées grâce au mode interactif.

4. docker commit [ID du container] myaccount/myapp:v1 : capture du Container pour créer une Image nommée ‘myapp’ portant le tag ‘v1’ et attachée au compte ‘myaccount’. A noter que l’ID du Container peut être récupérée à l’aide de la commande docker ps qui liste les Images actuellement en cours d’exécution.

5. Docker push myaccount/myapp:v1 : upload de l’Image nouvellement créée dans le Registry actuellement configuré. myaccount/myapp représente le ‘namespace’ dans lequel sera stocké l’Image. Il est constitué par le nom de compte ‘myaccount’ et du Repository ‘myapp’ contenant une ou plusieurs versions de l’Image du même nom.

Création ‘automatique’ d’Image avec un ‘Dockerfile’ 

Afin d’automatiser et de fiabiliser ce processus, les étapes 1 à 4 peuvent être remplacées par un fichier de configuration appelé Dockerfile qui est lu et exécuté par la commande docker build. Un Dockerfile décrit de manière séquentielle les étapes de création d’une Image dans un simple fichier texte. La commande docker build exploitera ensuite ce fichier afin de créer l’Image.

L’un des avantages majeurs est d’intégrer la création d’Image dans un processus de Continuous Integration. Il est, par exemple, possible de monitorer GitHub à l’aide de ‘web hook’ afin de déclencher automatiquement le build d’une nouvelle Image à la suite d’un nouveau commit de code.

Un Dockerfile est constitué des principaux éléments suivants :

FROM : spécifie l’Image parente à partir de laquelle sera instancié un Container

ADD/COPY : permet de copier du contenu (fichiers/dossiers) depuis un chemin local ou URL vers un chemin à l’intérieur du Container

EXPOSE : spécifie un port exposé sur lequel le Container écoutera lors de son exécution

RUN : exécute une ou plusieurs instructions afin de modifier le contenu du Container et capture ces changements effectués au sein d’une nouvelle Image. Un Dockerfile contient souvent plusieurs étapes ‘RUN’ qui, à chaque fois, constituent une nouvelle couche de l’Image finale

CMD : définit la commande et donc le processus qui sera exécuté par défaut lorsque l’Image est instanciée sous forme d’un Container. Une autre commande par défaut peut être spécifiée lors de l’exécution du Container afin d’écraser ce paramètre

ENTRYPOINT : équivalent de ‘CMD’ mais la commande spécifiée ne pourra pas être écrasée lors de l’exécution du Container

Etant donné que chaque instruction ‘RUN’ créera une nouvelle couche dans l’Image finale, il est judicieux de grouper certaines commandes à exécuter au sein d’une seule étape ‘RUN’ afin d’optimiser le nombre de couche de l’Image finale.

Containers pour les ‘Ops’ 

Pour les Ops, Docker intègre le cycle opérationnel d’une application dès sa mise à disposition sur un Registry on premise ou cloud depuis lequel elle peut être déployée à l’aide des mêmes commandes que celles utilisées par les développeurs (Pull/Run).

Cette continuité avec le cycle de développement ainsi que l’isolation et l’indépendance des Containers simplifient et fiabilisent le processus de déploiement, ce qui facilite l’automatisation des opérations à l’aide d’outils d’orchestration utilisant l’API de Docker.

Voici un exemple de mise en œuvre d’un cercle vertueux DevOps.

1. Notifications et déploiement automatiques en cas de nouvelle version d’une Image mise à disposition dans un Repository

2. Monitoring de l’application à différents niveaux (disponibilité, performance, user expérience…) et roll-back automatisé vers la version précédente en cas d’incident

3. Génération de rapports à destination des développeurs de manière régulière pour fournir des informations télémétriques mais aussi ponctuellement en cas d’incident pour fournir les logs associés

4. Prise en compte des rapports dans le cycle de développement afin de revoir les priorités de mises à jour correctives ou d’intégrer de nouvelles évolutions. La mise à disposition d’une nouvelle version déclenchera un nouveau cycle

   3 – Ecosystème et plugins 

Batterie incluse mais remplaçable 

Il est une notion chère au modèle développé par Docker, celle de la « batterie incluse mais remplaçable » qui signifie que Docker propose des fonctionnalités ‘built-in’ qui sont complétées par des plugins ou drivers. C’est le cas, par exemple, de la provision d’hôte, de la création de réseaux virtuels et de volumes dédiés aux Containers. Ces fonctionnalités, détaillées ci-après, peuvent chacune exploiter des plugins ou drivers afin d’étendre leurs capacités de sorte à s’interfacer avec des technologies existantes proposées par d’autres éditeurs.

Docker Machine, et l’hôte fut …

Docker Machine est un utilitaire qui permet de provisionner des Container Host de manière automatique soit en créant une machine virtuelle dans laquelle seront installés et configurés l’OS et le Docker Engine, soit en installant et configurant le Docker Engine sur une machine existante. C’est aussi Docker Machine qui se charge d’identifier et de modifier l’hôte cible auquel sont transmises les commandes passées au Docker CLI.

A l’aide de drivers, Docker Machine permet de provisionner des hôtes Docker.

– Sur la machine locale en s’appuyant sur l’hyperviseur installé (Hyper-V, Virtual box, VMware…)

– Dans un cloud public (Azure, Amazon AWS, Digital Ocean…)

– A partir de machines physique ou virtuelles existantes

Docker Volume, et la persistance fut…

Pour rappel, les Containers sont par essence ‘stateless’ donc plutôt adaptés à contenir la logique applicative sans en conserver, après exécution, ni état ou ni données produites, qu’il s’agisse de journalisation ou de données dites de production. Pour stocker ces données et rendre ainsi les applications ‘statefull’, Docker intègre la fonctionnalité Volume qui permet de mapper un chemin local à l’hôte vers un chemin interne au système de fichier du Container.

Parmi les cas d’usage, un Container exécutant un moteur de base de données pourra être arrêté, supprimé, puis relancé en étant rattaché au même Volume contenant les logs et les bases de données et ainsi récupérer les données précédemment produites. Les Volumes ont, d’ailleurs, l’avantage de proposer de meilleures performances en lecture et écriture que le système de fichier du Container lui-même, ce qui peut être utile pour les applications exigeantes.

Un autre cas d’usage utile lors du cycle de développement, consiste à monter dans le Container les sources d’une application web stockées localement pour pouvoir les modifier à chaud sans mode interactif et sans relancer le Container. L’exemple de commande ci-dessous lance en arrière-plan un Container Nginx au sein duquel ‘/home/demo/html’ mappera vers le chemin ‘/usr/share/nginx/html’ de la machine hôte :

docker run -d -v /home/demo/htlm:/usr/share/nginx/html nginx

Côté plugin, les principaux permettent de monter des Volumes depuis des espaces accessibles sur le réseau ou de les migrer d’un hôte à l’autre pour résoudre des problématiques de multi-hôte en clusters.

Depuis peu, les Volumes sont des objets à part entière qui peuvent être créés et nommés indépendamment avec la commande docker volume create pour être attachés par la suite à un ou plusieurs Containers, cependant Docker ne possède pas de mécanisme pour limiter les écritures concurrentes ce qui doit être géré au niveau applicatif pour éviter les corruptions.

Docker Network, et la connectivité fut …

Dans le même esprit d’abstraction et d’indépendance des Containers vis-à-vis des environnements et plus précisément de l’infrastructure réseau sous-jacente, Docker intègre une fonctionnalité de virtualisation réseau reposant sur de l’encapsulation VxLan.

C’est un exemple parfait de Software Defined Network qui permet la connectivité entre Containers qu’ils soient ou non exécutés sur le même hôte.

Cette connectivité étant sélective il s’agit aussi de ségrégation entre des groupes de Containers puisqu’en en spécifiant explicitement la connexion d’un Container à un Network, celui-ci ne pourra communiquer qu’avec les Containers joints à ce même Network, permettant donc l’isolation des composants applicatifs les uns par rapport aux autres.

Docker Network repose sur le Container Network Model (CNM) constitué des éléments suivants

Network : réseau virtuel permettant de connecter des Containers afin qu’ils puissent communiquer entre eux et/ou avec le monde extérieur

Endpoint : interface réseau d’un Container. Chaque connexion d’un Container à un réseau se fait au travers d’un Endpoint

Network Sandbox : élément logique contenant les Endpoints, donc la configuration réseau d’un Container mais isolé de ce dernier pour permettre une gestion indépendante du Container lui-même

Les Networks s’appuient sur des plugins ou drivers qui définissent leur scope et leurs fonctionnement. Un Network peut être local à un hôte ou étendu sur plusieurs hôtes distants afin de connecter, toujours de manière sélective, les Containers qu’ils exécutent.

Docker intègre deux drivers Network par défaut

Bridge : c’est le driver par défaut dans les situations d’hôte unique. Il permet de créer des Networks pour connecter des Containers d’un même hôte entre eux mais il est aussi responsable d’exposer les ports des Containers grâce au NAT lorsque ceux-ci sont exécutés avec l’option -p

Overlay : c’est le driver par défaut dans les situations d’hôte multiple. Ce driver permet de créer des Network étendus et disponibles sur plusieurs hôtes afin de connecter des Containers exécutés sur ces hôtes distants

Les Networks sont désormais eux aussi des objets à part entière qui peuvent être créés et nommés indépendamment avec la commande docker network create pour être attachés, par la suite, à un ou plusieurs Containers avec la commande docker network connect. Depuis la version 1.10 de Docker, la résolution DNS est intégrée afin de résoudre le nom des Containers en IP sans passer par la modification du fichier HOST des Containers.

L’exemple, ci-dessous, fonctionne aussi bien sur un hôte unique ou sur un cluster constitué de multiples hôtes avec pour seule différence le driver par défaut.

– Deux réseaux sont créés et respectivement nommés FRONTEND et BACKEND

– x1 Container nommé DB est attaché à FRONTEND

– x1 Container nommé WORKER est attaché à FRONTEND et BACKEND

– x1 Container nommé WEB est attaché à FRONTEND. Son port 80 est exposé sur le port 80 de l’hôte grâce au NAT en l’attachant au ‘bridge’ par défaut nommé Docker0.

Les conséquences de cette configuration sont les suivantes

– Seul, le Container WEB peut communiquer avec le monde extérieur et ce, uniquement sur le port 80

– Les Containers WEB et WORKER peuvent communiquer entre eux quel que soit le port

– Les Containers WORKER et DB peuvent communiquer entre eux quel que soit le port

– Les Containers WEB et DB ne peuvent pas communiquer entre eux

 4 – Dernière étape, orchestration et produits clés en main 

Sur les bases du Container, des Images, du Registry, ces fonctionnalités vues précédemment permettent de répondre aux besoins

– De connectivité avec Docker Network

– De persistance avec Docker Volume

– D’automatisation du cycle de développement avec le Registry, Dockerfile et Docker Machine

Mais, ce n’est qu’une partie de l’équation pour répondre aux besoins des applications modernes hautement distribuées et complexes, potentiellement constituées en microservice.

Pour ces exigences-là, il faut pouvoir créer aussi facilement qu’avec un Dockerfile des applications constituées de multiples Containers de manière consistante et cohérente et être capable de les déployer de cette même manière avec leurs Networks et leurs Volumes associés.

C’est l’équation à laquelle tente de répondre Docker Compose et Docker Swarm. Le premier a pour rôle de créer et de manager des applications multi Containers, tandis que le second a pour but de créer et manager des clusters sur lesquels déployer de manière automatisée ces applications distribuées sans pour autant modifier l’API utilisé.

Autour d’eux, Docker Inc. a développé deux produits d’orchestration de Containers ‘clés en main’, l’un on premise, Docker Data Center et l’autre cloud, Docker Cloud (anciennement Tutum). Ils viennent concurrencer d’autres produits ‘clés en main’ existants que sont Openshift (basés sur Kubernetes), Azure Container Service (basés sur Mesos Marathon), Amazon EC2 Container Service… avec pour principal intérêt d’être hybrides et multi-cloud.

C’est sur ce terrain de l’orchestration que se joueront les principales évolutions à venir autour de la containerisation, et par conséquent l’adoption de la containerisation par les entreprises de toute taille.

Téléchargez cette ressource

Travail à distance – Guide complet pour les Directions IT et Métiers

Travail à distance – Guide complet pour les Directions IT et Métiers

Le travail à distance met à l'épreuve la maturité numérique des entreprises en termes de Cybersécurité, d'espace de travail, de bien-être des collaborateurs, de communication et gestion de projet à distance. Découvrez, dans ce nouveau Guide Kyocera, quels leviers activer prioritairement pour mettre en place des solutions de travail à domicile efficaces, pérennes et sécurisées.

Tech - Par iTPro.fr - Publié le 04 mai 2017