WebApi sous Linux avec ASP.NET 5 et Docker

La sortie prochaine d’ASP.NET 5 ouvre de nombreuses perspectives aux développeurs .NET. En particulier, la possibilité de compiler et exécuter du code .Net sur n’importe quelle plateforme. Nous allons voir ici comment compiler et exécuter une application ASP.NET 5 sous Linux avec Docker.
Cet exemple a été réalisé avec Windows 10 et Powershell, mais la majorité de l’article peut être effectué avec une autre configuration.
Docker Setup
Nous allons commencer par installer Docker. Sous Windows, il faut installer la Docker Toolbox :
https://docs.docker.com/windows/step_one/
Note : Il faut désactiver la fonctionnalité Hyper-V de Windows pour que VirtualBox fonctionne.
La toolbox installe tout ce qu’il faut pour faire tourner Docker sous Windows. Notamment VirtualBox, qui permettra d’avoir une machine virtuelle Linux. Elle installe une invite de commande spécifique, mais toutes les manipulations peuvent être faites dans la commande de votre choix. Nous allons ici utiliser Powershell.
Docker ne fonctionne pas encore de façon native sous Windows, il faut donc commencer par créer une machine Docker avec l’utilitaire docker-machine :
docker-machine create -d virtualbox default
Le nom de notre machine est default, et nous l’avons créée avec VirtualBox.
Pour pouvoir travailler avec Docker sur cette machine, la session Powershell courante doit connaître les informations de celle-ci. Pour cela, nous exécutons la commande suivante :
docker-machine env default --shell powershell | Invoke-Expression
Notre machine Docker est prête à être utilisée. Pour le vérifier nous allons lancer un conteneur Docker simple :
docker run hello-world
Docker doit télécharger l’image hello-world, et lancer le conteneur qui affiche “Hello from Docker”.
Service
Nous allons maintenant créer un service WebApi très simple avec ASP.NET 5.
Si vous n’avez pas déjà installé ASP.NET 5, vous pouvez le faire en suivant ce lien :
http://docs.asp.net/en/latest/getting-started/installing-on-windows.html
La version du framework utilisée (dnx) dans l’image docker de ce post est coreclr 1.0.0-rc1-final X64, voici la commande pour l’installer :
dnvm install 1.0.0-rc1-final -x64 -alias default -r coreclr
Notre projet est composé de 2 fichiers : Service.cs et project.json
project.json contient la configuration de notre application :
{ "dependencies": { "Microsoft.AspNet.Mvc": "6.0.0-rc1-final", "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final" }, "commands": { "kestrel": "Microsoft.AspNet.Server.Kestrel --server.urls http://+:5000" }, "frameworks": { "DNXCore50": { } } }
“dependencies” est la liste des dépendances de notre projet :
– Mvc (dans ASP.NET 5 mvc et WebApi ne font plus qu’un),
– Kestrel : le serveur web d’ASP.NET qui tourne sur tous les OS.
“commands” est la liste des commandes disponibles de notre projet : ici la commande kestrel lance notre service dans Kestrel. Celui-ci écoutera toutes les adresses sur le port 5000.
“frameworks” est la liste des frameworks .NET sur lesquels notre application peut tourner. Ici nous n’autoriserons que dnxcore50.
Service.cs contient le code de notre service :
using Microsoft.AspNet.Builder; using Microsoft.Extensions.DependencyInjection; using System.Collections.Generic; using Microsoft.AspNet.Mvc; namespace TestApp { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } public void Configure(IApplicationBuilder app) { app.UseMvc(builder => { builder.MapRoute( "test", "api/tests", new { controller = "test", action = "GetAll" }); }); } } public class TestController : Controller { public IEnumerable<string> GetAll() { return new[] { "Hello" , "from docker !" }; } } }
La classe startup contient le pipeline ASP.NET 5. Nous définissons ici que nous allons utiliser MVC. Et nous configurons une seule route : /api/tests.
La classe TestController est notre contrôleur, celui-ne définit qu’une méthode “GetAll” qui a été mappée à l’url “/api/tests” dans le startup.
Pour tester compiler et lancer le service, nous exécutons les commandes suivantes :
dnu restore
dnx kestrel
Dnu restore va restaurer les dépendances de notre projet (c’est l’équivalent du restore package de nuget).
Dnx compile et lance l’application, la commande kestrel correspond à celle spécifiée dans le fichier project.json.
Deploy service
Un container Docker est un empilement d’images, la première étant l’OS qui héberge nos applications. Beaucoup d’images existantes peuvent donc être utilisées, la source principale d’image étant DockerHub.
Pour déployer notre service, nous allons utiliser l’image aspnet. Pour lancer un conteneur avec cette image, nous exécutons la commande suivante :
docker run -ti microsoft/aspnet:1.0.0-rc1-final-coreclr /bin/bash
Nous avons ici demandé à Docker de lancer un conteneur avec l’image microsoft/aspnet, à sa version 1.0.0-rc1-final-coreclr, et d’y exécuter une commande bash. Les paramètres “ti” permettent de rediriger les entrées/sorties du conteneur vers notre terminal.
Une fois cette commande lancée, nous pouvons contrôler le conteneur comme sur une VM. Nous pouvons par exemple vérifier que la dnvm est bien installée, et voir quelle version de dnx est utilisée par défaut :
Pour créer une image docker, nous allons créer un fichier Dockerfile, dans le même répertoire que nos fichiers sources :
# Notre image se base sur celle d'aspnet FROM microsoft/aspnet:1.0.0-rc1-final-coreclr # Copie des sources dans un répertoire app COPY . /app # Curseur dans le répertoire app WORKDIR /app # Restauration des dépendances RUN ["dnu", "restore"] # Notre service est exposé sur le port 5000 EXPOSE 5000 # Commande de lancement du service à exécuter au lancement du conteneur ENTRYPOINT ["dnx", "kestrel"]
Pour construire l’image docker avec le Dockerfile, nous exécutons la commande Powershell suivante :
docker build -t testapp .
La commande Powershell suivante nous permet de lister nos images locales, nous pouvons donc vérifier que notre image “testapp” a bien été créée :
docker images
Il ne nous reste plus qu’à lancer un conteneur à partir de notre image :
docker run -d -p 80:5000 testapp
Nous avons lancé un conteneur en mode détaché (-d) c’est à dire que la commande nous a rendu la main immédiatement, mais que le conteneur est en cours d’exécution.
Nous avons aussi spécifié un mapping entre le port 5000 de notre conteneur et le port 80 de notre VM (-p 80:5000).
Pour connaitre l’IP de notre VM, nous pouvons exécuter la commande suivante :
docker-machine ip default
Si tout s’est bien passé, l’url http://IpDeLaVM/api/tests retourne maintenant le résultat de notre service !!
Voilà, nous avons bien un service .Net qui tourne sous Linux dans un conteneur docker, que l’on peut déployer à notre convenance, n’est-ce pas merveilleux ?! 🙂