Introduction

Je n’ai jamais eu le temps de jouer avec Bicep et j’étais coincé avec les modèles ARM. Suite à un article de blog, j’ai décidé de documenter une méthode alternative s’appuyant sur DSC et d’essayer Bicep en même temps : déployer une VM avec plusieurs disques, les formater et les attacher à la VM. Bien sûr, DSC peut être utilisé pour des choses plus puissantes, de l’installation du package choco à l’installation et à la gestion de SQL Server.

L’utilisation de DSC par rapport à du PowerShell seul est un débat sans fin. Chaque approche a ses pours et ses contres. Personnellement, j’ai été séduit par :

  • Le nombre de modules existants

  • L’idempotence de DSC

Les autres arguments sont :

Prérequis

CLI Bicep

L’outil de commande en ligne (CLI) Bicep existe en tant qu’extension d’Azure CLI ou en tant que CLI autonome. J’ai fait le choix d’utiliser l’extension Azure CLI. Pour installer cette extension, la commande est plutôt simple :

az bicep install

Groupes de ressources Azure

Les groupes de ressources sont nécessaires pour créer la VM par exemple. Habituellement, j’aurais un groupe de ressources "commun" pour le compte de stockage ou un VNET et un groupe de ressources pour la machine virtuelle, car mon compte de stockage est partagé entre mes ressources. Pour cet exemple, pour des raisons de simplicité, je n’utiliserai qu’un seul groupe de ressources. Pour le créer :

az group create --name my-rg --location francecentral

Compte de stockage Azure

Les scripts DSC doivent être disponibles pour la machine virtuelle. Je crée un compte de stockage pour stocker les scripts mais le garde privé pour des raisons de sécurité. Ainsi, les scripts ne sont pas accessibles sans authentification

Pour créer le compte de stockage, j’ai utilisé un fichier Bicep :

prerequisites/main.bicep
// cf. https://github.com/Azure/bicep/blob/main/docs/examples/101/storage-blob-container/main.bicep
param storageAccountName string
param containerName string = 'dsc'
param location string = resourceGroup().location

resource sa 'Microsoft.Storage/storageAccounts@2019-06-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
}

resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2019-06-01' = {
  name: '${sa.name}/default/${containerName}'
}

Ensuite, je déploie le modèle :

az deployment group create --resource-group my-rg --template-file prerequisites/main.bicep --parameters storageAccountName=mystorageaccount

PowerShell DSC

DSC permet de décrire une configuration à appliquer. Voici un exemple de configuration DSC qui :

  • Active le bureau à distance

  • Monte le disque de données

dsc/common.ps1
Configuration Common
{
    param
    (
        [Parameter()]
        [System.String[]]
        $NodeName = 'localhost'
    
    )
    Import-DscResource -Module xRemoteDesktopAdmin
    Import-DSCResource -ModuleName StorageDsc
    Import-DSCResource -ModuleName xPendingReboot
    
    Node $NodeName
    {
        LocalConfigurationManager {
            RebootNodeIfNeeded = $true
        }

        #region RDP
        xRemoteDesktopAdmin RemoteDesktopSettings {
            Ensure = 'Present'
        }
        #endregion

        xPendingReboot Reboot1 {
            Name = 'BeforeManageDisk'
        }

        #region Disk
        if (Get-CimInstance -ClassName Win32_CDROMDrive) {
            OpticalDiskDriveLetter SetFirstOpticalDiskDriveLetterToZ {
                DiskId      = 1
                DriveLetter = 'Z'
            }
        }

        WaitForDisk Disk2 {
            DiskId           = "2"
            RetryIntervalSec = 10
            RetryCount       = 3
        }

        Disk EVolume {
            DiskId      = "2"
            DriveLetter = 'E'
            FSLabel     = 'Data'
            DependsOn   = '[WaitForDisk]Disk2'
        }
        #endregion

    }
}

Une fois la configuration écrite, vous devez :

  1. Préparer un package

  2. Publier le package

Préparation du package

Vous devez installer toutes les dépendances/modules sur votre ordinateur. Dans mon cas :

install-module xRemoteDesktopAdmin
Install-Module StorageDsc
Install-Module xPendingReboot
L’installation des modules permettra également la complétion dans VSCode.

Vous pouvez créer un package à publier quelque part (compte de stockage, GitHub, etc.) avec la commande suivante, ou ignorer ceci et passer directement à l’étape suivante :

Publish-AzVMDscConfiguration .\common.ps1 -OutputArchivePath .\common.ps1.zip

Publication du package

Le module Az possède une cmdlet spécifique capable de créer le package et de le transférer directement dans un compte de stockage :

Publish-AzVMDscConfiguration .\common.ps1 -ResourceGroupName "my-rg" -StorageAccountName "mystorageaccount" -ContainerName "dsc" -verbose -force

VM et extension DSC

Une fois le package DSC prêt, nous pouvons déployer une VM. Dans mon exemple, je réutilise un VNET existant. Pour plus de commodité dans mes tests, j’ajouterai également une adresse IP publique, mais ce n’est bien sûr pas une bonne pratique.

Je vais me concentrer sur l’extension DSC à la fin du fichier Bicep. Tous les paramètres de l’extension sont décrits dans la documentation Microsoft.

resource stg 'Microsoft.Storage/storageAccounts@2019-06-01' existing = {
  name: storageAccountName
}

var _artifactsLocationSasToken = stg.listServiceSAS('2021-04-01', {
  canonicalizedResource: '/blob/${stg.name}/${containerName}'
  signedResource: 'c'
  signedProtocol: 'https'
  signedPermission: 'r'
  signedServices: 'b'
  signedExpiry: dateTimeAdd(baseTime, 'PT1H')
}).serviceSasToken (1)


resource dscExtension 'Microsoft.Compute/virtualMachines/extensions@2018-10-01' = {
  location: location
  parent: vm
  name: 'Microsoft.Powershell.DSC'
  properties: {
    publisher: 'Microsoft.Powershell'
    type: 'DSC'
    typeHandlerVersion: '2.77'
    autoUpgradeMinorVersion: true
    settings: {
      wmfVersion: 'latest'
      configuration: {
        url: '${stg.properties.primaryEndpoints.blob}${containerName}/common.ps1.zip' (2)
        script: 'common.ps1' (3)
        function: 'Common' (4)
      }
      configurationArguments: {}
    }
    protectedSettings: {
      configurationUrlSasToken: '?${_artifactsLocationSasToken}' (5)
    }
  }
}
1 Cette fonction, telle que décrite dans la doc permet d’obtenir un jeton SAS, en fonction de paramètres. Cependant, ce Token SAS ne contient pas le '?' comme paramètre de requête (query string).
2 URL construite à partir de l’URL du compte de stockage + le conteneur + l’archive générée précédemment. L’URL blob se termine par un '/', d’où la concaténation sans '/' supplémentaire.
3 Nom du script DSC.
4 Nom de la configuration.
5 Petite astuce pour obtenir un paramètre de requête (query string).

Le fichier complet main.bicep est disponible ici.

Je comprends qu’à l’heure actuelle, il n’y a pas de mécanisme intégré pour créer un fichier de paramètres et que les fichiers de paramètres sont simplement des fichiers de paramètres de modèle ARM, basé sur JSON. J’ai utilisé un script trouvé dans un bug GitHub pour préparer mes paramètres :

vm/main.parameters.json
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "adminUsername": {
            "value": "administrateur"
        },
        "adminPassword": {
            "value": "mysuperpassword"
        },
        "virtualNetworkName": {
            "value": "MyVNET"
        },
        "subnetName": {
            "value": "Subnet"
        },
        "storageAccountName": {
            "value": "mystorageaccount"
        },
        "vmName": {
            "value": "myvm"
        },
        "nicName": {
            "value": "nic-myvm"
        },
        "publicIpName": {
            "value": "pip-myvm"
        },
        "networkSecurityGroupName": {
            "value": "nsg-myvm"
        },
        "sizeOfEachDataDiskInGB": {
            "value": 128
        }
    }
}

Finalement, on déploie le template Bicep avec les paramètres :

az deployment group create --resource-group my-rg --template-file vm/main.bicep --parameters @vm/main.parameters.json

Conclusion

Voici un moyen simple d’obtenir une machine virtuelle avec un disque de données prêt à l’emploi.

Cet article était un bon moyen de tester Bicep et il est claire que Bicep est vraiment plus concis que les modèles ARM. Pour autant, est-ce mieux?

J’aime la création automatique du graphe de dépendance entre les ressources, comme dans Terraform. J’aime la façon de référencer les ressources existantes.

Je n’ai pas aimé la très longue liste de paramètres que je ne pouvais pas réduire dans VSCode. J’ai cependant eu quelques problèmes de déploiement et j’étais heureux de voir le modèle ARM généré (grâce à la commande build) et de voir ce qui ne fonctionnait pas bien avec mon fichier Bicep.

En tout cas, Microsoft a vraiment poussé vers Bicep et a des modèles prêts à l’emploi qui sont très utiles.

Avec cet exemple, je n’ai pas testé les modules qui sont clairement un super ajout au langage, proche de Terraform, quand on connait les modèles imbriqués avec ARM.

Alors, je vais me prendre au jeu et continuer à travailler avec Bicep avec Azure !