Exercice - Créer un pool de nœuds de calcul pour exécuter nos travaux

Effectué

Pour exécuter un travail Batch, nous devons ajouter un pool à notre compte Batch. Un pool contient des nœuds de calcul, c’est-à-dire les moteurs qui exécutent votre travail Batch. Vous spécifiez le nombre, la taille et le système d’exploitation des nœuds au moment de la création. Dans cet exercice, vous allez modifier l’application console que vous avez créée dans l’exercice précédent pour ajouter un pool à votre compte Batch.

Votre entreprise souhaite contrôler les coûts de l’application et vous demande d’utiliser un nombre fixe de nœuds.

Important

Vous avez besoin de votre propre abonnement Azure pour exécuter cet exercice et des frais pourraient vous être facturés. Si vous n’avez pas d’abonnement Azure, créez un compte gratuit avant de commencer.

Ajouter des paramètres à votre nouveau pool

  1. Dans Cloud Shell, modifiez le fichier Program.cs dans l’éditeur :

    code Program.cs
    
  2. Ajoutez les propriétés suivantes à la classe Program dans Program.cs :

    private const string PoolId = "WinFFmpegPool";
    private const int DedicatedNodeCount = 0;
    private const int LowPriorityNodeCount = 3;
    private const string PoolVMSize = "STANDARD_D2_v2";
    private const string appPackageId = "ffmpeg";
    private const string appPackageVersion = "3.4";
    

    Les paramètres précédents sont utilisés dans le code pour créer le pool. Notre observation de chaque variable nous permet de les expliquer de la manière suivante :

    • PoolId : Nom que notre code utilise pour référencer le pool dans d’autres appels du client par lot.
    • LowPriorityNodeCount : Vous allez créer un pool avec trois machines virtuelles basse priorité.
    • PoolVMSize : Les machines virtuelles sont STANDARD_A1_v2, ce qui donne aux nœuds 1 processeur, 2 Go de RAM et 10 Go de stockage SSD.
    • appPackageId : Nom du package d’application à utiliser sur les nœuds que vous créez.
    • appPackageVersion : Version de l’application à utiliser sur les nœuds que vous créez.

Mettez à jour la méthode Main() pour prendre en charge les appels asynchrones

Nous allons effectuer plusieurs appels asynchrones aux services cloud. La première chose à faire est donc de rendre Main asynchrone. Avec C# .NET versions 7.1 et ultérieures, les méthodes Main asynchrones dans les applications console sont prises en charge.

  1. Changez l’application console pour autoriser les appels de méthodes asynchrones. Pour cela, ajoutez d’abord la bibliothèque System.Threading.Tasks.

    using System.Threading.Tasks;
    using System.Collections.Generic; // Also add generics to allow the app to use Lists
    
  2. Ensuite, mettez à jour la signature de la méthode Main comme ceci :

    static async Task Main(string[] args)
    

Créer un pool

  1. Ajoutez la nouvelle méthode suivante à la classe Program pour créer un pool Batch. La méthode  :

    • Crée un objet de référence d’image pour stocker les paramètres des nœuds à ajouter au pool.
    • Utilise la référence d’image pour créer un objet VirtualMachineConfiguration.
    • Crée un pool indépendant en utilisant les propriétés déclarées précédemment et le VirtualMachineConfiguration.
    • Ajoute une référence de package d’application au pool.
    • Crée le pool sur Azure.
    • Accepte deux paramètres, batchClient et PoolId.
      private static async Task CreateBatchPoolAsync(BatchClient batchClient, string poolId)
        {
            CloudPool pool = null;
            Console.WriteLine("Creating pool [{0}]...", poolId);
    
            // Create an image reference object to store the settings for the nodes to be added to the pool
            ImageReference imageReference = new ImageReference(
                    publisher: "MicrosoftWindowsServer",
                    offer: "WindowsServer",
                    sku: "2012-R2-Datacenter-smalldisk",
                    version: "latest");
    
            // Use the image reference to create a VirtualMachineConfiguration object
            VirtualMachineConfiguration virtualMachineConfiguration =
            new VirtualMachineConfiguration(
                imageReference: imageReference,
                nodeAgentSkuId: "batch.node.windows amd64");
    
            try
            {
                // Create an unbound pool. No pool is actually created in the Batch service until we call
                // CloudPool.CommitAsync(). This CloudPool instance is therefore considered "unbound," and we can
                // modify its properties.
                pool = batchClient.PoolOperations.CreatePool(
                    poolId: poolId,
                    targetDedicatedComputeNodes: DedicatedNodeCount,
                    targetLowPriorityComputeNodes: LowPriorityNodeCount,
                    virtualMachineSize: PoolVMSize,
                    virtualMachineConfiguration: virtualMachineConfiguration);  
    
                // Specify the application and version to install on the compute nodes
                pool.ApplicationPackageReferences = new List<ApplicationPackageReference>
                {
                    new ApplicationPackageReference
                    {
                    ApplicationId = appPackageId,
                    Version = appPackageVersion
                    }
                };
    
                // Create the pool
                await pool.CommitAsync();
            }
            catch (BatchException be)
            {
                // Accept the specific error code PoolExists as that is expected if the pool already exists
                if (be.RequestInformation?.BatchError?.Code == BatchErrorCodeStrings.PoolExists)
                {
                    Console.WriteLine("The pool [{0}] already existed when we tried to create it", poolId);
                }
                else
                {
                    throw; // Any other exception is unexpected
                }
            }
        }  
    
  2. Appelez CreateBatchPoolAsync à partir de notre méthode Main. La méthode Main doit désormais se présenter comme suit :

    static async Task Main(string[] args)
    {
        // Read the environment variables to allow the app to connect to the Azure Batch account
        batchAccountUrl = Environment.GetEnvironmentVariable(envVarBatchURI);
        batchAccountName = Environment.GetEnvironmentVariable(envVarBatchName);
        batchAccountKey = Environment.GetEnvironmentVariable(envVarKey);
    
        // Show the user the batch the app is attaching to
        Console.WriteLine("URL: {0}, Name: {1}, Key: {2}", batchAccountUrl, batchAccountName, batchAccountKey);
    
        // The batch client requires a BatchSharedKeyCredentials object to open a connection
        var sharedKeyCredentials = new BatchSharedKeyCredentials(batchAccountUrl, batchAccountName, batchAccountKey);
        var batchClient = BatchClient.Open(sharedKeyCredentials);
    
        // Create the Batch pool, which contains the compute nodes that execute tasks.
        await CreateBatchPoolAsync(batchClient, PoolId);
    }
    

Test de l'application

  1. Dans l’éditeur de code, cliquez avec le bouton droit et sélectionnez Enregistrer, puis cliquez avec le bouton droit et sélectionnez Quitter.

  2. Dans Cloud Shell, compilez et exécutez l’application avec la commande suivante :

    dotnet run
    
  3. L’exécution de l’application prend quelques minutes, puis vous devez obtenir la sortie suivante :

    URL: <your batch account url, Name: <your batch name>, Key: <your batch key>
    Creating pool [WinFFmpegPool]...
    

N’oubliez pas que chaque nœud est une machine virtuelle exécutant un serveur Windows 2012 avec un seul processeur et 2 Go de RAM. Il faut du temps à Batch pour transférer ces images de machine virtuelle Windows à partir de la Place de marché des machines virtuelles Azure, créer l’infrastructure et le réseau de la machine virtuelle, et enfin démarrer chaque nœud. Pour la plupart des solutions Batch, il s’agit de la partie la plus longue. Un workflow Batch type ne nettoie ni le pool ni ses nœuds.