Utilisation de Pulumi pour gérer votre IaC Azure

Cela fait un moment que je gère l'IaC (Infrastructure as Code) de mes applications dans Azure avec des templates ARM.

Cela fonctionne bien, mais dès que l'on commence à avoir des templates compliqués on se retrouve à devoir découper un gros fichier ARM json en plusieurs plus petits, et le développement et la validation commencent à devenir complexe.

J'ai essayé d'utiliser Terraform qui est très populaire mais je n'ai pas trop accroché car je n'étais pas fan du DSL pour la description de son IaC.

J'ai ensuite essayé Pulumi pour voir quelle serait l'expérience au moment du développement.

Pour commencer, il est nécessaire d'installer Pulumi sur votre machine (Windows), pour Linux ou macOS c'est par ici: https://pulumi.io/quickstart/install.html.

Vous devez ouvrir un cmd.exe et lancer la commande suivante:

@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://get.pulumi.com/install.ps1'))" && SET "PATH=%PATH%;%USERPROFILE%\.pulumi\bin"

Une fois que cela est fait, vous pouvez faire un petit test voir que tout fonctionne bien avec cette commande:

pulumi version

Et si tout se passe bien vous devez obtenir la version installée:

v0.16.11

Pulumi est installé, maintenant il faut installer Azure CLI.

Vous avez la base, maintenant nous allons pouvoir commencer à travailler. Pour que Pulumi fonctionne, il faut que l'état de votre IaC soit stocké à un endroit:

  • Chez Pulumi
  • Sur votre système de fichiers

Pour faire simple nous allons faire ça en local, mais je vous recommande de créer votre compte chez eux. Le service de stockage est gratuit.

Pour vous connecter en local:

pulumi login --local

Si la commande se passe bien voici le retour:

Logged into JU-LAPTOP as JU-LAPTOP\Julien (file://~)

Le stockage en local est dans ce répertoire par défaut: %USERPROFILE%\.pulumi

Ensuite nous allons nous connecter à Azure, là encore, ce n'est pas l'idéale, je vous conseille de créer un Service Principal

az login

Allez ensuite dans votre répertoire de travail (dans mon cas C:\dev\AzureTest).

Pulumi a deux concepts importants, Project et Stack.

Le concept de Project sert à définir comment notre IaC va être définie (python, nodejs) et quelques autres attributs: https://pulumi.io/reference/project.html.

Le concept de Stack sert à définir une configuration particulière pour un environnement (ie: Dev / Production).

Nous allons donc créer notre Project:

pulumi new
Please choose a template:                                                    
> aws-go                   A minimal AWS Go Pulumi program                   
  aws-javascript           A minimal AWS JavaScript Pulumi program           
  aws-python               A minimal AWS Python Pulumi program               
  aws-typescript           A minimal AWS TypeScript Pulumi program           
  azure-go                 A minimal Azure Go Pulumi program                 
  azure-javascript         A minimal Azure JavaScript Pulumi program         
  azure-python             A minimal Azure Python Pulumi program             
  azure-typescript         A minimal Azure TypeScript Pulumi program         
  gcp-go                   A minimal Google Cloud Go Pulumi program          
  gcp-javascript           A minimal Google Cloud JavaScript Pulumi program  
  gcp-python               A minimal Google Cloud Python Pulumi program      
  gcp-typescript           A minimal Google Cloud TypeScript Pulumi program  
  go                       A minimal Go Pulumi program                       
  hello-aws-javascript     A simple AWS serverless JavaScript Pulumi program 
  javascript               A minimal JavaScript Pulumi program               
  kubernetes-javascript    A minimal Kubernetes JavaScript Pulumi program    
  kubernetes-typescript    A minimal Kubernetes TypeScript Pulumi program    
  openstack-go             A minimal OpenStack Go Pulumi program             
  openstack-javascript     A minimal OpenStack JavaScript Pulumi program     
  openstack-python         A minimal OpenStack Python Pulumi program         
  openstack-typescript     A minimal OpenStack TypeScript Pulumi program     
  python                   A minimal Python Pulumi program                   
  typescript               A minimal TypeScript Pulumi program               

On va prendre azure-typescript, prendre les valeurs proposées par défaut et à la fin on choisira no à la question Do you want to perform this update?:

Please choose a template: azure-typescript         A minimal Azure TypeScript Pulumi program
This command will walk you through creating a new Pulumi project.

Enter a value or leave blank to accept the default, and press <ENTER>.
Press ^C at any time to quit.
project name: (AzureTest)
project description: (A minimal Azure TypeScript Pulumi program)
Created project 'AzureTest'.
stack name: (AzureTest-dev)
Created stack 'AzureTest-dev'
azure:environment: The Azure environment to use (`public`, `usgovernment`, `german`, `china`): (public)
Installing dependencies...
Your new project is configured and ready to go!
Previewing update (AzureTest-dev):

     Type                         Name                     Plan
 +   pulumi:pulumi:Stack          AzureTest-AzureTest-dev  create
 +   ├─ azure:core:ResourceGroup  resourceGroup            create
 +   └─ azure:storage:Account     storage                  create

Resources:
    + 3 to create

Do you want to perform this update? no

La preview nous informe des actions qui vont être effectuées à savoir:

  • Création de la stack AzureTest-dev
  • Création d'un resource group
  • Création d'un storage

Nous sommes presque prêts, il nous faut juste le nom des régions Azure pour configure notre stack:

az account list-locations --output=table
DisplayName          Latitude    Longitude    Name
-------------------  ----------  -----------  ------------------
East Asia            22.267      114.188      eastasia
Southeast Asia       1.283       103.833      southeastasia
Central US           41.5908     -93.6208     centralus
East US              37.3719     -79.8164     eastus
East US 2            36.6681     -78.3889     eastus2
West US              37.783      -122.417     westus
North Central US     41.8819     -87.6278     northcentralus
South Central US     29.4167     -98.5        southcentralus
North Europe         53.3478     -6.2597      northeurope
West Europe          52.3667     4.9          westeurope
Japan West           34.6939     135.5022     japanwest
Japan East           35.68       139.77       japaneast
Brazil South         -23.55      -46.633      brazilsouth
Australia East       -33.86      151.2094     australiaeast
Australia Southeast  -37.8136    144.9631     australiasoutheast
South India          12.9822     80.1636      southindia
Central India        18.5822     73.9197      centralindia
West India           19.088      72.868       westindia
Canada Central       43.653      -79.383      canadacentral
Canada East          46.817      -71.217      canadaeast
UK South             50.941      -0.799       uksouth
UK West              53.427      -3.084       ukwest
West Central US      40.890      -110.234     westcentralus
West US 2            47.233      -119.852     westus2
Korea Central        37.5665     126.9780     koreacentral
Korea South          35.1796     129.0756     koreasouth
France Central       46.3772     2.3730       francecentral
France South         43.8345     2.1972       francesouth
Australia Central    -35.3075    149.1244     australiacentral
Australia Central 2  -35.3075    149.1244     australiacentral2

Nous allons créer avec Pulumi, un resource group qui contiendra:

  • Un App Service Plan
  • Application Insights
  • Un App Service configuré avec Application Insights

Vous allez modifier le fichier index.ts et mettre ce contenu dedans:

import * as pulumi from "@pulumi/pulumi";
import * as azure from "@pulumi/azure";

// Création du Resource Group
const resourceGroup = new azure.core.ResourceGroup("azuretest", {
    name: "azuretest",
    location: "westeurope",
});

const resourceGroupArgs = {
    resourceGroupName: resourceGroup.name,
    location: resourceGroup.location,
};

// Création du App Service Plan
const appServicePlan = new azure.appservice.Plan(`azuretest-asp`, {
    ...resourceGroupArgs,
    name: 'azuretest-asp',
    kind: "App",
    sku: {
        tier: "Free",
        size: "F1",
    },
});

// Création d'Application Insights
const appInsights = new azure.appinsights.Insights(`azuretest-ai`, {
    ...resourceGroupArgs,
    name: `azuretest-ai`,
    applicationType: "Web"
});

// Création du App Service
const app = new azure.appservice.AppService(`azuretest-web`, {
    ...resourceGroupArgs,
    name: `azuretest-web`,
    appServicePlanId: appServicePlan.id,
    appSettings: {
        "APPINSIGHTS_INSTRUMENTATIONKEY": appInsights.instrumentationKey
    }
});

// Affiche l'URL de notre site web
export const webSiteUrl = app.defaultSiteHostname.apply(n => `https://${n}`);

On demande à Pulumi de mettre à jour notre IaC dans Azure:

pulumi up

La commande nous affiche les actions qu'elle va effectuer et cette fois nous allons choisir yes à la question Do you want to perform this update?:

Previewing update (AzureTest-dev):

     Type                            Name                     Plan
 +   pulumi:pulumi:Stack             AzureTest-AzureTest-dev  create
 +   ├─ azure:core:ResourceGroup     azuretest                create
 +   ├─ azure:appinsights:Insights   azuretest-ai             create
 +   ├─ azure:appservice:Plan        azuretest-asp            create
 +   └─ azure:appservice:AppService  azuretest-web            create

Resources:
    + 5 to create

Do you want to perform this update? yes
Updating (AzureTest-dev):

     Type                            Name                     Status
 +   pulumi:pulumi:Stack             AzureTest-AzureTest-dev  created
 +   ├─ azure:core:ResourceGroup     azuretest                created
 +   ├─ azure:appservice:Plan        azuretest-asp            created
 +   ├─ azure:appinsights:Insights   azuretest-ai             created
 +   └─ azure:appservice:AppService  azuretest-web            created

Outputs:
    webSiteUrl: "https://azuretest-web.azurewebsites.net"

Resources:
    + 5 created

Duration: 38s

Permalink: file://C:\Users\Julien\.pulumi\stacks\AzureTest-dev.json

Et voilà, vous avez votre IaC totalement déployée. Il faut quand même avouer que c'est bien plus compact que le format json des templates ARM et c'est aussi plus agréable à lire!

Maintenant que vous avez vu comment démarrer, je vous conseille vraiment de créer votre compte chez Pulumi, mettre en place votre token d'accès et un Service Principal dans Azure. Vous serez fin prêt pour industrialiser vos déploiement!