Docker ASP.NET MVC image creation issue ‘GetFileAttributesEx : The system cannot find the path specified’

When using Visual Studio 2017 and trying to create a Docker image for your ASP.NET web app from the standard microsoft\aspnet image (or another image), you may have the following error message : GetFileAttributesEx bin\Release\PublishOutput : The system cannot find the path specified

image

This error is caused by the .dockerignore file generated by Visual Studio 2017 (more information on .dockerignore file : https://docs.docker.com/engine/reference/builder/#dockerignore-file).

How to solve the issue

  1. Open and edit the .dockerignore file located at the root of your Visual Studio project
  2. Remove the first line with the ‘*’ (this is the guilty line !)
  3. Save the modified .dockerignore file
  4. Re execute your docker build command (ex : docker build –t <your tag> .)

Original Visual Studio 2017 .dockerignore file :

image

The corrected .dockerignore file :

image

Check your web app to know if everything works fine

  1. First, you won’t be able to use the URL http://localhost, you need the IP address of the container. To find it, execute this command in Powershell :
  2. docker inspect -f "{{ .NetworkSettings.Networks.nat.IPAddress }}" ncit_liasse

  3. Open your favorite browser and enter the URL http//<your ip address> to show you web app shining

image

More documentation on the use of this image at https://hub.docker.com/r/microsoft/aspnet/

Useful documentation on how to migrate an ASP.NET MVC application to Docker : https://docs.microsoft.com/en-us/aspnet/mvc/overview/deployment/docker-aspnetmvc

Now enjoy migrating your ASP.NET MVC web apps to Docker containers !

Déployer un site ASP.NET Core dans un conteneur Nano Server

Avec l’arrivée de Windows Server 2016, les entreprises se voit maintenant dotées d’un nouveau type de conteneur : les conteneurs Windows (exécutant Windows Server Core et Nano Server). A l’instar des conteneurs Linux, les conteneurs Windows possèdent leurs propres images disponible sur le Docker Hub. L’agnosticité de Docker (peu importe le fournisseur ou la technologie sous-jacente) et les capacités multiplateforme de .NET Core vont nous permettre de migrer une application ASP.NET Core existante s’exécutant dans conteneur Linux (cf dernier post) vers Nano Server sous Windows Server 2016.

Migrer vers un conteneur Windows

Lors du dernier post sur le sujet, nous avions vu comment déployer une application ASP.NET MVC Core dans un conteneur Linux. Voici le Dockerfile (que j’ai nommé Dockerfile.nanoserver permettant d’avoir un Dockerfile par type de conteneur) permettant de déployer la même application dans un conteneur Windows :

FROM microsoft/dotnet:nanoserver
 
COPY . /app
WORKDIR /app
RUN ["dotnet", "restore"]
RUN ["dotnet", "build"]
 
EXPOSE 5000/tcp
ENTRYPOINT ["dotnet", "run", "--server.urls", http://*:5000]

Constat : la seule différence à ce fichier Dockerfile est l’image de base (microsoft/dotnet:nanoserver) qui spécifie que nous souhaitons utiliser l’image .NET Core sous Nano Server. C’est aussi simple que ça ! (pour une application .NET Core en tout cas).

En quelques étapes :

  • Exécuter la même commande de Build pour construire votre image : docker build –t <votre tag> –f Dockerfile.nanoserver .

image

  • Démarrer un conteneur avec la commande : docker run –d –p 5000:5000 <votre tag>
  • Ouvrez un navigateur web et naviguez vers votre conteneur : http://<ip de votre conteneur/serveur Windows Server 2016>:5000

Exécuter l’application dans un conteneur Hyper-V

Le conteneur Windows Hyper-V apporte une couche d’isolation et de sécurité supplémentaire à l’application. Le choix entre un conteneur Windows “simple” et un conteneur virtualisé Hyper-V se fera en fonction de vos besoins, ce dernier fournissant une isolation du kernel et une séparation entre le niveau/version des patchs de l’hôte et de l’application.

La ligne de commande est similaire, nous précisons simplement le niveau d’isolement :

  • Démarrer un conteneur avec la commande incluant le paramètres isolation : docker run –d –p 5000:5000 –isolation=hyperv <votre tag>
  • Ouvrez un navigateur web et naviguez vers votre conteneur : http://<ip de votre conteneur/serveur Windows Server 2016>:5000

Container everywhere !

L’introduction des conteneurs Windows avec l’arrivée de Windows Server 2016 annonce une adoption du conteneur encore plus importe que celle actuellement avec les conteneurs Linux : containarization d’applications anciennes ou déploiement d’applications IIS avec le .NET Framework (avec Windows Server Core), déploiement Apps/IIS/AD DS/Hyper-V/etc (avec Nano Server), etc. L’adage Docker “Build, Ship and Run any app, Everywhere” n’a jamais eu autant de sens !

Déployer un projet web ASP.NET Core 1.0 avec Docker sur Windows en 15 minutes

Venant tout juste de passer sous Windows 10 update November 2015 (prérequis pour Docker beta) et souhaitant tester la RC2 fraichement débarquée de .NET Core, je me suis dit qu’un petit post ne serait pas de trop pour prendre les (nouvelles) bonnes habitudes. Aussi voici comment faire court pour créer une application .NET Core :

Installation des prérequis

Pour créer un projet ASP.NET Core :

  • .NET Core SDK (en RC 2 lors de la rédaction de ce post) : https://go.microsoft.com/fwlink/?LinkID=798398
  • NodeJS et son gestionnaire de package NPM : https://nodejs.org
  • Docker pour Windows (si vous êtes sur Windows) ou Docker pour Mac (si vous êtes sur Mac) : https://beta.docker.com/ (l’utilisation de la Beta nécessite l’obtention d’une clef qui arrive au compte goutte en ce moment …). Vous devez également avoir une version de Windows 10 adéquate (avec Hyper-V installé … pourquoi ne l’auriez-vous pas installé d’ailleurs ?!?) et la mise à jour de Novembre 2015.

Création du projet ASP.NET Core

  1. Dans une invite de commande ou dans une console PowerShell :
    1. mkdir coreapp : création d’un répertoire racine pour le projet
    2. cd .\coreapp\
  2. Installation du générateur Yeoman ASP.NET pour créer une application ASP.NET Core (et non juste une application console avec la commande dotnet new)
    1. npm install –g yo : installation de Yeoman
    2. npm install –g generator-aspnet : installation du générateur ASP.NET Core de Yeoman
  3. Création du projet :
    1. yo aspnet : affiche un wizard pour créer un nouveau projet :
      image
  4. Dans le wizard :
    1. Sélectionnez Web Application > Boostrap
    2. Saisissez le nom de l’application
  5. Le générateur va se mettre au travail et récupérer pour vous toutes les dépendances du projet et les placer dans un répertoire du même nom que celui de votre projet.
  6. Nous avons un peu de modification à faire pour rendre notre application compatible avec Docker (et rendre accessible notre application  à l’extérieur du container).
    Ouvrez le fichier Program.cs dans votre éditeur préféré (Visual Studio Code ?)
    Modifiez le contenu pour avoir un contenu similaire à ce qui suit puis enregistrez vos modifications :

    using Microsoft.Extensions.Configuration;
    
    ...
    namespace AppCoreDocker
    {
     public class Program
     {
     public static void Main(string[] args)
     {
     var config = new ConfigurationBuilder()
     .AddEnvironmentVariables("")
     .Build();
     var url = config["ASPNETCORE_URLS"] ?? "http://*:5000";
     var env = config["ASPNETCORE_ENVIRONMENT"] ?? "Development";
     
     var host = new WebHostBuilder()
     .UseKestrel()
     .UseUrls(url)
     .UseEnvironment(env)
     .UseContentRoot(Directory.GetCurrentDirectory())
     .UseIISIntegration()
     .UseStartup&amp;lt;Startup&amp;gt;()
     .Build();
    
     host.Run();
     }
     }
    }
    

    Cette modification permet de spécifier à Kestrel d’écouter sur le port 5000 quel que soit l’adresse que nous lui fournissons (merci à Laurent qui m’a évité de perdre du temps). Vous remarquerez la nouveauté liée à la RC 2 de cette configuration.

  7. Une fois le projet générer, les étapes sont les mêmes que pour tout projet :
    1. cd <nom de votre projet>
    2. dotnet restore : restaure les packages Nuget de l’application
    3. dotnet build : compile le projet (se produira si vous faites un run également)
    4. dotnet ef database update : crée la base de données SQLite pour gérer l’authentification (démo uniquement)
    5. dotnet run : lance le serveur Kestrel sur l’URL http://localhost:5000

image

Ouvrez un navigateur web avec l'URL : http://localhost:5000

image

Déploiement avec Docker

Afin de pouvoir lancer votre application dans un container Docker, nous devons créé notre Dickerfile. Le générateur Yeoman vous a déjà généré ce fichier, néanmoins, pour le moment le template de Yeoman n'est pas à jour (notamment l’image de base qui n’est pas la bonne et les actions maintenant avec la commande dotnet au lieu de dnx - cela a été mis à jour dans Github mais pas dans les distributions npm lors de la rédaction de ce post) que vous devrez modifier afin d’avoir un Dockerfile similaire à :

FROM microsoft/dotnet

ENV ASPNETCORE_ENVIRONMENT= "Production"

COPY . /app
 WORKDIR /app
 RUN ["dotnet", "restore"]

EXPOSE 5000
ENTRYPOINT ["dotnet", "run"]

Une fois le fichier modifié, vous pouvez exécuter les commandes suivantes :

  1. docker build –t <votre tag> .
  2. docker run –d –p 5000:5000 <votre tag>

La première commande build crée l'image Docker en installant les dépendances. La commande run exécute un container avec l'image créée précédemment sur le port 5000.

Ouvrez un navigateur web avec l'URL suivante : http://docker:5000 (et non localhost)

image

 

Conclusion

Force est de constater que l’uniformisation de la chaîne de commandes .NET Core et la possibilité de réaliser ses containers Docker dans un environnement Windows (ou Mac) apporte un réel gain de temps et une uniformité des outils quelle que soit l'environnement de développement.

Néanmoins, je ne pourrais que trop vous conseiller de tester vos containers dans un environnement Docker Linux stable et ne pas oublier que pour le moment Docker for Windows est en Beta.

Renommage des framework .NET Core

C’est en pleine rédaction d’un post sur ASP.NET 5 (avant de redémarrer ceux sur Docker et Nano Server) que Scott Hanselman choisit de nous annoncer que les noms des frameworks .NET Core que nous connaissions changent (cela devrait signifier que la sortie de la RTM devrait se faire très prochainement).

Voici la liste des mises à jour :

  • ASP.NET 5 => ASP.NET Core 1.0
  • .NET Core 5 => .NET Core 1.0
  • Entity Framework 7 => Entity Framework Core 1.0 / EF Core 1.0

ASP.NET Core 1.0

Cela est beaucoup plus cohérent que précédemment, aussi bien pour les clients que pour l’évolution des deux frameworks afin d’éviter toutes confusions entre les frameworks. En espérant que les librairies tierces joueront également le jeu de ce renommage, notamment celle qui ne supporte que ASP.NET Core et non ASP.NET 4.6 par exemple).

Tour d’horizon de Nano Server (partie 2) : déployer un projet web ASP.NET 5

Dans le précédent post, nous avons créer notre première image Nano Server. Dans ce post nous allons créer une image Nano Server comprenant un serveur web IIS pleinement fonctionnel et y déployer un site ASP.NET 5.

IMPORTANT : ce post a été réalisé avec la CTP 4 de Windows Server 2016. Il sera mis à jour ultérieurement.

IMPORTANT : Le site ASP.NET 5 s’exécute directement sur Nano Server (VM ou physique) mais pas dans un container. Dans un prochain post, nous verrons comment faire tourner un projet web ASP.NET 5 dans un container (déploiement qui sera certainement privilégiée par Microsoft). Attention, la différence de procédure peut-être importance, que vous soyez ou non dans un container.

Voici l’état de la documentation d’aujourd’hui sur http://aspnetmvc.readthedocs.org :

image

Alors prenez ce guide en attendant que la documentation soit complétée pour déployer et exécuter une application ASP.NET 5 sur Nano Server.

Création de l’image NanoServer avec IIS

Nous avons deux options pour installer IIS sur un Nano Server : hors ligne (Nano Server est éteint) ou en ligne (Nano Server est en cours d’exécution). Dans ce post nous allons utiliser l’installation hors ligne et créer une image directement avec IIS intégré (nous aurions également pu ajouter IIS à une image déjà existante).

1. Reprenez les étapes de création de la partie 1 de cette série, à l’étape 5 exécutez à la place la ligne de commande suivante : New-NanoServerImage -MediaPath D:\ -BasePath .\Base -TargetPath ‘.\NanoImage\NanoVM.vhdx’ -GuestDrivers –EnableRemoteManagementPort –Language en-us –ComputerName NanoServerNode1 –Packages Microsoft-NanoServer-IIS-Package –ReverseForwarders

A propos du package ReverseForwarders : Pour pouvoir exécuter HttpPlatformHandler et Kestrel (c’est à dire libuv.dll) sur Windows Server, vous allez devoir ajouter un package ReverseForwarders. Les appels à kernel32.dll et advapi32.dll (DLLs qui n’existent pas dans Nano Server) seront ainsi redirigés vers les nouvelles de ces APIs qui ont été déplacés dans d’autres composants. Ce package n’est pas installé par défaut dans Nano Server (alors que c’est le cas sur Win10 IoT) puisque l’objectif est de n’avoir que le strict minimum d’embarqué, il vous faut donc le rajouter.

Création de la machine virtuelle Hyper-V Nano Server

Créer une nouvelle machine virtuelle Hyper-V et connectez une machine virtuelle avec ce nouveau VHD. Vous devriez voir la recovery console.

image

Exemple de script PowerShell de création de VM :

New-VM -VHDPath ‘.\NanoImage\NanoVM.vhdx’ -MemoryStartupBytes 512MB -Name NanoServerNode1 -Generation 2

Set-VMMemory -VMName NanoServerNode1 -DynamicMemoryEnabled $True -MaximumBytes 512MB -MinimumBytes 256MB

Set-VMProcessor -Count 2 -VMName NanoServerNode1

Note : N’oubliez pas mettre le bon switch virtuel pour avoir du réseau et vous connecter à la VM (cf étape suivante pour le vérifier).

Vérifier le fonctionnement de IIS

1. La première chose à faire est de récupérer l’adrese IP de la machine, pour cela, deux options :
- Récupérer l’IP depuis la console de restauration (recovery console) en vous connectant sur la machine et en vous authentifiant
- Récupérer l’IP depuis Hyper-V avec la ligne de commande suivante :  Get-VM –name <Nom de votre VM>| Select -ExpandProperty networkadapters | Select IPAddresses

image

2. Connectez vous avec un navigateur web sur cet IP, vous devriez observer une page de bienvenue IIS :

image

Vous voilà avec un serveur IIS fonctionnel.

Se connecter à Nano Server

Bien qu’il existe plusieurs façons de pouvoir se connecter à distance avec Nano Server, nous allons utiliser le module de gestion IIS PowerShell pour gérer notre serveur IIS. Tout d’abord

1. Pour pouvoir vous connecter au Nano Server avec une session PS, vous devez d’abord l’ajouter dans la liste des hôtes de confiance.  Exécuter la commande PowerShell (toujours dans une console en tant qu’administrateur) : Set-Item WSMan:\localhost\Client\TrustedHosts "<IP de votre serveur>"

image

2. Exécutez la ligne de commande suivante dans PowerShell :
$session = New-PSSession –ComputerName <IP de votre serveur> –Credential Administrator
Enter-PSSession $session

Un prompt vous demandera le mot de passe de l’administrateur.

image

3. (facultatif )Dans la session distante, importez le module de gestion IIS puis récupérer les sites IIS avec les commandes :
Import-Module IISAdministration
Get-IISSite

image

Vous êtes connectez à Nano Server, nous allons pouvoir créer le projet ASP.NET 5 et le déployer.

Création du projet ASP.NET 5

Nano Server ne contient pas de Framework .NET justement parce que celui-ci possède trop de dépendance avec Windows et qu’il fallait couper sévèrement dans les composants. Néanmoins, pour faire fonctionner Powershell, Nano Server utilise une partie de .NET Core (la version open source et portable du framework .NET) mais qui ne suffira pour exécuter votre application.

Note : vous pouvez aussi récupérer le projet ASPNET5WebHello.

Installer la dernière version de .NET Core

Avant de créer votre projet ASP.NET 5 sur votre machine de développement, assurez vous que vous avez bien la dernière version de .NET Core (surtout en ces temps de Beta et RC) avec la commande : dnvm list

image

Si vous n’avez pas la dernière version (ou disons la version que vous souhaitez déployer) de la Core CLR (et en version x64, Nano Server ne s’exécutant qu’en 64 bits), exécuter le commande :

dnvm install latest –r coreclr –arch x64 –alias coreclr-latest

image

image

Projet ASP.NET 5 avec Visual Studio 2015

Dans Visual Studio 2015 (toutes éditions confondues) :

1. Créez un nouveau projet Visual C# > Web > ASP.NET Web Application :

image

2. Choisissez ASP.NET 5 Preview Templates :

image

3. Dans les propriétés du projet, vérifiez que la cible du DNX est bien celle que vous souhaitez :

image

Dans l’onglet de Debug (pour les tests sur l’environnement de développement) :

image

4. Lancez l’application (F5), pour voir un magnifique texte “hello world” apparaître dans votre navigateur.

image

5. Avant de publier votre application, il reste un détail important (sans quoi Nano Server ne servira pas vos pages web) : remplacez l’URL du projet. Dans le fichier project.json, changer la ligne :

"commands": {
"web": "Microsoft.AspNet.Server.Kestrel server.urls=
http://localhost:5000"
  },

par

"commands": {
"web": "Microsoft.AspNet.Server.Kestrel server.urls=
http://<ip de votre serveur Nano Server>:5000"
  },

Enregistrez les modifications du fichier.

6. Nous allons maintenant pouvoir publier l’application web sur notre disque dur avant de copier les fichiers vers Nano Server. Ouvrez une console PowerShell dans le répertoire de votre projet :

image

Dans la console excutez les commandes suivantes pour restaurer les packages (normalement Visual Studio a dû le faire pour vous mais nous ne sommes jamais trop prudent) et publier l’application avec le runtime dnx-coreclr-win-x64.1.0.0-rc1-update1  :

dnu restore
dnu publish –out <chemin vers répertoire de sortie>--runtime C:\Users\<nom de l’utilisateur>\.dnx\runtimes\dnx-coreclr-win-x64.1.0.0-rc1-update1

Remarque : Publiez votre projet si possible à la racine d’un disque, la technique de copie à suivre ne permettra pas les chemins d’accès de plus de 260 caractères.

6. Vous devriez avoir dans votre répertoire cible, un contenu similaire à celui-ci :

image

Publication du projet vers Nano Server

A ce stade, la seule option que j’ai trouvé pour publier le site est de faire un copier/coller du répertoire publié vers IIS sur le Nano Server. La possibilité d’utiliser un WebDeploy n’est aujourd’hui pas supporté sur le IIS de Nano Server.

Remarque : pour procéder à la copie vers une session distante, si vous êtes sur Windows 8.1 ou 7, vous devrez installer Windows Management Framework 5.0.

Nous allons donc procéder à une copie entre le système de fichier de la machine de développement et le serveur Nano Server :

- Ouvrez une session avec :  $session = New-PSSession –ComputerName <ip de voter serveur> –Credentials Administrator

image

- Exécutez la commande de copie : Copy-item –ToSession $session –Path <chemin vers votre projet publié> –Destination C:\Users\Administrator\Documents –Recurse

image

La copie des fichiers devraient prendre un peu de temps. Les fichiers de votre projet sont maintenant publiés sur Nano Server.

Configurer le pare-feu de Nano Server

Nous avons configurer le site sur le port 5000 qui n’est pas encore ouvert (les ports HTTP et HTTPS sont déjà ouverts). Pour ouvrir le port 5000, vous avez deux options : la ligne de commande ou la console de restauration (recovery console) :

netsh advfirewall firewall add rule name="HTTP (5000)" dir=in action=allow protocol=TCP localport=5000

image

Démarrer le site web

Le démarrage va être effectuer via le fichier web.cmd qui a été créé lors de la publication du projet. Ce fichier contient les commandes nécessaires pour démarrer votre projet en analysant le fichier project.json.

Naviguez dans le répertoire approot de votre projet et exécuter le fichier web.cmd pour démarrer le serveur :

image

image

Ouvrez un navigateur avec l’adresse http://<ip de votre serveur>:5000 , et voilà :

image

Important : une fois que vous aurez lancé la commande web.cmd, vous devriez observer un écran noir dans votre machine virtuelle. Une fois le serveur arrêté (Ctrl+C), la recovery console réaffichera l’écran en cours. Nous verrons dans un prochain post comment faire éviter cela.

 

Nano Server est définitivement le futur du serveur IIS pour les applications ASP.NET 5. Bien que cette édition soit pour le moment assez limitée en termes d’interface et d’outil de gestion, Microsoft devrait améliorer cet aspect là dans les prochaines versions de son OS.

A ce stade, le manque de documentation se fait sentir ! La communauté et Microsoft devrait combler cette lacune rapidement au vu de l’engouement pour Nano Server. Tous les contributeurs de docs.asp.net sont les bienvenus sur le projet Github.

La solution présentée dans ce post n’est pas définitive, mais permet de montrer comment exécuter une application web ASP.NET 5 dans Nano Server.

Dans un prochain post nous verrons l’hébergement d’un application web ASP.NET 5 dans un container Nano Server et également comment bénéficier de IIS pour l’exécution en production.

Ressources

En attendant, voici quelques ressources qui m’ont bien aidé (malgré que tout ne fonctionne pas) à faire fonctionner un site ASP.NET 5 sur le IIS de Nano Server :

- Pour plus de détails sur les commandes et fichier de configuration IIS : https://msdn.microsoft.com/en-us/library/mt627783.aspx

- Channel 9 “Nano Server in a container running IIS & ASP.NET 5” : https://channel9.msdn.com/Series/Nano-Server-Team/Demo-Nano-Server-in-a-Container-running-IIS-ASPNET5

Déployer ASP.NET 5 dans un container Docker

image

Docker et bientôt Windows Server Container vont vous permettre de délivrer et d’exécuter des applications plus rapidement et avec moins de ressources. La “containerization” des applications embrace l’approche DevOps en permettant d’exécuter des centaines d’applications en parallèle alors que même un cluster de VMs en seraient incapable et de surcroit difficile à gérer. Le container permet aussi de rendre l’architecture microservices plus fiable et plus accessible aux équipes réduites.

imageCette série de post vous proposer une première approche au déploiement d’une application ASP.NET 5 dans un container Docker. Ainsi vous serez capable de déployer votre application sur vos serveurs de production ou dans le Cloud (AWS, Azure, etc) rapidement et de façon fiable.

Introduction sur les containers

L’avantage des containers, en dehors d’une densification plus importante des serveurs en applications, est aussi l’utilisation des images. Une image contient aussi bien l’OS que les dépendances de l’application (CoreCLR, ASP.NET MVC, etc) et est de de petite taille. Cela permet de créer des containers rapidement et de les démarrer tout aussi rapidement. Aujourd’hui le hub Docker contient plus de 100 000 images.

Bien que Docker se limite aujourd’hui à délivrer des containers Linux (OS du container et OS hôte), l’arrivée de Windows Container et de Nano Server devraient faire évoluer le paysage de cette technologies dans les prochains mois.

Pour ce post, .NET Core étant multi plateforme, nous allons créer une application ASP.NET 5 MVC puis l’exécuter un container Docker sous Linux.

Prérequis

Vous devez disposer :

  • D’une machine hébergeant Docker. Pour ce blog, j’ai utilisé une machine hébergée sur  Azure mais une VM Hyper-V avec Ubuntu ou autre fait tout aussi bien l’affaire.
  • Eventuellement d’un projet ASP.NET 5 à déployer. Pour ce post, j’ai créé une application excessivement simple affichant une page de bienvenue et disponible sur Github.

Création du fichier Dockerfile

Le fichier Dockerfile permet de créer des containers en industrialisant sa composition par un script de création. Ces fichiers peuvent être versionnés et mis à jour en fonction de l’évolution de vos plateformes et applications.

FROM microsoft/aspnet:1.0.0-rc1-final-coreclr

COPY . /app
WORKDIR /app
RUN ["dnu", "restore"]

EXPOSE 5004
ENTRYPOINT ["dnx", "-p", "project.json", "kestrel"]

L’instruction FROM permet de spécifier l’image Docker de base utilisée. Dans notre cas, une image préconfigurée avec la version CoreCLR 1.0.0 RC1.

L’instruction COPY va exécuter une copie des fichiers situés à la racine dans le répertoire app avant de devenir le répertoire courant (instruction WORKDIR) dans lequel nous allons restaurer les packages de l’application à partir du fichier project.json.

L’instruction EXPOSE spécifie que le container aura un port 5004 exposé (ce port est configuré dans le fichier project.json comme étant celui du serveur web). Le point d’entrée ENTRYPOINT spécifie la commande à exécuter lors du lancement du container. Dans notre cas, nous exécutons un serveur kestrel.

Créer le container

A partir  de ce fichier Docker, vous allez maintenant pouvoir construire votre container, voir automatiser ce processus afin d’effectuer des tests automatisés de votre application (nous aurons l’occasion d’en parler plus tard).

Dans votre machine Docker (ici dans une console d’une VM Azure connectée en SSH) :

1. Exécuter la commande Git afin de récupérer un projet simple et le fichier Dockerfile prêt à l’emploi sur votre serveur :
git clone https://github.com/NCITNoumea/docker-ressources.git

2. Une fois les fichiers récupérés depuis github sur votre serveur
cd docker-ressources/images/mvc-hello/
sudo docker build -t mvc-hello .

La construction du container devrait prendre quelques minutes, nécessaires au téléchargement de l’image de base et des dépendances .NET. Au bout de quelques minutes, vous devriez avoir un message indiquant le succès de l’opération :

image
Remarque : dans cette capture, vous pourrez observer que l’image et les dépendances sont déjà contenues dans le cache (“Using cache”). Lors de la première exécution, vous verrez défiler les téléchargements.

3. Votre container nommé mvc-hello est maintenant prêt à être déployer et exécuter dans le Docker Engine.

Exécuter le container

Toujours dans votre machine Docker (ici dans une console d’une VM Azure connectée en SSH) :

1. Exécuter le commande de démarrage du container :
sudo docker run –t –d –p 80:5004 mvc-hello

L’exécution de cette commande devrait vous renvoyer un identifiant excessivement long :

image

Cette commande propose différent paramètres, le plus important dans notre cas est le mapping des ports entre le container et l’hôte Docker. Nous spécifions que le port 80 de l’hôte sera redirigé vers le port 5004 (que nous avons exposé précédemment) du container.

Vérifier le déploiement

Vous pouvez vous connecter sur l’IP de votre VM (port 80) avec un navigateur web pour constater l’exécution du serveur web et de votre application ASP.NET 5 :

image

En cas d’erreur …

L’exécution d’un container n’est pas sans mauvaise configuration de notre part, aussi vous pouvez demander à Docker d’afficher les logs d’exécution d’un container afin de diagnostiquer la source de l’erreur :

1. Exécuter le commande de démarrage du container :
sudo docker logs <identifiant de votre container>

Vous pouvez récupérer l’identifiant de votre container de plusieurs façons, la plus simple est de copier/coller celui-ci lorsqu’il s’est affiché à l’exécution de la commande run. Il s’agit bien de l’ “identifiant excessivement long” évoqué précédemment.

image

Arrêter le container

Dans votre machine Docker (ici dans une console d’une VM Azure connectée en SSH) :

1. Exécuter le commande de démarrage du container :
sudo docker ps

Cette commande liste les containers en cours d’exécution. Vous devriez trouver le vôtre :

image

2. Exécuter le commande de démarrage du container :
sudo docker stop <nom de votre container>

L’arrêt devrait prendre quelques secondes le temps que le serveur web s’arrête. Si vous réexécuter la commande sudo docker ps, le container devrait avoir disparu.

Conclusion

Bien qu’attendu au premier semestre 2016, ASP.NET 5 est d’ores et déjà fonctionnel que ce soit au travers d’un serveur IIS ou d’un serveur web Linux (kestrel).

L’utilisation d’application “containeriser” devrait apporter une nouvelle bouffée d’air aux process DevOps des projets .NET. L’arrivée de Windows Server Container (dont nous parlerons dans un prochain post) devrait encore ajouter de l’agilité à ces projets, comme c’est déjà le cas avec l’intégration des extensions Docker dans Visual Studio et Azure.

Alors que le déploiement de services .NET (site web, services SOAP/REST/OData, etc) avait un TCO plus élevé que des homologues tels que PHP, Java, Ruby, etc (hébergés le plus souvent sur Linux/Apache), le déploiement d’une application .NET dans un container Linux devrait radicalement changer la donne et permettre à toutes les entreprises et développeurs de pouvoir utiliser la puissante et la flexibilité de .NET et de ses framework (ASP.NET MVC, Entity Framework, etc) à coûts d’hébergement identiques.

Cela devrait permettre à .NET de devenir enfin une plateforme de service compétitive : économique tout en continuant de garantir la productivité acquises avec les frameworks .NET et ses outils (notamment Visual Studio) pour apporter plus et plus rapidement de la valeur utilisateur à ses utilisateurs / clients.

Note : ce post se base sur des versions préliminaires des images ASP.NET , par conséquent les instructions pourront changer en cours de temps. Néanmoins, n’hésitez pas à consulter le repository Docker des images officielles : https://hub.docker.com/r/microsoft/aspnet/

Création d’une VM Docker dans Azure

Azure propose aujourdh’ui une VM préconfigurée pour exécuter Docker sur un Ubuntu 15.04 Server afin de vous épargner la création d’une machine et l’installation des différents composants.

Voici les étapes à suivre pour avoir une machine disponible en quelques minutes :

1. Connectez vous sur votre compte Azure : http://portal.azure.com

2. Dans le portail, cliquez sur Nouveau

image

3. Rechercher l’image “Docker on Ubuntu Server” dans le marketplace

image

image

4. Cliquez sur Créer en bas de page, puis saisissez le nom d’hôte, le nom d’utilisation et mot de passe. Gardez le type d’authentification en Mot de passe plutôt que clé publique SSH pour des raisons de simplicité. Si vous êtes familiarisé avec SSH et les clés publiques, changez de mode. Sélectionnez votre niveau de tarification selon vos besoins, le groupe de ressources et l’emplacement du data center.

image

5. Cliquez sur Créer puis attendez la création de la VM qui devrait prendre quelques minutes.

6. Une fois la VM créée, connectez-vous à l’interface d’administration de celle-ci dans le portail Azure

image

7. Naviguez dans Gérer > Adresses IP pour récupérer l’adresse IP avec laquelle vous vous connecterez en SSH

image

8. Créez un point de terminaison pour autoriser la connexion sur le port HTTP (80) si vous déployer un container avec un serveur web en naviguant dans Gérer > Points de terminaison :

image

9. Pour tester la connexion SSH avec le serveur, utilisez un client SSH (par exemple Putty) et essayer de vous connecter pour valider la bon fonctionnement de votre nouvel VM Docker :

image

10. Exécuter la commande sudo docker pour vérifier le bon fonctionnement de Docker :

image

Votre VM Docker est maintenant fonctionnelle. Vous allez pouvoir héberger des containers (voir prochains posts).

Visual Studio 2015 est enfin là !

La version RTM de Visual Studio 2015 vient tout juste de sortir et nous avons le droit à de nombreuses améliorations et fonctionnalités comparé à VS 2013.

Alors pourquoi, un 'enfin' dans le titre ? Tout simplement car VS 2015 et .NET 4.6 apporte chacun de vraies nouveautés dans la façon de développer vos projets : nouveau modèle de projet, prise en charge de .NET 4.6 et ASP.NET 5 (et donc de .NET Core, la version open source et optimisée cloud de .NET), télémétrie (pour tout savoir de l'exécution de votre application), développement multi plateforme mobile, compilateur Roslyn, outils de diagnostic (un must), etc ...

La version Community est disponible à cette adresse : https://www.visualstudio.com/downloads/download-visual-studio-vs

Les versions entreprise sont quantà elles disponibles sur votre compte MSDN dès aujourd'hui !

Les éditions

Quelle édition choisir :

  • Edition Community : gratuit pour les étudiants, les projets open source et les équipes de petite taille. Les fonctionnalités vous permettront de développer des applications web, Azure, Windows et multi plateforme mobile (iOS, Android et Windows Phone).
  • Edition Professionelle : l'environnement le plus répandu parmi les développeurs expérimentés. Possède tous les outils nécessaires à développer une application complexe à l'aide d'outil de productivité de code (CodeLens, collaboration Agile, connectivité avec Team Foundation Server, VS Online, etc).
  • Edition Test Professionnelle : uniquement dédié aux testeurs avec uniquement les outils pour ce dernier.
  • Edition Entreprise : dédié aux sociétés souhaitant réaliser et automatiser les tests (charge, unitaires, etc) et utiliser IntelliTest et IntelliTrace pour le débogage. Mais encore avoir 150$ de crédits Azure par mois.

Les fonctionnalités en (très) bref

  • Outils de développement pour réaliser des applications web, mobile (iOS, Android et WP via Cordova et Xamarin), Windows, Windows 10 universelle (PCs, tablets, XBox, HoloLens, IoT), et cloud
  • Langages supportés : C#, JavaScript, NodeJS, TypeScript, Visual Basic, F#, C++, IronPython, ...

Coup de coeur : ASP.Net 5 et .NET Core

Supporté sur Windows, Linux et MacOS, les applications ASP.NET 5 et .NET Core vont pouvoir se déployer sur des serveurs cloud à moindre coût ! La plateforme .Net rentre dans une nouvelle phase d'adoption des développeurs, où mêmant outils et productivité, ceux-ci auront la vie beaucoup plus facile et pourront porter l'innovation rapidement et de façon fiable vers leurs utilisateurs.

Vous pouvez retrouver tous les projets .NET sur le github de la .NET Foundation à cette adresse : https://github.com/dotnet

Utilisation du service WorkflowQueuingService

L'exécution d'un workflow est souvent dépendante des entrées que les hommes (via une console ou une application Windows Form) ou les programmes (ASP.NET, Web Service, Mainframe, etc) feront dans votre workflow, même après plusieurs jours d'attente. Une activité qui attend des entrées d'une entité extérieure se doit de faire deux choses :

  • Notifier qu'elle attend des données (se mettre 'au repos')
  • Etre notifié quand les données seront mise à disposition.

Et cela, même si l'instance de son workflow est persistée (dans un fichier texte ou une base de données par exemple). Lorsque les données arrivent, le moteur d'exécution (le runtime) doit pouvoir recharger en mémoire l'instance et être capable de continuer l'exécution du workflow au bon endroit.

Comment faire en sorte de pouvoir spécifier au workflow qu'il est en attente d'une donnée et de traiter la donnée une fois celle-ci mise à la disposition de l'instance du workflow ? Comment assurer une communication 'propre' à l'intérieur des couches logicielles et de votre architecture ? Il y a plusieurs méthodes, plus ou moins robuste pour le faire,  une bonne méthode est néanmoins d'utiliser ce qui fait le fondement de WF : les files de Workflow !

De cette façon, à chaque fois que vous avez besoin de pousser une entrée vers le workflow, telle qu'une chaine de cractères ou tout autre objet (dans notre exemple, une transaction financière), vous ajoutez un élément à l'une ou les piles de l'instance du workflow. La pile se chargera à son tour d'appeler les méthodes abonnées aux évènements pour traiter ces entrées comme stimuli de l'activité. Ce principe nous permet d'utiliser le service WorkflowQueuingService qui s'exécute dans le moteur d'exécution de WF et qui va vous permettre d'ajouter et de nommer des files dans une instance de workflow.

L'autre avantage de cette méthode est le fait de pouvoir ainsi marquer des points d'exécution et des points de persistence dans votre workflow sans que vous ne soyez obligé d'être dans la portée d'une transaction.

Imaginons que nous voulons traiter un workflow simple qui attend le traitement d'une transaction financière par un serveur backend.

Voici la structure d'une transaction attendue comme entrée par le workflow :

public struct Transaction {

public double Amount;

public DateTime Date;

public Guid ID;

public Transaction(Guid id, double amount, DateTime date) {

this.ID = id; this.Amount = amount; this.Date = date;

}

public override string ToString() {

return string.Format("ID: {0} - Amount: {1} - Date: {2}", ID, Amount, Date);

}

}

Commençons par implémenter une activité possédant une propriété contenant notre transaction  :

public partial class WaitProcessedTransaction : System.Workflow.ComponentModel.Activity

{

private Transaction mTransaction;

public Transaction Transaction

{

get { return mTransaction; }

set { mTransaction = value; }

}

...

}

Voici les méthodes de création (méthode d'initialisation de l'activité) et de destruction (méthode de 'désinitialisation', comprendre que cette méthode est appelée de façon synchrone lorsque de la transition de l'état de l'activité de Executing vers Closed) de la file de Workflow :

protected override void Initialize(IServiceProvider provider) {

WorkflowQueuingService qService =

(WorkflowQueuingService)provider.GetService(typeof(WorkflowQueuingService));

if (!qService.Exists(this.Name))

qService.CreateWorkflowQueue(this.Name, true);

}

protected override void Uninitialize(IServiceProvider provider) {

WorkflowQueuingService qService = (WorkflowQueuingService)provider.GetService(typeof(WorkflowQueuingService));

if (qService.Exists(this.Name))

qService.DeleteWorkflowQueue(this.Name);

}

}

On peut constater que les files sont nommées, ici par le nom de l'activité.

Nous allons redéfinir la méthode d'exécution de l'activité par la méthode suivante :

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) {

WorkflowQueuingService qService = executionContext.GetService<WorkflowQueuingService>();

WorkflowQueue queue = qService.GetWorkflowQueue(this.Name);

if (queue.Count > 0){

this.mTransaction = (Transaction)queue.Dequeue();

return ActivityExecutionStatus.Closed;

}

queue.QueueItemAvailable += this.ContinueAt;

return ActivityExecutionStatus.Executing;

}

void ContinueAt(object sender, QueueEventArgs e){

ActivityExecutionContext context = (ActivityExecutionContext)sender;

WorkflowQueuingService qService = context.GetService<WorkflowQueuingService>();

WorkflowQueue queue = qService.GetWorkflowQueue(this.Name);

this.mTransaction = (Transaction)queue.Dequeue();

context.CloseActivity();

}

Dans la méthode d'exécution, nous récupérons le service de file puis nous extrayons l'entrée qui pourrait potentiellement se trouver dans la file. Si la donnée est récupérée de la file, nous spécifions la clôture de l'activité, sinon nous abonnons une méthode à l'évènement qui sera appelée dés qu'une entrée dans la file sera disponible, puis nous laissons le statut de l'activité comme 'en cours d'exécution'.

Maintenant c'est au tour de l'application de jouer son rôle en fournissant l'entrée dans la file nommée de l'instance du workflow :

// Création d'une instance de workflow et démarrage

WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowDemo.WorkflowQueueTest));

instance.Start();

...

// On crée une transaction financière et la met dans la file nommée 'WaitTransactionProcessed' (qui est le nom de l'activité ciblée) ce qui aura pour effet de réveiller le workflow et d'exécuter la méthode abonnée à l'évènement 'QueueItemAvailable' de la file (méthode 'ContinueAt')

Transaction t = new Transaction(Guid.NewGuid(), 1000.0, DateTime.Now);

instance.EnqueueItem("AttendreTraitementTransaction", t, null, null);

...

En utilisant un objet d'une instance de workflow, et cela n'importe où dans l'application hôte, vous allez pouvoir marquer des points d'exécution dans votre workflow grâce aux files et communiquer une ou plusieurs entrées à votre activité pour pouvoir continuer son exécution. Cela est vrai même si celui-ci a été persisté pendant son état de repos.

Dans notre cas, nous parlons d'un workflow qui peut attendre un stimulus d'une entité extérieure sur des périodes plutôt longues, il faut donc s'attendre à se que le workflow soit décharger de la mémoire pour être persisté à un endroit physique. Dans notre cas nous allons le faire persister dans une base SQL Server 2005 (classique en quelque sorte) en utilisant le service SqlWorkflowPersistenceService (voici un lien pour mettre en place tout ce qu'il faut : http://msdn2.microsoft.com/en-us/library/aa349366.aspx).

clip_image002

Note : voici également un excellent schéma des états d'un workflow : http://msdn2.microsoft.com/en-us/library/aa663362.hostingwwf03l%28en-us,msdn.10%29.jpg

Voici les quelques lignes qu'il faut rajouter pour configurer le runtime :

...

string stringConnection = @"Initial Catalog=WF_Persistence;Data Source=localhost\SQLEXPRESS;User Id=x;Password=x";

// Création d'une instance du service de persistence Sql Server avec un argument à true pour spécifier de persister une instance de workflow dés que son état passe au repos

SqlWorkflowPersistenceService persistenceService = new SqlWorkflowPersistenceService(

stringConnection, true, TimeSpan.MaxValue, new TimeSpan(0, 1, 0));

workflowRuntime.AddService(persistenceService);

...

Pour mieux comprendre ce qui se passe on rajoute des handle à différents évènements qui afficheront les changements d'état :

workflowRuntime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(workflowRuntime_WorkflowIdled);

workflowRuntime.WorkflowPersisted += new EventHandler<WorkflowEventArgs>(workflowRuntime_WorkflowPersisted);

workflowRuntime.WorkflowLoaded += new EventHandler<WorkflowEventArgs>(workflowRuntime_WorkflowLoaded);

workflowRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(workflowRuntime_WorkflowCompleted);

...

void workflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e) { Console.WriteLine("Workflow completed !"); }

void workflowRuntime_WorkflowLoaded(object sender, WorkflowEventArgs e){ Console.WriteLine("Workflow loaded !"); }

void workflowRuntime_WorkflowPersisted(object sender, WorkflowEventArgs e) { Console.WriteLine("Workflow persisted !"); }

void workflowRuntime_WorkflowIdled(object sender, WorkflowEventArgs e) { Console.WriteLine("Workflow idle !"); }

...

Imaginons que nous avons un workflow séquentiel contenant notre activité qui attend le traitement d'une transaction lancée en amont d'un workflow, et d'une activité qui affiche un message de confirmation du traitement :

clip_image004

Nous pourrons observer le résultat suivant :

clip_image006

Voici un cas simple d'utilisation du service WorkflowQueuingService. Ce service est à la base de nombreuses activités et reste un moyen élégant et efficace de placer des points d'attente nommés - par le nom de la file - où vos activités peuvent recevoir des données, c'est à dire des endroits logiques dans votre workflow dont l'exécution peut être reprise quand un stimuli spécifique (une données, un évènement, ...) arrive, tout en étant capable d'être persisté pendant le temps d'attente.

Le lien MSDN vers le WorkflowQueuingService qui devrait être à la base de beaucoup de vos activités communicant avec l'extérieur (permet de remplacer très élégamment l'activité HandleExternalEvent : http://msdn2.microsoft.com/en-us/library/system.workflow.runtime.workflowqueuingservice.aspx