Docker, et la conteneurisation de manière générale, sont devenus pratiques courantes et résolvent bien des problèmes depuis l’avènement de ces technologies : déploiement, isolation des applicatifs, environnement homogène… Si votre application fonctionne sur votre machine avec des conteneurs, elle fonctionnera assurément sur vos environnements de déploiement.
La technologie des conteneurs se rapprochent de la virtualisation tout en étant beaucoup plus légère : un conteneur n’embarque pas forcément un système d’exploitation. De par cette caractéristique très importante, les conteneurs sont ainsi plus appropriés pour rendre les applications portable (d’une machine à une autre ou d’un Cloud à un autre) que les VM.
La technologie Docker
À l’origine, Docker est une technologie issue du monde Open Source. L’entreprise de la Silicon Valley exploite en effet plusieurs composants du noyau Linux afin de concevoir ses conteneurs (LXC, Libvirt …).
Lancé par le français Solomon Hykes, Docker permet de faciliter les déploiements d’application et la gestion du dimensionnement de l’infrastructure. Cette technologie s’appuie sur une brique d’API standard (LXC sur Linux et Windows Server Container sur Windows) afin de fournir une couche d’abstraction permettant aux conteneurs de s’exécuter sur n’importe quelle machine. Docker à l’avantage d’être bien plus léger qu’une machine virtuelle. Le lancement d’un conteneur est également plus rapide, ce qui en fait une solution privilégiée pour le déploiement de ses applications.
Docker ne fait pas qu’aider les entreprises dans leurs déploiements, il permet également d’accélérer les évolutions des écosystèmes Cloud, et ça Microsoft, Amazon ou encore Google l’ont bien compris. En effet, avec les conteneurs, il est très facile de déployer les services Cloud on-demand. Par exemple, il est judicieux de conteneuriser les bases de données (MySQL, SQL Server …) afin de les déployer très rapidement selon la demande des utilisateurs.
Une réponse concrète à certains scénarios de développement
Cette technologie apporte une réponse concrète à certains scénarios de développement. Par exemple, vous souhaitez tester une nouvelle version d’un Framework sur votre applicatif ? Très simple ! Docker est fait de plusieurs images Docker qui s’empilent pour créer votre image Docker, il suffit donc de remplacer la couche souhaitée par la nouvelle version afin d’essayer votre application. Avec une VM, cela devient compliqué de changer de version car il faut désinstaller, puis installer la nouvelle version. Le temps perdu peut être conséquent.
Il en va de même pour la mise en production des applicatifs. Avec Docker, si l’application fonctionne sur votre machine, vous serez certain qu’elle fonctionnera sur l’environnement de production. Docker permet d’encapsuler toutes les dépendances relatives au système d’information, et ceci tout en conservant des systèmes sous-jacents propres (votre machine de développement par exemple). Vous n’avez pas besoin d’installer les dépendances, tout est embarqué dans le conteneur.
Le grand avantage de Docker est donc sa portabilité. Il est tellement portable qu’il est possible de faire tourner des images Docker sur des objets connectés. À partir du moment où des terminaux embarquent des noyaux Linux (Raspbian par exemple sur des Raspberry), il est possible de faire fonctionner Docker sur des objets connectés. Docker propose également depuis longtemps des outils Open Source afin de manipuler des conteneurs et tester des architectures sur des objets connectés : LinuxKit.
Une limite persiste tout de même avec Docker : il n’est pas possible de faire fonctionner des images créées avec Linux sur Windows, et réciproquement. Cependant, les équipes de Docker travaillent activement avec les équipes de Microsoft pour pallier à ce manque (notamment avec LinuxKit car il faut un minimum de noyau Linux pour faire fonctionner ce genre d’image Docker).
Installer Docker
La documentation de Docker explique très clairement comment installer Docker sur Linux et Windows. Sur Linux, c’est une série de commandes à lancer. Pour Windows, il faut installer Docker for Windows permettant ainsi de disposer de la technologie sur son poste. Une fois installée, on peut tester le CLI via la commande suivante :
> docker info
Cette commande donne accès à la version courante de Docker, mais également à toutes les images et les conteneurs du poste de travail. Afin de mieux tester l’installation, il suffit de lancer la commande suivante, qui va lancer une image très simple de test :
> docker run hello-world
L’image n’étant pas sur votre machine (si c’est la première fois), Docker va télécharger l’image et lancer le conteneur. Un message apparaît alors dans la console montrant que l’installation s’est bien passée :
La commande suivante permet de vérifier les images qui ont été téléchargées sur votre machine :
> docker image ls
Ensuite, cette commande permet de lister les conteneurs qui sont en cours de fonctionnement sur votre machine :
> docker container ls --all
Enfin, pour arrêter un conteneur, il suffit de lancer la commande suivante :
> docker stop NOM_DU_CONTENEUR
Les images
Un conteneur se construit à partir d’une image. Mais à partir de quoi se construit une image ? Docker se base sur des fichiers intitulés Dockerfile pour construire les images. Un Dockerfile contient une série d’instructions que Docker va exécuter afin de construire l’image finale qui va être stockée dans un registre d’image Docker. Le site Docker contient son propre registre public : https://hub.docker.com/.
Vous pouvez vous-même publier sur ce registre. Beaucoup de grandes compagnies comme Microsoft ont déjà poussé des images Docker sur ce registre afin que le grand public puisse les utiliser. Sinon, vous pouvez toujours installer un Hub privé sur vos serveurs, ou encore utiliser des services clé-en-main disponibles sur Azure ou AWS pour constituer vos Hub privés.
Une image est constituée de couches successives d’autres images Docker. Ainsi, lors de la constitution de son image Docker, on va commencer par s’appuyer sur une autre image afin de bénéficier des commandes lancées précédemment dans cette image. Dans un fichier Dockerfile, la ligne ci-dessous permet de s’appuyer sur une image comportant déjà le Framework .NET Core en version 2.2 :
FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base
La commande FROM permet cette succession de couche d’image Docker. À partir de là, notre image est capable de lancer des projets .NET Core car l’image microsoft/dotnet:2.2-aspnetcore-runtime a déjà installé le runtime .NET Core.
Analyse du Dockerfile
Visual Studio 2017 intègre un template de projet avec un Dockerfile déjà intégré permettant de démarrer rapidement sur un projet ASP.NET Core avec Docker. Nous allons décortiquer le Dockerfile généré afin de mieux comprendre ce que fait Docker :
Les trois premières lignes permettent d’exposer le port 80 du conteneur vers l’extérieur. Cela veut dire que lorsque l’application .NET Core va fonctionner, son port 80 va automatiquement être exposé vers l’extérieur, garantissant les échanges entre le monde extérieur et l’application .NET Core fonctionnant à l’intérieur du conteneur.
Les lignes suivantes permettent de copier le .csproj du projet dans le conteneur Docker afin de restaurer les paquets Nuget :
Ensuite, les 3 lignes suivantes permettent de copier tout le code source afin de lancer la commande dotnet build à l’intérieur du conteneur :
Enfin, Docker va lancer une publication via la commande dotnet publish, puis va lancer l’applicatif qui en résulte :
Quelques remarques par rapport à ces dernières lignes :
- FROM build AS publish permet de n’utiliser que l’image avec le SDK .NET Core, c’est-à-dire les commandes de build. Ceci est une micro-optimisation car l’image est plus petite que si on prenait l’image avec tout le SDK .NET Core ;
- FROM base AS final permet d’utiliser uniquement l’image avec le runtime .NET Core pour lancer le projet.
Syntaxe personnalisée
Docker possède sa petite syntaxe personnalisée pour effectuer quelques commandes dans un Dockerfile. La documentation est très bien fournie à ce sujet : https://docs.docker.com/engine/reference/builder/.
Une fois votre fichier complété, il suffit de lancer la commande suivante dans le dossier qui contient le Dockerfile :
docker build .
Une fois lancé, on peut s’apercevoir que Docker lance les commandes inscrites dans le Dockerfile sous la forme d’étapes qui s’enchaînent dans la console :
Si vous lancez une deuxième fois la commande, on peut s’apercevoir que Docker réutilise le résultat de la dernière build sur chaque couche déjà utilisée. C’est ici toute la puissance de Docker : ce système de cache permet de rapidement construire des images qui peuvent au final être conséquentes.
Au final, Docker indique que la build s’est bien passée. Nous n’avons pas donné de nom à notre image, mais Docker se charge de donner un identifiant unique pour pouvoir la retrouver.
Cette image est pour le moment sur votre ordinateur, et peut être lancée à tout moment via la commande suivante :
docker run f0568f9b129c
Nous pouvons constater que l’application se lance comme si on l’avait lancée sur le PC, mais ici le serveur fonctionne dans le conteneur Docker.
C’est ici toute la force de Docker. Il permet d’encapsuler l’exécution d’une application, et ainsi de la rendre portable de machine en machine. Notre application fonctionnant sur notre machine de développement, nous sommes certains que cette application fonctionnera sur un environnement différent supportant Docker (pré-production, production …).