好きなプログラミング言語で IaC する Pulumi (プルミ) で Azure リソース作成を試してみた

IaC と言えば Terraform が有名だと思います。Terraform は HCL (HashiCorp Configuration Language) という、JSON に似た独自の構文で記述する必要があります。今回試してみた Pulumi は、Pulumi SDK を使って好きなプログラミング言語で記述する事ができます。ただし SDK が対応していない最新の Azure リソースは待つ必要があるのかもしれません。また Pulumi を使ってみた感想としては、プログラミング言語で IaC を実現する AWS CDK と Terraform Cloud の実行履歴管理の両方が備わっている点が良かったです。

## Pulumi の Get Started を C# やってみる

https://www.pulumi.com/docs/clouds/azure/get-started/

```bash:bash
$ brew install pulumi/tap/pulumi

$ pulumi version

$ mkdir quickstart

$ cd quickstart

$ pulumi new azure-csharp
```

下記のメッセージが表示され Enter キーを押すと Pulumi のサインイン画面が表示されたので GitHub アカウントを連携しました。

```txt
Manage your Pulumi stacks by logging in.
Run `pulumi login --help` for alternative login options.
Enter your access token from https://app.pulumi.com/account/tokens
    or hit <ENTER> to log in using your browser                   :  
We've launched your web browser to complete the login process.

Waiting for login to complete...


  Welcome to Pulumi!

  Pulumi helps you create, deploy, and manage infrastructure on any cloud using
  your favorite language. You can get started today with Pulumi at:

      https://www.pulumi.com/docs/get-started/

  Tip: Resources you create with Pulumi are given unique names (a randomly
  generated suffix) by default. To learn more about auto-naming or customizing resource
  names see https://www.pulumi.com/docs/intro/concepts/resources/#autonaming.


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.
```

残りの質問はデフォルト値のまま Enter キーのみで、最後のロケーションだけ `japaneast` を入力しました。

```txt
project name (quickstart):  
project description (A minimal Azure Native C# Pulumi program):  
Created project 'quickstart'

Please enter your desired stack name.
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
stack name (dev):  
Created stack 'dev'

azure-native:location: The Azure location to use (WestUS2): japaneast 
Saved config

Installing dependencies...

MSBuild のバージョン 17.8.3+195e7f5a3 (.NET)
  復元対象のプロジェクトを決定しています...
  /Users/minoru/work/test/quickstart/quickstart.csproj を復元しました (8.24 sec)。
  quickstart -> /Users/minoru/work/test/quickstart/bin/Debug/net6.0/quickstart.dll

ビルドに成功しました。
    0 個の警告
    0 エラー

経過時間 00:00:10.07
Finished installing dependencies

Your new project is ready to go! ✨

To perform an initial deployment, run `pulumi up`
```

## ローカルに作成された Pulumi ファイルの構成

```bash:bash
$ tree

.
├── Program.cs
├── Pulumi.dev.yaml
├── Pulumi.yaml
├── bin
│   └── Debug
│       └── net6.0
│           ├── Ben.Demystifier.dll
│           ├── Google.Protobuf.dll
│           ├── Grpc.AspNetCore.Server.Reflection.dll
│           ├── Grpc.AspNetCore.Server.dll
│           ├── Grpc.Core.Api.dll
│           ├── Grpc.Net.Client.dll
│           ├── Grpc.Net.Common.dll
│           ├── Grpc.Reflection.dll
│           ├── OneOf.dll
│           ├── Pulumi.AzureNative.dll
│           ├── Pulumi.dll
│           ├── Semver.dll
│           ├── Serilog.Extensions.Logging.dll
│           ├── Serilog.Sinks.Console.dll
│           ├── Serilog.dll
│           ├── quickstart
│           ├── quickstart.deps.json
│           ├── quickstart.dll
│           ├── quickstart.pdb
│           └── quickstart.runtimeconfig.json
├── obj
│   ├── Debug
│   │   └── net6.0
│   │       ├── apphost
│   │       ├── quickstart.AssemblyInfo.cs
│   │       ├── quickstart.AssemblyInfoInputs.cache
│   │       ├── quickstart.GeneratedMSBuildEditorConfig.editorconfig
│   │       ├── quickstart.assets.cache
│   │       ├── quickstart.csproj.AssemblyReference.cache
│   │       ├── quickstart.csproj.CopyComplete
│   │       ├── quickstart.csproj.CoreCompileInputs.cache
│   │       ├── quickstart.csproj.FileListAbsolute.txt
│   │       ├── quickstart.dll
│   │       ├── quickstart.genruntimeconfig.cache
│   │       ├── quickstart.pdb
│   │       ├── ref
│   │       │   └── quickstart.dll
│   │       └── refint
│   │           └── quickstart.dll
│   ├── project.assets.json
│   ├── project.nuget.cache
│   ├── quickstart.csproj.nuget.dgspec.json
│   ├── quickstart.csproj.nuget.g.props
│   └── quickstart.csproj.nuget.g.targets
└── quickstart.csproj

9 directories, 43 files
```

## Pulumi の Azure リソースを作成するコード

自動生成されたコードを見ると、リソースグループとストレージアカウントを作成してくれるようです。また、ストレージアカウントキーもしています。

```csharp:Program.cs
using Pulumi;
using Pulumi.AzureNative.Resources;
using Pulumi.AzureNative.Storage;
using Pulumi.AzureNative.Storage.Inputs;
using System.Collections.Generic;

return await Pulumi.Deployment.RunAsync(() =>
{
    // Create an Azure Resource Group
    var resourceGroup = new ResourceGroup("resourceGroup");

    // Create an Azure resource (Storage Account)
    var storageAccount = new StorageAccount("sa", new StorageAccountArgs
    {
        ResourceGroupName = resourceGroup.Name,
        Sku = new SkuArgs
        {
            Name = SkuName.Standard_LRS
        },
        Kind = Kind.StorageV2
    });

    var storageAccountKeys = ListStorageAccountKeys.Invoke(new ListStorageAccountKeysInvokeArgs
    {
        ResourceGroupName = resourceGroup.Name,
        AccountName = storageAccount.Name
    });

    var primaryStorageKey = storageAccountKeys.Apply(accountKeys =>
    {
        var firstKey = accountKeys.Keys[0].Value;
        return Output.CreateSecret(firstKey);
    });

    // Export the primary key of the Storage Account
    return new Dictionary<string, object?>
    {
        ["primaryStorageKey"] = primaryStorageKey
    };
});
```

## Pulumi で Azure リソースを作成

途中 `yes` を選択して処理を進めます。

```bash:bash
$ pulumi up

Previewing update (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/mnrst/quickstart/dev/previews/da08073d-3bbd-49bf-b77d-2ea9858cad68

     Type                 Name            Plan     Info
     pulumi:pulumi:Stack  quickstart-dev           'dotnet build -nologo .' completed successfully
Downloading plugin: 29.84 MiB / 29.84 MiB [=========================] 100.00% 1s
     Type                                     Name            Plan       
 +   pulumi:pulumi:Stack                      quickstart-dev  create     
 +   ├─ azure-native:resources:ResourceGroup  resourceGroup   create     
 +   └─ azure-native:storage:StorageAccount   sa              create     

Outputs:
    primaryStorageKey: output<string>

Resources:
    + 3 to create

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

View in Browser (Ctrl+O): https://app.pulumi.com/mnrst/quickstart/dev/updates/1

     Type                                     Name            Status              
 +   pulumi:pulumi:Stack                      quickstart-dev  created (29s)       
 +   ├─ azure-native:resources:ResourceGroup  resourceGroup   created (0.56s)     
 +   └─ azure-native:storage:StorageAccount   sa              created (25s)       

Outputs:
    primaryStorageKey: [secret]

Resources:
    + 3 created

Duration: 31s
```

## 作成された Azure リソース

リソース名にランダムな英数が自動的に付加されるようです。

![pulumi-azure-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675885/cd843bb4-5d68-4e88-bb48-baa5e85d2cd1.png)

## 作成した Azure リソースを削除

途中 `yes` を選択して処理を進めます。

```bash:bash
$ pulumi destroy

Previewing destroy (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/mnrst/quickstart/dev/previews/7ebdac60-f4b1-4259-bb01-2a5020ea2103

     Type                                     Name            Plan       
 -   pulumi:pulumi:Stack                      quickstart-dev  delete     
 -   ├─ azure-native:storage:StorageAccount   sa              delete     
 -   └─ azure-native:resources:ResourceGroup  resourceGroup   delete     

Outputs:
  - primaryStorageKey: [secret]

Resources:
    - 3 to delete

Do you want to perform this destroy? yes
Destroying (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/mnrst/quickstart/dev/updates/3

     Type                                     Name            Status              
 -   pulumi:pulumi:Stack                      quickstart-dev  deleted (0.39s)     
 -   ├─ azure-native:storage:StorageAccount   sa              deleted (4s)        
 -   └─ azure-native:resources:ResourceGroup  resourceGroup   deleted (15s)       

Outputs:
  - primaryStorageKey: [secret]

Resources:
    - 3 deleted

Duration: 22s

The resources in the stack have been deleted, but the history and configuration associated with the stack are still maintained. 
If you want to remove the stack completely, run `pulumi stack rm dev`.
```

## pulumi.com で IaC の実行履歴を確認

追加、変更なし、削除のリソース数が一覧で確認できます。

![pulumi-azure-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675885/7e536c56-e615-5624-e44c-466460348ca8.png)

## 参考

https://www.pulumi.com/docs/languages-sdks/

https://azure.microsoft.com/en-us/updates/public-preview-support-for-pulumi-in-azure-deployment-environments/

https://devblogs.microsoft.com/develop-from-the-cloud/customized-project-specific-templates-in-azure-deployment-environments/