Pulumiを試してみた

とある勉強会でPulumiの事を知ったので公式に沿って試してみました！
チュートリアルをただなぞっただけなので、深い内容ではありませんのでご容赦ください！

https://www.pulumi.com/

## 環境のセットアップ
Pulumiは色々な言語対応してますが、今回はPythonでやろうと思います。
筆者はVsCodeとDevContainerでPython実行環境を作っておきました。
※DevContainerについては省略します。

https://code.visualstudio.com/docs/devcontainers/containers

まずはPulumiをセットアップします。
```bash:bash
curl -fsSL https://get.pulumi.com | sh
```

今回はAzureのリソースを作っていきますので、```az login```でAzureへログインまで済ませます。
Azure CLIが未インストールの場合、Ubuntuへのインストールは下記の手順でおこないます。

https://learn.microsoft.com/ja-jp/cli/azure/install-azure-cli-linux?pivots=apt

① インストール プロセスに必要なパッケージを取得します。
```bash:bash
sudo apt-get update
sudo apt-get install ca-certificates curl apt-transport-https lsb-release gnupg
```
② Microsoft の署名キーをダウンロードしてインストールします。
```bash:bash
sudo mkdir -p /etc/apt/keyrings
curl -sLS https://packages.microsoft.com/keys/microsoft.asc |
    gpg --dearmor |
    sudo tee /etc/apt/keyrings/microsoft.gpg > /dev/null
sudo chmod go+r /etc/apt/keyrings/microsoft.gpg
```

③ Azure CLI ソフトウェア リポジトリを追加します。
```bash:bash
AZ_REPO=$(lsb_release -cs)
echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" |
    sudo tee /etc/apt/sources.list.d/azure-cli.list
```

④ リポジトリ情報を更新し、azure-cli パッケージをインストールします。
```bash:bash
sudo apt-get update
sudo apt-get install azure-cli
```


## Pulumiプロジェクトの作成
それでは早速プロジェクトを作成してみましょう。

```bash:bash
mkdir quickstart && cd quickstart && pulumi new azure-python
pulumi new azure-python
```

すると色々な項目が出てくるので答えていきましょう。
まずはログイン。
```
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 
```

続けて設問項目
```
#このコマンドは、新しいPulumiプロジェクトを作成する手順を説明します。
This command will walk you through creating a new Pulumi project.

#値を入力するか、空白にして（デフォルト）を受け入れ、<ENTER>を押します。
終了するには、いつでも^Cを押してください。
Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.

#プロジェクト名
project name: (quickstart) 
#プロジェクト内容
project description: (A minimal Azure Native Python Pulumi program) 

#ご希望のスタック名を入力してください。
#スタック名とはブランチ名みたいなものっぽい。
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) 

#Azure プロジェクトの場合、Azureのリージョンを指定するよう求められます。
#今回はjapaneastと入力
azure-native:location: The Azure location to use: (WestUS2) japaneast
```
ちなみに、選択できるリージョンを確認する場合は…
```bash:bash
az account list-locations --output table
```
設定を変更する場合は…
```
pulumi config set azure-native:location eastus #eastusへ変更
```
との事です！
そんなこんなで下記の表示が出ればセットアップ完了！
```
Your new project is ready to go! 

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

## プロジェクトの内容を確認してデプロイ
プロジェクトの配下には、いくつかファイルが出来上がってます。
- ```Pulumi.yaml``` プロジェクトを定義します。
- ```Pulumi.dev.yaml``` 初期化したスタックの構成値が含まれています。
- ```main.py``` スタック リソースを定義する Pulumi プログラムです。

```__main__.py```を確認してみます。

```python:python
"""An Azure RM Python Pulumi program"""

import pulumi
from pulumi_azure_native import storage
from pulumi_azure_native import resources

# Create an Azure Resource Group
resource_group = resources.ResourceGroup("resource_group")

# Create an Azure resource (Storage Account)
account = storage.StorageAccount(
    "sa",
    resource_group_name=resource_group.name,
    sku=storage.SkuArgs(
        name=storage.SkuName.STANDARD_LRS,
    ),
    kind=storage.Kind.STORAGE_V2,
)

# Export the primary key of the Storage Account
primary_key = (
    pulumi.Output.all(resource_group.name, account.name)
    .apply(
        lambda args: storage.list_storage_account_keys(
            resource_group_name=args[0], account_name=args[1]
        )
    )
    .apply(lambda accountKeys: accountKeys.keys[0].value)
)

pulumi.export("primary_storage_key", primary_key)

```
デフォルトで用意されたのは、Azure リソース グループとストレージ アカウントを作成し、ストレージ アカウントの主キーをエクスポートする。といったプログラムのようです。
わーい！わかりやすーい！
リソースグループのリージョンは```Pulumi.dev.yaml``` に記載の場所との事。
```yaml:yaml
config:
  azure-native:location: japaneast #ここ
```

それでは早速デプロイしてみます。
```bash:bash
pulumi up
```

デプロイして良いか聞かかれるのでyesを選択します。
ちなみに、detailsを選択すると変更内容の差分が表示されます。
```
Do you want to perform this update?
> yes
  no
  details
```

完了したようです。

```
     Type                                     Name            Status              
 +   pulumi:pulumi:Stack                      quickstart-dev  created (32s)       
 +   ├─ azure-native:resources:ResourceGroup  resource_group  created (0.82s)     
 +   └─ azure-native:storage:StorageAccount   sa              created (25s)       
 ```

Azureのポータル画面でみると…、おおちゃんとできてる。
![done-img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821082/bf64bf8a-6cf9-dabd-ff52-379b148fa4cb.png)

Pulumiのポータルでも諸々確認できるので良いですね！
Outputsにストレージアカウントのキーも表示されてます！
![pulumi-img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821082/0ac813b7-9d76-b67a-1198-61c998cdd067.png)

## 作成したストレージにhtmlファイルを配置してみる
それでは、作成したストレージにhtmlファイルを追加するように変更します。
① 適当な```index.html```を作ります。
② ```__main__.py```を変更します。

```python:python
import pulumi
from pulumi_azure_native import storage
from pulumi_azure_native import resources

resource_group = resources.ResourceGroup("resource_group")

account = storage.StorageAccount(
    "sa",
    resource_group_name=resource_group.name,
    sku=storage.SkuArgs(
        name=storage.SkuName.STANDARD_LRS,
    ),
    kind=storage.Kind.STORAGE_V2,
)

# 追記箇所 - 静的ウェブサイトへの対応を可能に
static_website = storage.StorageAccountStaticWebsite("staticWebsite",
    account_name=account.name,
    resource_group_name=resource_group.name,
    index_document="index.html")


# 追記箇所 - ファイルのアップロード
index_html = storage.Blob("index.html",
    resource_group_name=resource_group.name,
    account_name=account.name,
    container_name=static_website.container_name,
    source=pulumi.FileAsset("index.html"),
    content_type="text/html")

primary_key = (
    pulumi.Output.all(resource_group.name, account.name)
    .apply(
        lambda args: storage.list_storage_account_keys(
            resource_group_name=args[0], account_name=args[1]
        )
    )
    .apply(lambda accountKeys: accountKeys.keys[0].value)
)

pulumi.export("primary_storage_key", primary_key)

# 追記箇所 - Webサイトへのエンドポイントを出力
pulumi.export("staticEndpoint", account.primary_endpoints.web)

```
それでは、再度実行してみましょう。
```
pulumi up
```
反映したようです。
変更差分をポータルでも確認できるのが嬉しいですね！
![diff-img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821082/09b39519-f30b-9415-89d2-4385081d6007.png)

ちゃんとindex.htmlの内容も確認できました。
![upload-img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821082/66aa1589-9710-eb9d-8ab8-519090d6b372.png)

最後に作成したリソースを削除しておきます。
```bash:bash
pulumi destroy
```
スタックも消去する場合は
```bash:bash
pulumi stack rm <stack-name>
```

## 感想
いやー面白いですねPulumi！
普段、AzureのリソースはArmやBicepで作成するのですがやっぱり慣れ親しんだ言語で書けるとテンションあがります！
比較対象としてTerraformが有名ですが、好きな言語で書けるというのは大きいなーと思いました。Pulumiをまだ深く触っていないので、残念ポイントはあまり分かっていませんが…各ベンダーの変更要素にどれだけ早く対応してくれるかが肝になってきそうです！
これから色々試していこうと思います！

## 参考元

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