Déployer des applications .NET sur Google Cloud

Cet article explique comment déployer des applications .NET sur Google Cloud et fournit des conseils pour choisir la bonne approche de déploiement à adopter.

Présentation

Microsoft .NET Framework fournit un ensemble complet d'outils et de bibliothèques pour le développement d'applications. Grâce à l'introduction de Docker sous Windows et la possibilité d'exécuter des applications .NET Core sous Linux, les applications .NET sont désormais compatibles avec diverses cibles de déploiement.

Pour un développement et des tests efficaces, vous pouvez automatiser le déploiement d'applications et l'intégrer à un pipeline d'intégration/diffusion continues (CI/CD). Toutefois, pour choisir les bons outils et créer un pipeline CI/CD, vous devez d'abord déterminer comment exécuter l'application en production et quelle approche de déploiement adopter.

Il n'existe pas de méthode optimale universelle pour déployer une application .NET sur Google Cloud Les meilleures options dépendent de l'application et de vos besoins. Par exemple, si votre application nécessite la totalité du framework .NET ou doit être exécutée sur un serveur IIS, le déploiement s'effectuera sous Windows. D'autre part, si votre application peut s'exécuter avec les fonctionnalités compatibles de .NET Core, vous pouvez alors la déployer sous Linux.

Cet article décrit les différentes façons d'exécuter des applications .NET et de les déployer sur Google Cloud, y compris les conditions dans lesquelles chaque option est adaptée. À la fin, vos options de déploiement sont résumées dans un arbre de décision pour vous aider à choisir les composants et les approches Google Cloud les plus adaptés à votre application .NET.

Modèles de déploiement

Il existe deux manières de procéder au déploiement automatisé d'une application. Le package de déploiement est transmis aux serveurs d'applications, ou les serveurs d'applications extraient le package de l'application à partir d'un emplacement connu. Dans les sections suivantes, nous expliquons les différences entre ces deux modèles.

Déploiements en mode Push

Dans un déploiement en mode Push, l'artefact de déploiement (un fichier zip, un package NuGet ou un autre artefact) n'est initialement disponible que sur un serveur de déploiement. Le serveur de déploiement peut être une machine dédiée ou un rôle exécuté par le système CI.

Pour effectuer un déploiement, un processus sur le serveur de déploiement se connecte à un serveur d'applications, puis copie l'artefact de déploiement et lance son installation. S'il existe plusieurs serveurs d'applications, ce processus est répété en parallèle ou, le plus souvent, en séquence, de façon à déployer les artefacts sur tous les serveurs d'applications.

Le schéma suivant illustre ce flux.

Déploiements en mode Push

Divers outils de gestion de la configuration sont disponibles pour automatiser les déploiements effectués de cette façon. Certains se basent sur une approche impérative selon laquelle la séquence des étapes de déploiement est définie comme un script. Bien que cette méthode soit intuitive, elle peut entraîner une dérive de configuration. En d'autres termes, après un certain temps, il se peut que les états de plusieurs machines ne soient plus identiques et ne reflètent pas fidèlement l'état souhaité. Ainsi, de nombreux outils vous permettent de définir l'état que vous souhaitez en déterminant eux-mêmes les étapes nécessaires pour atteindre cet état.

Voici les outils couramment utilisés sous Windows pour ce modèle de déploiement :

Ansible, Chef et Puppet sont des outils Open Source couramment utilisés. Bien qu'ils ciblent principalement Linux, ils sont également capables de déployer des cibles Windows.

Sécurité

Pour que le serveur de déploiement déclenche un déploiement sur un serveur d'applications, un canal arrière doit être disponible. Par exemple, pour effectuer cette tâche, Web Deploy et Octopus Deploy font appel à un protocole et à un port personnalisés, tandis que l'outil Ansible utilise le protocole SSH.

Quel que soit le protocole utilisé par l'outil, il est essentiel de sécuriser la communication afin d'empêcher les pirates informatiques de déployer des applications malveillantes en exploitant le canal arrière. Plus important encore, une communication sécurisée exige que le serveur de déploiement puisse s'authentifier auprès du serveur d'applications.

Le protocole SSH peut s'appuyer sur l'authentification par clé publique. Si vous employez la configuration IAM appropriée, vous pouvez laisser Google Cloud effectuer automatiquement la distribution de la clé publique nécessaire à l'authentification SSH auprès des serveurs d'applications. Toutefois, si vous n'utilisez pas IAM, Google Cloud ne peut pas gérer la clé pour vous et vous devez distribuer la clé vous-même.

Une autre possibilité est de recourir au service Active Directory. Lorsque le serveur de déploiement et le serveur d'applications s'exécutent sous Windows et appartiennent à un domaine Active Directory, l'authentification s'effectue via Kerberos. Toutefois, l'exécution d'un environnement Active Directory tolérant aux pannes nécessite au moins deux instances de VM supplémentaires pour pouvoir exécuter les contrôleurs de domaine. Si votre configuration utilise l'autoscaling, tous les serveurs doivent également être associés dynamiquement au domaine, ce qui ralentit le processus de création d'un serveur. L'autoscaling peut également entraîner une accumulation d'objets informatiques obsolètes dans le répertoire, appelant ainsi une logique de nettoyage supplémentaire. Si vous recourez au service Active Directory dans un environnement cloud, vous devez prendre en compte ces facteurs supplémentaires.

En l'absence d'un service Active Directory, l'authentification doit s'effectuer via NTLM ou par d'autres moyens, tels que l'authentification HTTP de base. Les deux approches exigent que les identifiants restent synchronisés entre le serveur de déploiement et les serveurs d'applications, et stockés de manière sécurisée. Ces deux tâches peuvent s'avérer difficiles.

Que vous utilisiez Linux ou Windows, la sécurisation de la communication entre le serveur de déploiement et le serveur d'applications nécessite des mécanismes distincts d'IAM. Cependant, le contrôle de l'accès aux systèmes à l'aide de plusieurs mécanismes augmente la complexité globale et donc le risque d'une configuration inappropriée.

Mises à jour du système d'exploitation (OS)

S'il est important de pouvoir déployer efficacement les nouvelles versions de packages d'applications sur des serveurs d'applications, il est tout aussi fondamental de desservir le système d'exploitation (OS) sous-jacent sur ces mêmes serveurs. Par conséquent, cela implique d'installer des correctifs de sécurité. Pour les parcs de serveurs plus importants, vous devez automatiser ce processus de façon à minimiser les risques et le nombre de serveurs indisponibles lors de la mise à jour.

Pour mettre à jour l'OS, vous pouvez également choisir une approche Push. Dans ce cas, le serveur de déploiement déclenche la mise à jour de l'OS sur les serveurs d'applications. Sous Linux, il est courant de faire appel au protocole SSH pour exécuter à distance des commandes de mise à jour à cet effet. Sous Windows, PowerShell Remoting (qui repose sur WinRM) est une option fréquemment utilisée. Ces deux mécanismes doivent vous permettre de sécuriser à la fois l'authentification et le stockage des identifiants.

Autoscaling

Dans un environnement statique où le nombre de serveurs d'applications ne change pas, le serveur de déploiement connaît toutes les cibles de déploiement à l'avance. Dans un environnement cloud, il est souvent avantageux d'augmenter ou de réduire automatiquement le nombre de serveurs d'applications. En revanche, deux problèmes se posent lorsque vous déployez des applications en mode Push :

  • Lorsque vous ajoutez un nouveau serveur d'applications, vous devez l'enregistrer auprès du serveur de déploiement pour qu'il soit inclus dans les déploiements ultérieurs.
  • Le nouveau serveur doit recevoir son déploiement initial.

Un événement d'autoscaling n'est pas initié par le serveur de déploiement, mais par le groupe d'instances géré sous-jacent, qui fonctionne à un niveau inférieur à celui du serveur de déploiement.

La nouvelle instance de serveur d'applications doit s'enregistrer auprès du serveur de déploiement et déclencher un déploiement avant que le nouveau serveur d'applications puisse répondre aux requêtes. Le diagramme suivant illustre ce processus.

Autoscaling et déploiements en mode Push

Pour que cette approche fonctionne, il ne suffit pas que le serveur de déploiement puisse contacter des serveurs d'applications et s'authentifier auprès d'eux. Ces derniers doivent également contacter le serveur de déploiement et s'authentifier auprès de lui.

Enfin, le serveur qui vient d'être démarré doit également disposer des derniers correctifs de sécurité de l'OS. Or, le lancement d'une mise à jour pendant l'autoscaling retarderait considérablement le processus. Par conséquent, les mises à jour doivent déjà être installées sur l'image à partir de laquelle la VM du serveur d'applications est créée. Pour ce faire, vous avez le choix entre deux méthodes :

  • Utiliser les images publiques fournies par Google Cloud, qui sont mises à jour par Google. Comme ces images ne contiennent que l'OS, vous devez gérer toutes les personnalisations (code de votre application, utilitaires et configurations d'OS) à l'aide de scripts de démarrage ou dans le cadre du déploiement de l'application.
  • Conserver une image d'OS personnalisée et la maintenir à jour. Cette approche vous permet de personnaliser l'image, mais augmente la complexité globale liée à la gestion des déploiements.

Effectuer des déploiements en mode Push est donc une méthode intuitive, mais qui risque d'augmenter considérablement la complexité lorsque l'on tient compte de la sécurité, des mises à jour d'OS et de l'autoscaling. Dans la section suivante, nous nous intéressons aux déploiements en mode Pull, la méthode de déploiement la plus "cloud native".

Déploiements en mode Pull

Les déploiements en mode Pull s'effectuent de manière indirecte. Une fois que le système CI a généré une nouvelle version d'un artefact de déploiement, il publie cet artefact dans un dépôt. Le diagramme suivant illustre ce processus :

Déploiements en mode Pull

Lorsqu'un déploiement est effectué, immédiatement après la publication de l'artefact ou ultérieurement, le serveur de déploiement déclenche le déploiement réel. Là encore, le serveur de déploiement peut être un système distinct ou un rôle exécuté par le système CI. Pour déclencher le déploiement, la connexion au serveur d'applications est nécessaire pour lui permettre d'extraire et d'installer l'artefact de déploiement à partir du dépôt central.

Bien que les différences entre le modèle Push et le modèle Pull puissent vous sembler mineures de prime abord, la mise en œuvre d'un déploiement en mode Pull entraîne d'importantes conséquences :

  • Le déclenchement d'un serveur d'applications pour extraire un artefact de déploiement ne doit pas nécessairement se produire au niveau de l'application ou de l'OS. Au lieu de cela, le serveur de déploiement peut déclencher l'opération d'extraction en ordonnant à Compute Engine de redémarrer ou de remplacer la VM. Cette méthode peut permettre d'éviter les problèmes de sécurité associés aux déploiements en mode Push.
  • Plutôt que de simplement contenir des fichiers d'application, l'artefact de déploiement peut être une image Docker ou une image de VM, ce qui permet d'unifier le processus de mise à jour des applications et de l'OS.

Sécurité

Pour certains types de déploiements, le serveur de déploiement n'a pas besoin d'interagir avec le serveur d'applications. Par exemple, aucune interaction n'est nécessaire si l'artefact de déploiement est l'un des éléments suivants :

  • Une image de VM
  • Une image Docker à déployer sur Google Kubernetes Engine
  • Un package à déployer sur App Engine

Le serveur de déploiement doit simplement interagir avec les API Google Cloud pour lancer le déploiement. Le processus de déploiement peut donc s'appuyer sur des mécanismes d'authentification fournis par IAM, ce qui évite d'avoir à gérer des clés ou des identifiants.

Lorsque vous utilisez des artefacts de déploiement tels que des packages zip ou NuGet, qui ne contiennent que les fichiers d'application et les fichiers binaires, vous pouvez déclencher un déploiement de l'une des manières suivantes :

  • Si le serveur est configuré pour extraire et installer le dernier artefact de déploiement lors du démarrage de l'OS, vous pouvez déclencher une mise à jour en ordonnant à Google Cloud de redémarrer la VM. Même si le redémarrage peut sembler une perte de temps, il évite d'avoir à authentifier le serveur de déploiement auprès du serveur d'applications.
  • Comme pour les déploiements en mode Push, le serveur de déploiement peut déclencher la mise à jour à distance via un canal arrière. Cependant, cette approche est soumise aux mêmes implications en matière de sécurité et aux mêmes contraintes en ce qui concerne la gestion des identifiants que celles des déploiements en mode Push.
  • Le serveur de déploiement peut exécuter un agent qui recherche de nouveaux artefacts de déploiement dans le dépôt. Lorsqu'un nouvel artefact est détecté, le serveur peut l'appliquer automatiquement. Cependant, un problème peut éventuellement se poser : plusieurs serveurs d'applications risquent d'installer des mises à jour simultanément et de perdre leur disponibilité. Pour éviter cela, l'agent peut suivre l'état du serveur dans le dépôt et exploiter ces informations d'état pour déployer les mises à jour de manière contrôlée.

Afin d'empêcher les serveurs d'extraire et d'installer des packages malveillants, assurez-vous de contrôler l'accès en écriture au dépôt dans chacun de ces cas.

Mises à jour du système d'exploitation (OS)

Lorsque des images Docker ou de VM sont utilisées comme artefacts de déploiement, ces artefacts combinent des fichiers d'application et des dépendances. Cela vous permet d'utiliser le même mécanisme de déploiement pour mettre à jour le système d'exploitation et l'application. Dans ce cas, vous devez vous assurer qu'un nouvel artefact de déploiement peut être créé et publié dans deux cas distincts : premièrement, la mise à disposition d'une nouvelle version de l'application et deuxièmement, la publication de nouvelles mises à jour de sécurité de l'OS ou d'autres dépendances.

Dans d'autres cas, où l'artefact de déploiement ne contient que les fichiers de l'application, la mise à jour de l'OS est une tâche distincte. Par conséquent, les mêmes implications que celles évoquées dans le contexte des déploiements en mode Push s'appliquent.

Autoscaling

La capacité des serveurs d'applications à extraire des artefacts de déploiement cadre bien avec l'idée de l'autoscaling, car cela réduit considérablement la complexité résultant de la combinaison de cette fonctionnalité avec les déploiements en mode Push. Chaque fois qu'un nouveau serveur d'applications est lancé en raison d'un événement d'autoscaling, le serveur contacte le dépôt, puis extrait et installe le dernier package de déploiement.

Si vous utilisez des images VM ou Docker, les mécanismes permettant d'extraire des images sont fournis par GCP. Si vous utilisez d'autres packages tels que des archives zip ou NuGet, vous devez configurer des serveurs d'applications pour lancer un déploiement après le démarrage. Pour ce faire, vous pouvez personnaliser l'image de la VM ou exécuter des scripts de démarrage.

Cibles de déploiement

Auparavant, les applications .NET ne fonctionnaient que sous Windows, qui ne permettait pas d'utiliser des conteneurs. Cela laissait peu de choix quant à l'environnement dans lequel exécuter l'application.

Depuis l'introduction de .NET Core, vous pouvez décider d'exécuter une application sous Windows ou sous Linux. De plus, comme les deux systèmes d'exploitation permettent d'utiliser des conteneurs, vous avez désormais plusieurs choix quant à l'environnement à cibler.

Système d'exploitation

Bien que Mono offre un moyen de déployer des applications .NET sur des plates-formes autres que Windows depuis de nombreuses années, ce n'est que depuis la publication de .NET Core que Linux est devenu une plate-forme entièrement compatible avec la pile de développement Microsoft.

Toutefois, .NET Core ne fournit qu'un sous-ensemble des fonctionnalités du framework .NET. Par conséquent, le ciblage de .NET Core impose certaines restrictions aux applications. Plus important encore, le portage de .NET Framework vers .NET Core n'est pas toujours pratique ni rentable avec des applications existantes et peut, dans certains cas, ne pas être du tout possible.

Par conséquent, la question fondamentale qui se pose lors du choix d'un modèle et d'une cible de déploiement est de savoir s'il faut utiliser Linux (qui nécessite .NET Core) ou Windows (compatible avec .NET Core ou .NET Framework).

Voici les avantages que peut offrir l'exécution d'applications .NET sous Linux :

Vous devez donc évaluer ces avantages par rapport aux inconvénients éventuels liés à l'utilisation de .NET Core sous Linux, qui sont indiqués ci-dessous :

  • L'effort requis pour porter une application .NET existante vers un framework .NET Core pourrait freiner les possibilités de réduction des coûts, ou, comme indiqué plus haut, porter une application .NET existante vers .NET Core pourrait tout simplement s'avérer impossible.
  • Le serveur IIS n'est pas compatible avec Linux. Quant à Kestrel, le serveur Web .NET Core, il affiche de très bonnes performances, mais n'offre pas les mêmes fonctionnalités que le serveur IIS. Par conséquent, il sera peut-être nécessaire de combiner un serveur Kestrel et un serveur Web tel que Nginx.
  • Un service Windows n'a pas d'équivalent direct sous Linux. Bien que vous puissiez d'habitude convertir des services Windows en applications pour console Linux qui s'exécutent en tant que daemons, cette conversion n'est pas toujours pratique.
  • Le dépannage et le débogage des applications .NET Core sous Linux nécessitent des compétences et des outils différents de ceux utilisés avec .NET sous Windows. Si votre équipe dispose de peu d'expérience de l'environnement Linux, ces tâches peuvent s'avérer difficiles.

Conteneurs

Les conteneurs se prêtent particulièrement bien aux applications exécutées dans un processus unique. Voici quelques exemples :

  • Services Windows
  • Applications de console Linux agissant en tant que daemons
  • Services WCF auto-hébergés
  • Applications ASP.NET MVC ou API Web hébergées sur un serveur Kestrel

De nombreuses applications .NET ciblent les serveurs IIS. Généralement utilisés pour gérer plusieurs applications (dans des répertoires virtuels et des pools d'applications distincts), ils peuvent ne pas correspondre au modèle à processus unique.

Lorsque vous déplacez une configuration basée sur un serveur IIS vers un conteneur, vous pouvez adopter différentes approches :

  • Placer le serveur IIS, ainsi que tous les répertoires et pools virtuels, dans une seule image Docker Windows en utilisant l'image microsoft/iis comme base. À moins que les applications ne soient étroitement couplées, cette approche n'est généralement pas recommandée car elle ne permet pas de mettre à jour ni de déployer des applications séparément.
  • Utiliser des images Docker Windows distinctes pour chaque application, chacune exécutant le serveur IIS. En procédant ainsi, vous pouvez gérer les applications indépendamment. Cependant, dans le cas où vous devriez exploiter un grand nombre de conteneurs, le serveur IIS engendre des frais généraux non négligeables qui peuvent devenir importants.
  • Migrer toutes les applications ou certaines d'entre elles depuis le serveur IIS vers le serveur Kestrel. Étant donné que le serveur Kestrel peut être déployé dans un conteneur Windows ou un conteneur Docker sous Linux, cette approche vous permet de gérer les conteneurs individuellement.

Avec le serveur IIS, plusieurs applications Web peuvent s'exécuter sur un même site Web et partager un même nom de domaine. Lorsque vous regroupez des applications dans des conteneurs distincts, vous pouvez obtenir la même fonctionnalité en utilisant l'équilibrage de charge basé sur le contenu. De même, un équilibreur de charge HTTP Google rend inutile le déploiement d'un proxy inverse personnalisé en amont des serveurs Kestrel.

La plupart des applications peuvent être placées dans un conteneur. Il est rare que l'une ne le soit pas. Toutefois, certains scénarios de conteneurisation présentent des défis :

  • Pour les applications gérées par un serveur IIS, il est fréquent que le déploiement soit déjà automatisé. Cependant, les étapes de configuration d'un serveur IIS (création de pools d'applications, liaisons, etc.) s'effectuent manuellement. Lorsque vous adoptez une approche basée sur les conteneurs, vous devez également automatiser toutes ces étapes initiales.
  • Les applications qui reposent sur des fichiers de configuration ou sur des données stockées sur disque peuvent nécessiter des modifications. Par exemple, vous pouvez obtenir les informations de configuration à partir de variables d'environnement, et installer les fichiers et dossiers concernés sous forme de volumes. De cette manière, vous pouvez conserver l'image sans état ni configuration spécifique à l'environnement.

Enfin, si vous utilisez des conteneurs Docker basés sur Windows, sachez que Google Cloud n'est actuellement pas compatible avec la technologie Hyper-V et ne vous permet pas d'exécuter des conteneurs Hyper-V. Par conséquent, dans Google Cloud, vous ne pouvez employer que des conteneurs Windows Server. Ils sont plus légers que les conteneurs Hyper-V, mais offrent une isolation légèrement moins performante.

Contraintes de déploiement

Certains facteurs liés à la façon de créer une application peuvent imposer des contraintes par rapport à la méthode de déploiement utilisée, comme nous l'avons expliqué dans cette section.

Architecture de l'application

Un autre facteur à prendre en compte lors du choix de la cible et du modèle de déploiement est l'architecture de l'application. D'un côté, une application peut suivre un modèle d'architecture monolithique, dans lequel toute sa logique est mise en œuvre dans une base de code unique et s'exécute dans un seul processus ou dans un pool d'applications IIS. D'un autre côté, une application peut suivre un modèle de microservices. Dans cette approche, l'application se compose d'un certain nombre de services qui s'exécutent indépendamment dans des processus distincts, des pools d'applications IIS individuels ou bien comme des services Windows séparés.

Enfin, vous pouvez déployer plusieurs applications indépendantes à l'aide d'une stratégie de déploiement uniforme, selon laquelle chaque application peut être monolithique. Aux fins de la présente discussion, cette approche peut être considérée comme équivalente au scénario de microservices.

Une architecture de microservices doit permettre d'exécuter l'application de manière rentable tout en isolant et en gérant les services de manière indépendante. Vous pouvez allouer des VM dédiées à chacun de ces services afin de les gérer et de les déployer individuellement. En revanche, dans cette approche, un grand nombre de VM peuvent être sous-utilisées, ce qui entraîne des coûts inutiles. Pour de telles applications, les modèles de déploiement permettent un regroupement plus strict, en particulier lorsqu'ils reposent sur des conteneurs, et sont vraisemblablement plus rentables.

Avec état et sans état

Lorsque vous concevez des applications pour le cloud, essayez de les maintenir sans état et de gérer l'état en externe à l'aide d'un service de stockage basé sur GCP. Les applications sans état offrent de nombreux avantages dont voici quelques exemples :

  • Possibilité de les déployer de manière redondante pour accroître la disponibilité et la capacité
  • Possibilité de répartir librement les requêtes entre diverses instances
  • Ajustement parfait à l'autoscaling
  • En cas d'échec, possibilité de recréer l'environnement (qu'il s'agisse d'un conteneur ou d'une VM) sans risque de perte de données

Concevoir des applications de sorte qu'elles demeurent sans état n'est pas toujours facile. D'ailleurs, de nombreuses applications plus anciennes ne s'y conforment pas. Néanmoins, il est intéressant de déterminer s'il est possible de déployer une application sans état.

État de la session

Les applications ASP.NET et ASP.NET MVC utilisent couramment des sessions afin de suivre l'état de l'utilisateur, ce qui confère un état à l'application. Cependant, plusieurs options permettent de limiter l'impact des sessions :

  • Si la quantité de données de session est faible, vous pouvez stocker l'état dans un cookie chiffré ou signé.
  • Plutôt que d'utiliser le fournisseur d'état de session InProc par défaut, vous pouvez utiliser le fournisseur SQLServer. Toutefois, cette méthode nécessite une instance SQL Server, ce qui engendre des coûts supplémentaires et peut affecter la latence et la disponibilité de l'application.
  • Vous pouvez tirer parti de la méthode basée sur l'affinité de session dans Cloud Load Balancing. Cette fonctionnalité garantit le routage de toutes les requêtes d'un seul client vers la même instance d'application. Cependant, l'utilisation de l'affinité de session peut compromettre l'équité de l'équilibrage de charge. En d'autres termes, certaines instances d'applications peuvent recevoir plus de requêtes que d'autres. Par ailleurs, si une instance d'application est arrêtée pour une raison quelconque, toutes les sessions gérées par cette instance seront perdues, ce qui pourrait avoir des répercussions sur l'utilisateur final. S'en remettre à l'affinité de session n'est donc pas une solution idéale, mais peut souvent offrir un compromis viable entre robustesse et coût.

Caches en mémoire

Afin d'éviter les calculs redondants ou les recherches dans les bases de données, les applications utilisent généralement des caches en mémoire. Cette pratique peut toutefois s'avérer problématique si plusieurs instances de l'application s'exécutent simultanément, car les caches peuvent devenir incohérents.

Pour éviter les incohérences, utilisez un cache distribué, soit directement, soit à l'aide de l'interface IDistributedCache. En principe, les serveurs de cache tels que Redis ou Memcached sont relativement moins gourmands en ressources, mais accroissent la complexité de la configuration globale.

Stockage

Les données sous forme d'images, de pièces jointes ou de fichiers multimédias sont généralement stockées sur un disque. Sur une VM, le stockage sur un disque persistant ne constitue pas une option viable, car cela empêche le partage de données entre plusieurs machines, et présente un risque de perte si une nouvelle instance de VM est générée. Choisissez plutôt l'une des approches suivantes :

  • Déplacer les données vers un serveur de partage de fichiers. Cette méthode réduit l'impact sur l'application, mais la mise en place d'un serveur SMB ou NFS à haute disponibilité engendre des coûts et des efforts de maintenance supplémentaires.
  • Déplacer les données vers Cloud Storage. Bien que cette méthode implique de modifier l'application, Cloud Storage offre une haute disponibilité, est beaucoup plus économique que l'exécution d'un serveur de fichiers, et ne nécessite aucune opération de maintenance supplémentaire.

Stratégies de déploiement

Lorsque vous déployez une nouvelle version d'application, vous devez minimiser les risques et les répercussions sur l'utilisateur final. Les trois stratégies les plus courantes pour y parvenir sont les déploiements Recréer, Bleu/Vert et les déploiements progressifs.

Stratégie Recréer

L'idée de la stratégie Recréer consiste à arrêter l'application en cours d'exécution sur tous les serveurs, à en déployer une nouvelle version et à démarrer l'application. L'inconvénient majeur de cette stratégie est de provoquer une interruption de service, mais elle évite les problèmes pouvant éventuellement survenir lorsque deux versions différentes d'une application coexistent temporairement et accèdent à des données communes.

Stratégie Bleu/Vert

La stratégie Bleu/Vert (également appelée Rouge/Noir) consiste à déployer une nouvelle version de l'application sur un nouvel ensemble de serveurs. Une fois le déploiement terminé, vous transférez tout le trafic de l'ancien vers le nouvel ensemble de serveurs. Cette approche nécessite temporairement jusqu'à deux fois le nombre de serveurs nécessaires à la production, mais évite les interruptions de service.

Par ailleurs, cette stratégie exige que deux versions d'une application puissent coexister temporairement sans interférer l'une avec l'autre. Dans le cas des applications qui accèdent aux bases de données, chaque itération des modifications apportées aux schémas de base de données doit être compatible, au minimum, avec la version précédente.

Stratégie de déploiement progressif

Le déploiement progressif consiste à mettre à jour un serveur après l'autre. Comme pour la stratégie Bleu/Vert, deux versions différentes d'une application doivent coexister pendant un certain temps. Toutefois, contrairement au déploiement Bleu/Vert, vous transférez progressivement le trafic de l'ancienne vers la nouvelle version. À mesure que les serveurs sont mis à jour, le nombre d'utilisateurs routés vers la nouvelle version augmente jusqu'à ce que tous l'utilisent dès la mise à jour du dernier serveur. Cette approche présente un avantage clé : les problèmes potentiels peuvent être détectés rapidement, avant que tous les utilisateurs ne soient affectés, ce qui contribue à réduire le risque global.

Étant donné que les déploiements progressifs reposent sur la coexistence de deux versions de l'application, cette stratégie implique souvent de configurer un équilibreur de charge de façon à éviter le renvoi des utilisateurs d'une version à l'autre.

Options de déploiement

Jusqu'à présent, nous avons évoqué les modèles, les cibles et les stratégies de déploiement dans cet article. Les sections suivantes présentent des options spécifiques permettant de déployer des applications .NET sur Google Cloud.

Environnement flexible App Engine (Linux)

L'environnement flexible App Engine fournit un environnement PaaS (Platform as a Service) pour les applications .NET Core. L'environnement flexible d'App Engine étant basé sur Linux, il n'est utile que pour les applications .NET Core.

Cet environnement flexible utilise, en interne, des conteneurs pour exécuter et faire évoluer des applications, mais vous évite de créer ou de gérer des images de conteneur. À la place, les fichiers binaires de l'application peuvent être déployés directement. En s'appuyant sur les services, l'environnement flexible App Engine vous permet d'exécuter des applications décomposées en plusieurs microservices plus petits.

L'environnement flexible App Engine peut adapter automatiquement le nombre d'instances d'application en fonction de la charge, en tenant compte des limites que vous avez configurées pour l'application. Par défaut, un minimum de deux instances est conservé, bien que vous puissiez modifier ce paramètre.

L'environnement flexible App Engine convient mieux aux applications sans état. Vous pouvez désactiver l'autoscaling pour prendre en charge les applications avec état, mais dans ce cas, vous ne bénéficierez pas des nombreux avantages de l'environnement géré. Par ailleurs, bien que l'environnement flexible App Engine autorise l'accès aux disques, ils sont considérés comme éphémères et ne sont donc pas utiles pour le suivi de l'état persistant.

Pour chaque instance d'une application, l'environnement flexible App Engine gère une VM dédiée. La tarification étant basée sur le nombre de VM en cours d'exécution, l'environnement flexible App Engine est plus rentable lorsque l'application est fortement utilisée. Dans le cas contraire, les VM sous-jacentes peuvent être mal exploitées, ce qui peut compromettre la rentabilité de l'environnement flexible App Engine par rapport aux autres options de déploiement, en particulier de l'environnement GKE.

Déploiement en mode Pull à l'aide de l'outil de ligne de commande gcloud

Le moyen le plus courant de déployer l'environnement flexible App Engine consiste à utiliser l'outil de ligne de commande gcloud. Dans un premier temps, il sert à publier des artefacts de déploiement dans un dépôt géré par Cloud Storage. Chaque fois qu'une instance est lancée, les artefacts sont extraits de ce dépôt. Les déploiements s'appuient sur la stratégie Bleu/Vert par défaut.

Chaque déploiement est suivi par un numéro de version. En cas de problème, il est possible de rétablir un déploiement dans une version précédente. Grâce à la répartition du trafic, l'environnement flexible App Engine vous permet également d'exécuter plusieurs versions de l'application en parallèle et de diriger une certaine partie du trafic vers l'une ou l'autre version. Ainsi, les déploiements Canary ou les tests A/B ne demandent qu'un minimum d'effort.

GKE (Linux)

L'outil GKE fournit un environnement Kubernetes entièrement géré. Les capacités d'orchestration de Kubernetes font de GKE un outil particulièrement bien adapté à l'exécution d'applications de microservices complexes constituées de nombreux conteneurs. Économe en ressources et facile à gérer, cet outil vous permet d'exécuter beaucoup de conteneurs sur une infrastructure partagée, même pour les applications qui ne s'appuient pas sur le modèle des microservices.

GKE exige de regrouper toutes les parties de l'application en tant que conteneurs Docker. Ces derniers doivent être basés sur Linux, car GKE n'est pas compatible avec les conteneurs Windows pour le moment. Pour créer des conteneurs, vous devez donc mettre en place un framework .NET Core et un environnement basé sur Linux. Or, si votre système est basé sur Windows, la création de conteneurs sous Linux peut s'avérer difficile. Quoi qu'il en soit, Azure Pipelines/Team Foundation Server et Cloud Build permettent, de façon intégrée, de créer des applications .NET Core ainsi que de compiler et de publier des images de conteneurs basées sur Linux.

L'outil GKE offre la plus grande flexibilité avec les applications sans état, mais vous pouvez également exécuter certains types d'applications avec état en utilisant des ensembles avec état et des volumes persistants.

Un cluster GKE comprend un certain nombre d'instances de VM, appelées nœuds, sur lesquelles des conteneurs sont planifiés. Dans le cas d'un cluster multizone ou régional, GKE peut répartir les nœuds et les charges de travail sur plusieurs zones afin d'assurer une haute disponibilité.

La tarification est basée sur le nombre de nœuds en cours d'exécution. L'outil GKE est donc le plus rentable lorsque les nœuds sont utilisés à bon escient. Vous pouvez exécuter des charges de travail plus importantes sur le même cluster ou adapter automatiquement le nombre de nœuds en fonction des besoins.

Déploiement en mode Pull à l'aide des commandes kubectl

Le déploiement d'une application sur GKE s'effectue en deux étapes :

  1. Publication des images Docker dans Container Registry ou dans un registre Docker externe via la commande docker push ou à l'aide d'un autre moyen. En général, le système CI se charge de cette étape.
  2. Déclenchement du déploiement à l'aide de kubectl. Cette étape peut être gérée par le système CI ou séparément. Comme le déploiement est lancé à distance, il importe peu que kubectl soit exécuté sous Linux ou sous Windows.

L'outil GKE est compatible avec les stratégies de déploiement de type "Recréer" et progressif. Bien que les primitives de contrôle des déploiements soient suffisamment flexibles pour autoriser d'autres stratégies, l'adoption d'une stratégie différente nécessite des outils ou des scripts supplémentaires.

Déploiement en mode Pull avec Spinnaker

Si les fonctionnalités intégrées de GKE pour orchestrer les déploiements s'avèrent insuffisantes, vous pouvez associer GKE avec Spinnaker. Spinnaker étant compatible avec GKE, vous pouvez mettre en œuvre des stratégies de déploiement plus avancées telles que les déploiements Bleu/Vert.

Comme Spinnaker n'est pas un service géré, vous devez le déployer et le gérer séparément. Vous pouvez déployer Spinnaker sur des instances de VM Linux distinctes ou dans un cluster GKE.

Compute Engine (Windows ou Linux)

Compute Engine vous permet de créer et de gérer des instances de VM. Il est compatible avec une série de versions de Windows Server et de distributions Linux, ainsi qu'avec plusieurs options de dimensionnement et de configuration. Compte tenu de cette flexibilité, vous pouvez recourir aux instances de VM Compute Engine pour un large éventail de charges de travail.

Pour garantir le déploiement et la gestion des applications de manière individuelle, déployez une seule application ou un seul service pour chaque instance de VM. Pour assurer une haute disponibilité, exécutez au moins deux instances de VM par application, chacune située dans une zone différente. On peut donc supposer que vous aurez besoin du double du nombre d'instances de VM et d'applications ou services que vous souhaitez déployer, quelle que soit la charge attendue.

Compute Engine offre un moyen simple de mettre en œuvre l'autoscaling via des groupes d'instances gérés. De même, ces groupes fournissent également un moyen de mettre en œuvre des déploiements progressifs, comme expliqué plus loin dans cet article.

Étant donné que Compute Engine est facturé par instance de VM, on peut considérer que l'exécution d'applications sur Compute Engine est plus rentable lorsque les applications reçoivent une charge de travail considérable, ce qui se traduit par une utilisation élevée des instances de VM. En revanche, si le nombre de services et d'applications est important, mais que l'utilisation moyenne est faible, d'autres options de déploiement telles que GKE sont souvent plus économiques, car elles permettent à plusieurs applications de tirer parti d'une infrastructure commune sans sacrifier l'isolation de la charge de travail.

L'exécution d'instances de VM Windows nécessite l'utilisation d'images payantes. Or, ces images contiennent des copies sous licence de Windows et entraînent des frais supplémentaires. Par conséquent, les VM Windows sont généralement moins rentables que celles qui reposent sur des distributions Linux telles que CentOS ou Debian, qui ne génèrent aucuns frais de licence.

Vous pouvez recourir au protocole SSH ou RDP pour configurer manuellement une instance de VM, soit pour déployer une application de cette manière, soit pour gérer une configuration initiale nécessaire à la préparation d'une machine en vue d'un premier déploiement. Cette pratique peut toutefois donner lieu à des machines de configurations uniques, différentes des autres instances de VM. À long terme, la configuration manuelle d'une instance de VM peut devenir complexe et demander beaucoup de travail. Il est donc conseillé d'automatiser le processus afin de le rendre reproductible.

L'automatisation des déploiements d'applications sur Compute Engine consiste à effectuer les tâches suivantes :

  1. Provisionner les instances de VM et les préparer à un premier déploiement d'application
  2. Déployer une application
  3. Effectuer la maintenance de l'OS (installer des mises à jour de sécurité)

Dans les deux sections suivantes, nous expliquons comment gérer les trois étapes de manière unifiée à l'aide du déploiement en mode Pull. Bien que les approches décrites dans ces sections fassent appel à des mécanismes et outils différents, l'idée générale est semblable à la manière de déployer une application basée sur un conteneur à l'aide de GKE.

Déploiement en mode Pull à l'aide d'un groupe d'instances géré

Les groupes d'instances gérés servent le plus souvent à mettre en œuvre l'autoscaling, mais ils permettent également de gérer les déploiements progressifs. Après avoir créé un modèle d'instance faisant référence à la nouvelle version de l'application, vous pouvez employer la fonctionnalité de remplacement progressif pour remplacer les instances de VM reposant sur l'ancien modèle par des instances basées sur le nouveau modèle.

Cette approche fonctionne à condition que la nouvelle version de l'application soit mise à disposition en tant que modèle d'instance. Pour ce faire, vous avez le choix entre deux méthodes :

  • Définir un modèle d'instance qui utilise l'une des images publiques de l'OS. Vous exécutez un script de démarrage pour configurer le système et installer l'application à partir d'un bucket Cloud Storage, d'un dépôt NuGet, d'un registre Docker ou d'une autre source. Le schéma suivant illustre cette approche.

    Déploiements en mode Pull reposant sur un groupe d'instances géré et une image publique

  • Créer une image de VM personnalisée dans le cadre du processus CI/CD, processus souvent appelé image baking. Dans cette approche, vous utilisez l'une des images publiques de système d'exploitation pour générer une nouvelle instance de VM, y installer la dernière application, créer une image de VM à partir de l'instance et la rendre disponible dans le projet Google Cloud. L'ensemble du processus peut être entièrement automatisé à l'aide d'un outil tel que Packer. Vous pouvez ensuite référencer l'image obtenue dans un modèle d'instance. Le schéma suivant illustre cette approche.

    Déploiements en mode Pull reposant sur un groupe d'instances géré et une image personnalisée

La création d'une image personnalisée (seconde option) présente néanmoins l'inconvénient de ralentir le processus "image baking", qui prend souvent plusieurs minutes. Ainsi, non seulement cette approche ralentit le processus CI/CD, mais elle accroît également sa complexité. En revanche, le lancement de nouvelles VM à l'aide d'une image personnalisée est un processus simple et rapide, particulièrement bénéfique avec l'autoscaling.

Quant au déploiement d'application à l'aide de scripts de démarrage (première option), il présente des inconvénients opposés. En effet, s'il n'entraîne pas de surcharge lors du processus "image baking" ou CI/CD, il ralentit néanmoins le processus de création d'instances de VM. En outre, si le script de démarrage n'est pas totalement fiable ou si les systèmes à partir desquels les fichiers binaires de l'application sont téléchargés ne sont pas hautement disponibles, cette approche peut réduire la disponibilité.

Ainsi, l'approche la mieux adaptée à votre application dépend de l'application elle-même et de la complexité de la configuration. Dans certains cas, il peut même être préférable de combiner les deux approches :

  • Une image personnalisée contient toutes les dépendances et la configuration, mais pas les fichiers binaires de l'application. Lorsque la configuration ou l'une des dépendances change, une nouvelle image est générée, mais pas pour chaque version d'application. Cela permet d'éviter le ralentissement du pipeline d'application CI/CD.
  • L'application est installée à l'aide d'un script de démarrage. Pour minimiser les risques et les ralentissements, ce processus doit être aussi simple que possible.

Dans le cas où vous souhaiteriez déployer de nombreuses applications ou services différents ayant une configuration de base commune, cette approche hybride évite d'avoir à créer et à maintenir des dizaines ou des centaines d'images presque identiques.

En cas de charges de travail Linux et Windows, vous pouvez orchestrer les déploiements à l'aide des groupes d'instances gérés. Avec un système Linux, il est possible d'utiliser des groupes d'instances gérés pour déployer des conteneurs Docker sur des instances de VM, et cette fonctionnalité est compatible avec la plate-forme. Cela n'est toutefois recommandé que pour les applications utilisées de façon intensive. Dans les autres cas, le déploiement d'un seul conteneur Docker par VM ne présente que peu d'avantages par rapport à la mise en place de l'environnement flexible GKE ou App Engine.

Comme indiqué précédemment, l'outil GKE n'est pas compatible avec Windows pour le moment. Pour exécuter des conteneurs Windows Server à l'aide de Compute Engine et de groupes d'instances gérés, suivez les instructions ci-dessous :

  • Utilisez l'image publique Windows Server 1709 Datacenter Core for Containers ou une image créée sur mesure avec Docker préinstallé.
  • Lancez un script de démarrage pour extraire l'image Docker et la démarrer en tant que conteneur Windows Server lors du démarrage de la VM. Vous pouvez exposer les services en cours d'exécution dans le conteneur à l'aide des mappages de port appropriés.

Notez que l'exécution d'un script de démarrage uniquement après le démarrage du service Docker n'est pas garantie. Pour gérer efficacement le cas où le script s'exécute avant que Docker ne soit disponible, incorporez la logique de répétition appropriée dans le script.

Lorsque vous créez des images Windows dans un environnement autre que cloud, vous pouvez compter sur Microsoft Deployment Toolkit (MDT) ou Windows Deployment Services (WDS). Cependant, étant donné que la gestion d'images et la création d'instances de VM basées sur des images personnalisées sont des fonctionnalités essentielles de Compute Engine, cet outil supplémentaire n'est pas nécessaire. Compute Engine est non seulement compatible avec les scripts de démarrage, mais également avec les scripts de spécialisation pour les instances de VM Windows. Par conséquent, il n'est généralement pas nécessaire de travailler avec des fichiers unattend.xml personnalisés. Toutefois, avant de créer une image, il est toujours important de généraliser une installation Windows à l'aide de GCESysprep.

Déploiement en mode Pull avec Spinnaker

Si les groupes d'instances gérés constituent un moyen simple et efficace de mettre en œuvre des déploiements progressifs, leurs fonctionnalités peuvent s'avérer insuffisantes pour certaines applications. Pour mettre en œuvre des stratégies de déploiement et des pipelines plus sophistiqués, vous pouvez vous servir de Spinnaker.

L'approche de base adoptée par Spinnaker pour orchestrer les déploiements sur Compute Engine est semblable à celle décrite dans la section précédente, c'est-à-dire qu'elle repose également sur le processus "image baking". Par conséquent, les mêmes considérations s'appliquent.

Comme Spinnaker n'est pas un service géré, vous devez le déployer et le gérer séparément de l'application. Vous pouvez déployer Spinnaker sur des instances de VM Linux distinctes ou dans un cluster GKE.

Déploiement à distance en mode Push

Les options de déploiement en mode Pull abordées dans les sections précédentes offrent de nombreux avantages, Mais elles ne conviennent pas à tous les types d'applications. En particulier, elles sont peu adaptées aux applications avec état qui se prêtent mieux à une approche de déploiement en mode Push.

En mode Push, les trois tâches de déploiement (provisionnement des instances de VM, déploiement de l'application et maintenance de l'OS) doivent être gérées individuellement. S'il est possible de se servir des mêmes outils pour exécuter ces trois tâches, il n'est pas rare de faire appel à des outils différents pour chacune d'entre elles.

Vous pouvez provisionner les instances de VM du serveur d'applications de la même manière que les autres infrastructures : les outils d'automatisation couramment utilisés à cet effet incluent Deployment Manager et Terraform. Vous pouvez installer les outils d'automatisation du déploiement d'application à l'aide des scripts de démarrage ou de spécialisation. Par exemple, avec les outils Puppet, Chef ou Octopus Deploy, vous devez vous assurer que le logiciel agent est bien installé.

Du point de vue de la sécurité, afin de réduire la surface d'attaque, veillez à utiliser le réseau interne pour toute communication entre le serveur de déploiement et les agents s'exécutant sur les instances de VM du serveur d'applications. Par ailleurs, assurez-vous de ne pas exposer les ports utilisés à l'Internet public.

Dans un environnement ne faisant pas appel à l'autoscaling, la jonction de serveurs d'applications Windows à un domaine Active Directory constitue un moyen viable de centraliser la configuration. Active Directory vous permet également de contrôler des tâches de gestion telles que la maintenance de l'OS.

Choisir une option de déploiement

Comme indiqué au début de cet article, il n'existe pas de méthode optimale universelle pour déployer une application .NET sur Google Cloud. Les meilleures options dépendent de l'application et de vos besoins. Pour choisir le bon modèle, vous devez vous poser plusieurs questions. Vous devez d'abord vous demander si .NET Core ou .NET Framework est l'infrastructure à utiliser et, en fonction de cela, si le déploiement doit s'effectuer sous Linux ou Windows. Une fois que vous avez identifié l'OS cible, reportez-vous aux arbres décisionnels suivants pour déterminer le modèle de déploiement approprié.

Pour déployer des applications .NET Core sous Linux :

Arbre décisionnel pour le déploiement à l'aide de .NET Core et Linux

Pour déployer une application .NET Core ou .NET Framework sous Windows :

Arbre décisionnel pour le déploiement sous Windows

Étape suivante