Développer un adaptateur pour un rôle machine virtuelle dans Windows Azure

Mis à jour: mars 2011

[La fonction Rôle de machine virtuelle de Windows Azure sera mise hors service le 15 mai 2013. Après cette date, les déploiements du rôle de machine virtuelle seront supprimés. Pour poursuivre avec vos applications existantes, vous pouvez utiliser des machines virtuelles Windows Azure. Pour plus d'informations sur l'utilisation de machines virtuelles pour votre application, voir Moving from VM Role to Windows Azure Virtual Machines (Passer d'un rôle de machine virtuelle à des machines virtuelles Windows Azure).

Vous pouvez écrire un adaptateur en tant que service Windows qui démarre automatiquement lorsque le système d'exploitation démarre, et qui utilise l'API Microsoft.WindowsAzure.ServiceRuntime pour tirer parti des informations d'exécution de Windows Azure. Vous pouvez être amené à écrire un service Windows si vous avez besoin des informations d'adresses réseau de l'instance de rôle machine virtuelle actuelle ou d'autres instances de rôle en cours d'exécution dans votre service, si vous avez besoin d'écrire dans une ressource de stockage local, ou si vous avez besoin de lire les paramètres de configuration de service au moment de l'exécution ou d'y répondre quand ils changent.

Cette section montre comment créer un adaptateur qui illustre l'utilisation de services prenant en charge un rôle machine virtuelle. L'exemple utilisé dans cette section monte un lecteur Windows Azure au démarrage du système d'exploitation, puis configure les services IIS (Internet Information Services) pour écrire des fichiers journaux HTTP sur le lecteur.

Pour créer un adaptateur, effectuez les tâches suivantes :

  1. Créer un conteneur de stockage

  2. Créer le projet d'adaptateur

  3. Ajouter la possibilité de suivre les modifications de configuration de l'instance de rôle

  4. Définir ce qui se produit lorsque l'adaptateur démarre

  5. Définir ce qui se produit lorsque l'adaptateur s'arrête

  6. Créer les programmes d'installation de l'adaptateur

  7. Créer un projet d'installation pour l'adaptateur

  8. Ajouter un événement post-build pour corriger les incohérences de l'assembly

  9. Ajouter des paramètres de configuration au modèle de service cloud

  10. Installer l'adaptateur

L'adaptateur utilise le stockage d'objets BLOB pour faciliter le stockage des données de journalisation sur le lecteur Windows Azure. Vous devez avoir accès à un compte de stockage dans Windows Azure, et vous devez créer un conteneur utilisé par l'adaptateur. Utilisez l'outil de votre choix pour créer un conteneur dans le stockage Windows Azure et nommez ce conteneur comme bon vous semble. Vous utiliserez le nom du conteneur au moment de configurer le modèle de service cloud.

Visual Studio 2010 fournit un modèle de création de service Windows. Vous pouvez utiliser ce modèle afin de créer l'adaptateur pour vos instances de rôle machine virtuelle.

  1. Ouvrez Visual Studio 2010, cliquez sur Fichier, sur Nouveau, puis sur Projet.

  2. Dans le volet Modèles installés, sous Visual C#, cliquez sur Windows, puis dans le volet central, cliquez sur Service Windows.

  3. Entrez un nom pour la solution et le projet d'adaptateur, puis cliquez sur OK.

  4. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur la solution, cliquez sur Gestionnaire de configurations, veillez à sélectionner Any CPU pour le projet, puis cliquez sur Fermer.

  5. Dans l'Explorateur de solutions, renommez le fichier Service1.cs à l'aide du nom utilisé pour l'adaptateur. Les exemples de cette section utilisent l'espace réservé AdapterName, qui représente le nom de votre choix.

  6. Cliquez avec le bouton droit sur le projet, cliquez sur Propriétés, et dans la page d'application, vérifiez que .NET Framework 3.5 est sélectionné pour Framework cible.

  7. Dans la page de publication des propriétés du projet, cliquez sur Configuration requise, puis assurez-vous que .NET Framework 4 (Client Profile) n'est pas sélectionné.

  8. Dans l'Explorateur de solutions, ajoutez des références pour les assemblys suivants :

    • Microsoft.WindowsAzure.ServiceRuntime.dll

      noteRemarque
      Vous devez vous assurer que la propriété Copie locale de cet assembly a la valeur False.

    • Microsoft.WindowsAzure.CloudDrive.dll

    • Microsoft.WindowsAzure.StorageClient.dll

    • Microsoft.Web.Administration.dll

  9. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur AdapterName.cs, puis cliquez sur Afficher le code.

  10. Ajoutez ce qui suit en utilisant des instructions :

    
    using Microsoft.WindowsAzure.ServiceRuntime;
    using Microsoft.WindowsAzure.StorageClient;
    using Microsoft.WindowsAzure;
    using Microsoft.Web.Administration;
    using System.IO;
    using System.Threading;
    
  11. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur AdapterName.cs, puis cliquez sur Concepteur de vues.

  12. Dans le volet Propriétés, définissez les propriétés suivantes :

    • ServiceName - Spécifiez le nom sous lequel l'adaptateur est identifié par le système.

    • (Name) - Spécifiez le nom utilisé dans le code pour représenter l'objet d'adaptateur.

    • CanShutdown - Vous devez spécifier que cette propriété a la valeur True pour permettre à l'adaptateur d'être prévenu lorsque le système s'arrête.

Le fichier Program.cs contient le code suivant :


static void Main()
{
   ServiceBase[] ServicesToRun;
   ServicesToRun = new ServiceBase[] 
   { 
      new ServiceName() 
   };  
   ServiceBase.Run(ServicesToRun);
}

Vous pouvez définir les opérations qui sont effectuées lors d'une modification de la configuration d'une instance de rôle. Par exemple, vous pouvez modifier l'emplacement d'un lecteur de stockage des données de journalisation en changeant la configuration de l'instance de rôle. Pour ce faire, utilisez les événements RoleEnvironment.

  1. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur AdapterName.cs, puis cliquez sur Afficher le code.

  2. Modifiez le constructeur pour définir les événements de modification de configuration. L'exemple de code suivant illustre l'ajout des définitions d'événement au constructeur :

    
    public AdapterName()
    {
       InitializeComponent();
       RoleEnvironment.Changed += RoleEnvironmentChanged;
       RoleEnvironment.StatusCheck += RoleEnvironmentStatusCheck;
    }
    
  3. Ajoutez la méthode RoleEnvironmentChanged, qui est appelée lorsque l'événement Changed se produit. L'exemple de code suivant illustre la méthode RoleEnvironmentChanged, qui monte un nouveau lecteur Windows Azure et configure IIS pour écrire des fichiers journaux sur le nouveau lecteur :

    
    private CloudDrive currentDrive;
     
    private void RoleEnvironmentChanged(object sender, RoleEnvironmentChangedEventArgs e)
    {
       if(!e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>().Any(
          c => c.ConfigurationSettingName == "AdapterName.BlobPath"))
          return;
    
       try
       {
          // perform a rolling drive change
          var oldDrive = this.currentDrive;
          var newDrive = MountDrive();
          try
          {
             ConfigureWebServer(newDrive.LocalPath);
          }
          catch (Exception)
          {
             UnmountDrive(newDrive);
             throw;
          }
          this.currentDrive = newDrive;
          UnmountDrive(oldDrive);
       }
       catch (Exception ex)
       {
          this.EventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
          throw;
       }
    }
    

    AdapterName est le nom que vous avez fourni pour le projet d'adaptateur.

  4. Ajoutez les méthodes qui montent et démontent le lecteur Windows Azure, puis ajoutez la méthode qui permet de configurer l'emplacement des fichiers journaux pour IIS. L'exemple de code suivant illustre la méthode MountDrive :

    
    private CloudDrive MountDrive()
    {
       // create or mount an instance-specific drive
       var credentials = GetStorageCredentials();
       var driveUri = GetDriveUri();
       var drive = new CloudDrive(driveUri, credentials);
    
       try
       {
          drive.Create(1024);
       }
       catch (Exception ex)
       {
          if (ex.Message != "ERROR_BLOB_ALREADY_EXISTS") throw;
       }
    
       // mount the drive
       string mountPoint = drive.Mount(1024, 
          DriveMountOptions.FixFileSystemErrors | DriveMountOptions.Force);
       this.EventLog.WriteEntry(string.Format("{0} mounted at {1}", drive.Uri, mountPoint));
       return drive;
    }
    
    private Uri GetDriveUri()
    {
       return new Uri(string.Format(
       RoleEnvironment.GetConfigurationSettingValue("AdapterName.BlobPath"),
          RoleEnvironment.CurrentRoleInstance.Id));
    }
    
    private StorageCredentials GetStorageCredentials()
    {
       return new StorageCredentialsAccountAndKey(
       RoleEnvironment.GetConfigurationSettingValue("AdapterName.AccountName"),
       RoleEnvironment.GetConfigurationSettingValue("AdapterName.AccountKey"));
    }
    

    Pour plus d'informations sur l'utilisation de l'API CloudDrive, consultez CloudDrive. Les paramètres AdapterName.BlobPath, AdapterName.AccountName et AdapterName.AccountKey sont définis dans le fichier de définition du service cloud et sont configurés dans le fichier de configuration du service. Pour plus d'informations sur la définition de ces paramètres, consultez Ajouter des paramètres de configuration au modèle de service cloud.

    L'exemple de code suivant illustre la méthode UnmountDrive :

    
    private void UnmountDrive(CloudDrive drive)
    {
       drive.Unmount();
       this.EventLog.WriteEntry(string.Format("{0} unmounted", drive.Uri));
    }
    
    

    L'exemple de code suivant illustre la méthode ConfigureWebServer :

    
    private void ConfigureWebServer(string drivePath)
    {
       using (var config = new ServerManager())
       {
          var logdir = Path.Combine(drivePath, @"inetpub\logs\LogFiles");
          config.SiteDefaults.LogFile.Directory = logdir;
    
          config.CommitChanges();
    
          this.EventLog.WriteEntry(string.Format("IIS log location set to '{0}'", logdir));
       }
    }
    
    
  5. Ajoutez la méthode RoleEnvironmentStatusCheck qui permet de déterminer l'état de l'instance de rôle. L'objet statusCheckWaitHandle est utilisé comme signal pour informer le programme d'équilibrage de charge que l'instance de rôle est soit occupée, soit prête. L'appel de la méthode Set de l'objet est le signal qui indique que la modification de configuration est terminée. L'exemple de code suivant illustre la méthode RoleEnvironmentStatusCheck :

    
    private readonly EventWaitHandle statusCheckWaitHandle = new ManualResetEvent(false);
    private volatile bool busy = true;
    
    private void RoleEnvironmentStatusCheck(object sender, RoleInstanceStatusCheckEventArgs e)
    {
       if (this.busy)
       {
          e.SetBusy();
       }
       statusCheckWaitHandle.Set();
    }
    
    

Dans cet exemple, l'adaptateur effectue les opérations suivantes lorsqu'il démarre :

  • Initialiser le cache du lecteur

  • Monter le lecteur

  • Configurer IIS pour utiliser le lecteur monté

  1. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur AdapterName.cs, puis cliquez sur Afficher le code. Localisez la méthode OnStart qui a été substituée automatiquement lorsque vous avez créé le projet, puis ajoutez le code qui vérifie l'instance de rôle afin de s'assurer qu'elle s'exécute, qui effectue les opérations de l'adaptateur sur un thread distinct et qui signale la fin des opérations à l'aide de l'objet statusCheckWaitHandle.

    
    protected override void OnStart(string[] args)
    {
       /// Windows Azure waits for auto-start services to be fully started 
       /// before sending any traffic.  Service Control Manager (SCM) does
       /// not impose a time limit on startup; the service need only 
       /// request additional time.
    
       if (!RoleEnvironment.IsAvailable) return;
          
       var startThread = new Thread(OnStartInternal);
       startThread.Start();
    
       // wait until a status check has occurred, so that Windows Azure 
       // knows we are working on something.
       WaitForHandle(statusCheckWaitHandle);
    }
    

    L'exemple de code suivant illustre la méthode OnStartInternal, où le lecteur Windows Azure est monté et la configuration IIS modifiée afin de permettre l'utilisation du nouveau lecteur pour l'écriture des données de journalisation :

    
    private void OnStartInternal()
    {
       try
       {
          // initialize the drive cache
          string cachePath = RoleEnvironment.GetLocalResource("Data").RootPath;
          CloudDrive.InitializeCache(cachePath, 4096);
          this.EventLog.WriteEntry("initialization succeeded");
    
          // mount the current drive
          this.currentDrive = MountDrive();
    
          // configure IIS
          ConfigureWebServer(this.currentDrive.LocalPath);
    
          this.busy = false;
       }
       catch (Exception ex)
       {
          this.EventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
          throw;
       }
    }
    

    L'exemple de code suivant illustre la méthode WaitForHandle qui attend qu'une vérification d'état se produise :

    
    private const int ThreadPollTimeInMilliseconds = 1000;
    
    private void WaitForHandle(WaitHandle handle)
    {
       while (!handle.WaitOne(ThreadPollTimeInMilliseconds))
       {
          this.RequestAdditionalTime(ThreadPollTimeInMilliseconds * 2);
       }
    }
    

Dans cet exemple, l'adaptateur reconfigure l'emplacement des fichiers journaux et démonte le lecteur lorsqu'il s'arrête.

  1. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur AdapterName.cs, puis cliquez sur Afficher le code. Localisez la méthode OnStop, qui a été substituée automatiquement lorsque vous avez créé le projet, puis ajoutez le code qui reconfigure l'emplacement des fichiers journaux et démonte le lecteur.

    
    protected override void OnStop()
    {
       OnStopInternal();
    }
    
  2. L'exemple de code suivant illustre la méthode OnShutdown :

    
    protected override void OnShutdown()
    {
       /// Windows Azure stops sending traffic before shutting down.
       /// Note that some requests may still be executing.
       OnStopInternal();
    }
    
  3. Ajoutez la méthode OnStopInternal à l'emplacement où les opérations sont effectuées.

    
    private void OnStopInternal()
    {
       try
       {
          ConfigureWebServer(@"%SystemDrive%");
    
          if (this.currentDrive != null)
          {
             UnmountDrive(this.currentDrive);
             this.currentDrive = null;
          }
       }
       catch (Exception ex)
       {
          this.EventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
          throw;
       }
    }
    
    

Certaines actions personnalisées doivent se produire lors de l'installation d'un service Windows, ce qui peut être effectué par la classe Installer. Visual Studio peut créer ces programmes d'installation de manière spécifique pour un service Windows, et les ajouter à votre projet.

  1. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur AdapterName.cs, puis sélectionnez Concepteur de vues.

  2. Cliquez à l'arrière-plan du concepteur pour sélectionner l'adaptateur lui-même, plutôt que son contenu.

  3. Lorsque le concepteur a le focus, cliquez avec le bouton droit, puis cliquez sur Ajouter le programme d'installation.

    Par défaut, une classe de composant contenant deux programmes d'installation est ajoutée à votre projet. Le composant se nomme ProjectInstaller et les programmes d'installation qu'il contient correspondent au programme d'installation de votre adaptateur et au programme d'installation du processus associé à l'adaptateur.

  4. En mode Design pour ProjectInstaller, cliquez sur serviceInstaller1.

  5. Dans la fenêtre Propriétés, affectez à la propriété ServiceName le nom de votre adaptateur.

  6. Affectez la valeur Automatic à StartType.

  7. Dans le concepteur, cliquez sur serviceProcessInstaller1. Affectez LocalService à la propriété Account. Cela entraîne l'installation de l'adaptateur et son exécution sur un compte de service local.

  8. Générez le projet.

Un projet d'installation installe les fichiers projet compilés et exécute les programmes d'installation requis pour le bon fonctionnement de l'adaptateur. Pour créer un projet d'installation complet, vous devez ajouter la sortie du projet au projet d'installation, puis ajouter une action personnalisée afin d'installer le programme.

  1. Dans l'Explorateur de solutions, cliquez avec le bouton droit pour sélectionner votre solution, pointez sur Ajouter, puis cliquez sur Nouveau projet.

  2. Dans le volet Modèles installés, développez Autres types de projets, développez Projets de configuration et de déploiement, puis cliquez sur Programme d'installation de Visual Studio.

  3. Dans le volet central, cliquez sur Projet d'installation.

  4. Entrez le nom du projet d'installation, puis cliquez sur OK.

  5. Développez Dépendances détectées, double-cliquez sur Microsoft .NET Framework, puis dans le volet Propriétés, assurez-vous que la valeur affectée à Version est .NET Framework 3.5.

  6. Pour chacun des assemblys suivants sous Dépendances détectées, cliquez avec le bouton droit sur l'assembly, puis cliquez sur Exclure :

    • Microsoft.Web.Administration.dll

    • Microsoft.WindowsAzure.ServiceRuntime.dll

    • msshrtmi.dll

    • mswacdmi.dll

Ajoutez à présent une action personnalisée afin d'installer le fichier programme de votre adaptateur.

  1. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur le projet d'installation, pointez sur Afficher, puis cliquez sur Actions personnalisées.

  2. Dans l'Éditeur des actions personnalisées, cliquez avec le bouton droit sur le nœud Actions personnalisées, puis sélectionnez Ajouter une action personnalisée.

  3. Double-cliquez sur Dossier d'application dans la zone de liste pour l'ouvrir, puis sélectionnez Ajouter une sortie.

  4. Dans la fenêtre Ajouter le groupe de sorties du projet, sélectionnez Sortie principale, sélectionnez (Active) pour la configuration, puis cliquez sur OK.

Dans la mesure où Visual Studio injecte des assemblys 32 bits dans le fichier .msi, mais que Windows Azure nécessite des assemblys 64 bits, un script doit être exécuté pour corriger les assemblys incohérents. Vous pouvez utiliser un fichier JavaScript en tant qu'événement post-build pour corriger les assemblys.

  1. Enregistrez le code suivant dans un fichier nommé FixMSI.js dans le dossier racine du projet d'installation :

    
    // workaround for "BadImageFormatException" issue - see http://msdn.microsoft.com/fr-fr/library/kz0ke5xt.aspx
    
    var msiOpenDatabaseModeTransact = 1;
    var msiViewModifyInsert = 1
    var msiViewModifyUpdate = 2
    var msiViewModifyAssign = 3
    var msiViewModifyReplace = 4
    var msiViewModifyDelete = 6
    
    var filespec = WScript.Arguments(0);
    var frameworkpath = WScript.Arguments(1);
    var installer = WScript.CreateObject("WindowsInstaller.Installer");
    var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
    
    WScript.Echo("Updating file '" + filespec + "' to use a 64-bit custom action...");
    
    Update64Bit();
    
    database.Commit();
    database = null;
    installer = null;
    
    function Update64Bit() {
        var sql;
        var view;
        var record;
        sql = "SELECT * FROM Binary WHERE `Name`='InstallUtil'";
        view = database.OpenView(sql);
        view.Execute();
        record = view.Fetch();
        if (record != null) {
            var dataCol = 2;
            record.SetStream(dataCol, frameworkpath + "\\InstallUtilLib.dll");
            view.Modify(msiViewModifyUpdate, record);
        }
        record = null;
        view.close();
        view = null;
    }
    
  2. Dans l'Explorateur de solutions, cliquez sur le projet d'installation que vous avez créé précédemment, puis dans le volet Propriétés, ajoutez la commande suivante à la propriété PostBuildEvent :

    
    cd $(ProjectDir) 
    CScript //NoLogo FixMSI.js "$(BuiltOutputPath)" "%SystemRoot%\Microsoft.NET\Framework64\v2.0.50727"
    
  3. Dans l'Explorateur de solutions, cliquez avec le bouton droit sur le projet d'installation, puis cliquez sur Générer.

Pour permettre à l'adaptateur de communiquer avec Windows Azure, des paramètres doivent être définis dans le modèle de service cloud.

  1. Ouvrez le fichier ServiceDefinition.csdef correspondant au rôle machine virtuelle.

  2. Ajoutez les paramètres suivants à l'élément ConfigurationSettings :

    
    <Setting name="AdapterName.BlobPath" />
    <Setting name="AdapterName.AccountName" />
    <Setting name="AdapterName.AccountKey" />
    

    AdapterName est le nom du projet d'adaptateur.

  3. Ajoutez le paramètre suivant à l'élément LocalResources :

    
    <LocalStorage name="Data" />
    

    Pour plus d'informations sur les éléments qui peuvent être utilisés dans le modèle de service, consultez VirtualMachineRole Schema.

  4. Enregistrez le fichier.

  1. Ouvrez le fichier ServiceConfiguration.cscfg correspondant au rôle machine virtuelle.

  2. Ajoutez les paramètres de configuration suivants au fichier :

    
    <Setting name="AdapterName.BlobPath" value="http://StorageAccountName.blob.core.windows.net/ContainerName/{0}.vhd" />
    <Setting name="AdapterName.AccountName" value="StorageAccountName" />
    <Setting name="AdapterName.AccountKey" value="StorageAccountKey" />
    

    AdapterName est le nom du projet d'adaptateur que vous avez créé. StorageAccountName est le nom de votre compte de stockage. StorageAccountKey est la clé primaire de votre compte de stockage. ContainerName est le conteneur de stockage que vous avez créé précédemment. Pour plus d'informations sur la configuration du modèle de service, consultez Windows Azure Service Configuration Schema. Pour plus d'informations sur la définition et la configuration des paramètres, consultez Créer et déployer le modèle de service du rôle machine virtuelle.

  3. Enregistrez le fichier.

Votre adaptateur est maintenant prêt à être installé sur le disque dur virtuel que vous téléchargez sur Windows Azure.

Après la création du code, ainsi que la définition et la configuration des paramètres dans le modèle de service, vous pouvez installer l'adaptateur et déployer le package de modèle de service. Pour un rôle machine virtuelle, l'adaptateur est installé sur la machine virtuelle une fois que les composants d'intégration de Windows Azure ont été installés.

Pour permettre à l'adaptateur de fonctionner correctement, plusieurs fonctionnalités du système d'exploitation doivent être activées. Sur l'image que vous allez télécharger sur Windows Azure, exécutez la commande suivante :

DISM /Online /Enable-Feature /FeatureName:NetFx3 /FeatureName:IIS-WebServerRole /FeatureName:IIS-WebServer /FeatureName:IIS-CommonHttpFeatures /FeatureName:IIS-HttpErrors /FeatureName:IIS-ApplicationDevelopment /FeatureName:IIS-HealthAndDiagnostics /FeatureName:IIS-HttpLogging /FeatureName:IIS-RequestMonitor /FeatureName:IIS-Security /FeatureName:IIS-RequestFiltering /FeatureName:IIS-Performance /FeatureName:IIS-WebServerManagementTools /FeatureName:IIS-StaticContent /FeatureName:IIS-DefaultDocument /FeatureName:IIS-DirectoryBrowsing /FeatureName:IIS-HttpCompressionStatic /FeatureName:IIS-ManagementConsole

Pour installer l'adaptateur, accédez au dossier qui contient le fichier .msi, puis double-cliquez sur le fichier. Ce fichier se trouve dans le dossier Debug du projet d'installation que vous avez créé précédemment.

Voir aussi

Ajouts de la communauté

Afficher: