概要
Pulumiは Indrastracture as Code を実現するソフトウェア。 Azure Resource Manager(Template) や Terraform で出来ることと同じですが、一般的なプログラム言語(Node.js,JavaScript,TypeScript,Python,GO)で記述できるのが強みでしょうか、、、
今まで terraform を駆使してきましたが、Pulumi を見かけたのでクイックスタートをやってみました(初めてさわってみました)。
実行環境
macOS Sonoma 14.0
python 3.8.12
Azure CLI 2.53.0
事前準備
Azure へのログイン
## Azure Login
$ az login
## 対象のサブスクリプションの定義
$ az account set --subscription <サブスクリプション名>
Pulumi のインストール
homebrew から Pulumi をインストールします。詳しくはここを参照ください。
## インストール
$ brew install pulumi
==> Downloading https://ghcr.io/v2/homebrew/core/pulumi/manifests/3.89.0
################################################################################################################################### 100.0%
==> Fetching pulumi
==> Downloading https://ghcr.io/v2/homebrew/core/pulumi/blobs/sha256:d5dd04de88bddf5d350795218b2212ff29a4340632493498846bba9f7d96f94f
################################################################################################################################### 100.0%
==> Pouring pulumi--3.89.0.sonoma.bottle.tar.gz
==> Caveats
zsh completions have been installed to:
/usr/local/share/zsh/site-functions
==> Summary
🍺 /usr/local/Cellar/pulumi/3.89.0: 21 files, 370.1MB
==> Running `brew cleanup pulumi`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
## 確認
$ pulumi version
v3.89.0
ログイン
基本的に、Pulumiは状態管理などをPulumiが提供しているCloud上(SaaS)で行う。 が、今回はこのSaaS使わない事にしてローカルで状態管理を行うことに。
## 作業場所の定義
$ mkdir ~/MyDevelops/Pulumi/quickstart
$ cd ~/MyDevelops/Pulumi/quickstart
## ログイン
$ pulumi login "file://~/MyDevelops/Pulumi/quickstart"
Logged in to IsseinoMacBook-Pro.local as ituru (file://~/MyDevelops/Pulumi/quickstart)
Pulumi IaC
プロジェクトの作成
Azure の Get Startを読みながら進める
プロバイダはAzure、言語はPythonでプロジェクトを作成します。
## プロジェクト作成
$ pulumi new azure-python
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 (quickstart):
project description (A minimal Azure Native Python Pulumi program):
Created project 'quickstart'
stack name (dev):
Created stack 'dev'
Enter your passphrase to protect config/secrets: **************
Re-enter your passphrase to confirm: *************
azure-native:location: The Azure location to use (WestUS2): Japaneast
Saved config
Installing dependencies...
Creating virtual environment...
Finished creating virtual environment
Updating pip, setuptools, and wheel in virtual environment...
Requirement already satisfied: pip in /Users/ituru/MyDevelops/Pulumi/quickstart/venv/lib/python3.8/site-packages (21.1.1)
Collecting pip
Downloading pip-23.3.1-py3-none-any.whl (2.1 MB)
|████████████████████████████████| 2.1 MB 7.1 MB/s
Requirement already satisfied: setuptools in /Users/ituru/MyDevelops/Pulumi/quickstart/venv/lib/python3.8/site-packages (56.0.0)
Collecting setuptools
Downloading setuptools-68.2.2-py3-none-any.whl (807 kB)
|████████████████████████████████| 807 kB 7.7 MB/s
Collecting wheel
Downloading wheel-0.41.2-py3-none-any.whl (64 kB)
|████████████████████████████████| 64 kB 8.4 MB/s
Installing collected packages: wheel, setuptools, pip
Attempting uninstall: setuptools
Found existing installation: setuptools 56.0.0
Uninstalling setuptools-56.0.0:
Successfully uninstalled setuptools-56.0.0
Attempting uninstall: pip
Found existing installation: pip 21.1.1
Uninstalling pip-21.1.1:
Successfully uninstalled pip-21.1.1
Successfully installed pip-23.3.1 setuptools-68.2.2 wheel-0.41.2
Finished updating
Installing dependencies in virtual environment...
Collecting pulumi<4.0.0,>=3.0.0 (from -r requirements.txt (line 1))
Downloading pulumi-3.89.0-py3-none-any.whl.metadata (11 kB)
Collecting pulumi-azure-native<3.0.0,>=2.0.0 (from -r requirements.txt (line 2))
Downloading pulumi_azure_native-2.12.0-py3-none-any.whl.metadata (3.6 kB)
Collecting protobuf~=4.21 (from pulumi<4.0.0,>=3.0.0->-r requirements.txt (line 1))
Downloading protobuf-4.24.4-cp37-abi3-macosx_10_9_universal2.whl.metadata (540 bytes)
Collecting grpcio==1.56.2 (from pulumi<4.0.0,>=3.0.0->-r requirements.txt (line 1))
Downloading grpcio-1.56.2-cp38-cp38-macosx_10_10_universal2.whl.metadata (4.0 kB)
Collecting dill~=0.3 (from pulumi<4.0.0,>=3.0.0->-r requirements.txt (line 1))
Downloading dill-0.3.7-py3-none-any.whl.metadata (9.9 kB)
Collecting six~=1.12 (from pulumi<4.0.0,>=3.0.0->-r requirements.txt (line 1))
Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting semver~=2.13 (from pulumi<4.0.0,>=3.0.0->-r requirements.txt (line 1))
Downloading semver-2.13.0-py2.py3-none-any.whl (12 kB)
Collecting pyyaml~=6.0 (from pulumi<4.0.0,>=3.0.0->-r requirements.txt (line 1))
Downloading PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl.metadata (2.1 kB)
Collecting parver>=0.2.1 (from pulumi-azure-native<3.0.0,>=2.0.0->-r requirements.txt (line 2))
Downloading parver-0.5-py3-none-any.whl.metadata (2.7 kB)
Collecting arpeggio>=1.7 (from parver>=0.2.1->pulumi-azure-native<3.0.0,>=2.0.0->-r requirements.txt (line 2))
Downloading Arpeggio-2.0.2-py2.py3-none-any.whl.metadata (2.4 kB)
Collecting attrs>=19.2 (from parver>=0.2.1->pulumi-azure-native<3.0.0,>=2.0.0->-r requirements.txt (line 2))
Downloading attrs-23.1.0-py3-none-any.whl (61 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.2/61.2 kB 1.5 MB/s eta 0:00:00
Collecting typing-extensions (from parver>=0.2.1->pulumi-azure-native<3.0.0,>=2.0.0->-r requirements.txt (line 2))
Downloading typing_extensions-4.8.0-py3-none-any.whl.metadata (3.0 kB)
Downloading pulumi-3.89.0-py3-none-any.whl (190 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 190.5/190.5 kB 3.9 MB/s eta 0:00:00
Downloading grpcio-1.56.2-cp38-cp38-macosx_10_10_universal2.whl (8.9 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.9/8.9 MB 5.4 MB/s eta 0:00:00
Downloading pulumi_azure_native-2.12.0-py3-none-any.whl (47.9 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 47.9/47.9 MB 5.2 MB/s eta 0:00:00
Downloading dill-0.3.7-py3-none-any.whl (115 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 115.3/115.3 kB 3.2 MB/s eta 0:00:00
Downloading parver-0.5-py3-none-any.whl (15 kB)
Downloading protobuf-4.24.4-cp37-abi3-macosx_10_9_universal2.whl (409 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 409.4/409.4 kB 5.4 MB/s eta 0:00:00
Downloading PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl (191 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 191.7/191.7 kB 3.8 MB/s eta 0:00:00
Downloading Arpeggio-2.0.2-py2.py3-none-any.whl (55 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 55.3/55.3 kB 1.8 MB/s eta 0:00:00
Downloading typing_extensions-4.8.0-py3-none-any.whl (31 kB)
Installing collected packages: arpeggio, typing-extensions, six, semver, pyyaml, protobuf, grpcio, dill, attrs, pulumi, parver, pulumi-azure-native
Successfully installed arpeggio-2.0.2 attrs-23.1.0 dill-0.3.7 grpcio-1.56.2 parver-0.5 protobuf-4.24.4 pulumi-3.89.0 pulumi-azure-native-2.12.0 pyyaml-6.0.1 semver-2.13.0 six-1.16.0 typing-extensions-4.8.0
Finished installing dependencies
Finished installing dependencies
Your new project is ready to go! ✨
To perform an initial deployment, run `pulumi up`
ローカルの場合はパスフレーズを使い暗号化を行う。これはプロジェクト毎に設定するようです。
次に、プロジェクトを作成した後、devというstackが作られる。stackというのは環境を表すもので、開発者が使う「Development(開発環境)」や、お客様が検証時使う「staging(検証環境)」や、実際に利用する「production(本番環境)」と定義することが一般的だが、Pulumiではこれらを1つ1つをstackと呼んで分離している。 なので、プロジェクトの中には複数のstackがあり、stack毎に変更等を反映していくことになる。今回はデフォルトのstackとしてdev(開発環境)が作られたが、stackの操作はサブコマンドのpulumi stackで一通り操作できます。
Pulumiのプログラムを書く
「__main__.py」が実際のコードになる。デフォルトでリソースグループとストレージアカウントを作成するコードが用意される。その2つのリソース名の変更と作成されたリソース名の画面表示(Output)を追加した。
"""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("rg_ituru_pulumi_")
# Create an Azure resource (Storage Account)
account = storage.StorageAccount(
"saiturupulumi",
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("ResourceGroup", resource_group.name)
pulumi.export("StorageAccount", account.name)
pulumi.export("primary_storage_key", primary_key)
pulumi up で 設定を反映
## Deploy Stack
$ pulumi up
Enter your passphrase to unlock config/secrets
(set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember):
Enter your passphrase to unlock config/secrets
Previewing update (dev):
Type Name Plan
+ pulumi:pulumi:Stack quickstart-dev create
+ ├─ azure-native:resources:ResourceGroup rg_ituru_pulumi_ create
+ └─ azure-native:storage:StorageAccount saiturupulumi create
Outputs:
ResourceGroup : output<string>
StorageAccount : output<string>
primary_storage_key: output<string>
Resources:
+ 3 to create
Do you want to perform this update? yes
Updating (dev):
Type Name Status
+ pulumi:pulumi:Stack quickstart-dev created (28s)
+ ├─ azure-native:resources:ResourceGroup rg_ituru_pulumi_ created (1s)
+ └─ azure-native:storage:StorageAccount saiturupulumi created (26s)
Outputs:
ResourceGroup : "rg_ituru_pulumi_0dd5a1af"
StorageAccount : "saiturupulumie1e8f28d"
primary_storage_key: "jMP11aD0HUJ0zn69Us+I5x1DhAV3jMRoNjffBmx0IC07uyKtDNNzNTDe6mgJWjVFQq9FkPXPssvY+ASt62Jf1Q=="
Resources:
+ 3 created
Duration: 29s
実際に作られたリソース名は rg_ituru_pulumi_0dd5a1af や saiturupulumie1e8f28d という感じで後ろに8文字のサフィックスをPulumiが勝手につけているみたい。
リソースグループ名を明示的に変更
ストレージアカウント はともかく、リソースグループはサフィックスを付けられたくないので、明示的に指定する。
# Create an Azure Resource Group
# resource_group = resources.ResourceGroup("rg_ituru_pulumi_")
resource_group = resources.ResourceGroup("resourceGroup",
resource_group_name="rg_ituru_pulumi",
)
pulumi up で 設定を再反映
## Deploy Stack
$ pulumi up
Enter your passphrase to unlock config/secrets
(set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember):
Enter your passphrase to unlock config/secrets
Previewing update (dev):
Type Name Plan Info
pulumi:pulumi:Stack quickstart-dev
+ ├─ azure-native:resources:ResourceGroup resourceGroup create
+- ├─ azure-native:storage:StorageAccount saiturupulumi replace [diff: ~resourceGroupName]
- └─ azure-native:resources:ResourceGroup rg_ituru_pulumi_ delete
Resources:
+ 1 to create
- 1 to delete
+-1 to replace
3 changes. 1 unchanged
Do you want to perform this update? yes
Updating (dev):
Type Name Status Info
pulumi:pulumi:Stack quickstart-dev
+ ├─ azure-native:resources:ResourceGroup resourceGroup created (0.54s)
+- ├─ azure-native:storage:StorageAccount saiturupulumi replaced (3s) [diff: ~resourceGroupName]
- └─ azure-native:resources:ResourceGroup rg_ituru_pulumi_ deleted (15s)
Outputs:
~ ResourceGroup : "rg_ituru_pulumi_0dd5a1af" => "rg_ituru_pulumi"
~ StorageAccount : "saiturupulumie1e8f28d" => "saiturupulumi7bc3549e"
~ primary_storage_key: "jMP11aD0HUJ0zn69Us+I5x1DhAV3jMRoNjffBmx0IC07uyKtDNNzNTDe6mgJWjVFQq9FkPXPssvY+ASt62Jf1Q==" => "e8xELGxafP6ot7QxCtrw0vXFFmx+DHZ/jXzXppkijGx4hcAJ658bIZz5mscA3bwaDPj+AUzac14y+AStxRiamg=="
Resources:
+ 1 created
- 1 deleted
+-1 replaced
3 changes. 1 unchanged
Duration: 46s
Azureのリソースグループは通常名前変更ができない。しかしpulumiは前回実行後の状態を(今回は)ローカルで管理しているので、使われなくなったリソースを削除し、再度新規作成する形で置き換わる。リソースグループに紐づくストレージアカウントも作り直しになっている。つまり、既存のリソース(データ含む)が全て吹っ飛ぶので注意が必要です。
Output情報の取得方法
## まとめて取得
$ pulumi stack output
Enter your passphrase to unlock config/secrets
(set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember): *************
Enter your passphrase to unlock config/secrets
Current stack outputs (4):
OUTPUT VALUE
ResourceGroup rg_ituru_pulumi
StorageAccount saiturupulumi7bc3549e
primary_storage_key e8xELGxafP6ot7QxCtrw0vXFFmx+DHZ/jXzXppkijGx4hcAJ658bIZz5mscA3bwaDPj+AUzac14y+AStxRiamg==
## 個別に取得(例)
$ pulumi stack output ResourceGroup
Enter your passphrase to unlock config/secrets
(set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember): *************
Enter your passphrase to unlock config/secrets
rg_ituru_pulumi
静的Websiteの立ち上げ
次はここを参照して、静的Webサイトを立ち上げます。
コンテンツの作成
ストレージアカウントがプロビジョニングされたので、それにオブジェクトを追加していきます。 コンテンツを含む新しいindex.html ファイルを作成します。
cat <<EOT > index.html
<html>
<body>
<h1>Hello, Pulumi!</h1>
</body>
</html>
EOT
プログラムの追加
静的Webサイトを有効にし、index.html をストレージコンテナーにアップロードし、リソースプロパティを使用してパブリックURLを取得します。
静的Webサイトのリソースは、プログラムで以前に定義されたストレージアカウントとリソースグループを利用します。
# Enable static website support
static_website = storage.StorageAccountStaticWebsite(
"staticWebsite",
account_name=account.name,
resource_group_name=resource_group.name,
index_document="index.html",
)
次に、index.html をストレージコンテナーにアップロードできるようにします。
# Upload the file
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",
)
最後に、結果のストレージ コンテナーのエンドポイントURL をOutput出来るようにします。
# Web endpoint to the website
pulumi.export("staticEndpoint", account.primary_endpoints.web)
pulumi up で 設定を再々反映
## Deploy Stack
$ pulumi up
Enter your passphrase to unlock config/secrets
(set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember):
Enter your passphrase to unlock config/secrets
Previewing update (dev):
Type Name Plan
pulumi:pulumi:Stack quickstart-dev
+ ├─ azure-native:storage:StorageAccountStaticWebsite staticWebsite create
+ └─ azure-native:storage:Blob index.html create
Outputs:
+ staticEndpoint : "https://saiturupulumi7bc3549e.z11.web.core.windows.net/"
Resources:
+ 2 to create
3 unchanged
Do you want to perform this update? yes
Updating (dev):
Type Name Status
pulumi:pulumi:Stack quickstart-dev
+ ├─ azure-native:storage:StorageAccountStaticWebsite staticWebsite created (1s)
+ └─ azure-native:storage:Blob index.html created (0.33s)
Outputs:
ResourceGroup : "rg_ituru_pulumi"
StorageAccount : "saiturupulumi7bc3549e"
primary_storage_key: "e8xELGxafP6ot7QxCtrw0vXFFmx+DHZ/jXzXppkijGx4hcAJ658bIZz5mscA3bwaDPj+AUzac14y+AStxRiamg=="
+ staticEndpoint : "https://saiturupulumi7bc3549e.z11.web.core.windows.net/"
Resources:
+ 2 created
3 unchanged
Duration: 3s
結果を確認してみます。問題なくアクセスできました(もちろんブラウザでも確認とれました)。
## Webアクセス動作確認
$ curl https://saiturupulumi7bc3549e.z11.web.core.windows.net/
<html>
<body>
<h1>Hello, Pulumi!</h1>
</body>
</html>
Stack情報の確認
Pulumiで作成したリソースは、Pulumi上ではStack単位で管理されています(今回は "dev")
## Stack情報の取得
$ pulumi stack
Enter your passphrase to unlock config/secrets
(set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember): **************
Enter your passphrase to unlock config/secrets
Current stack is dev:
Managed by IsseinoMacBook-Pro.local
Last updated: 16 minutes ago (2023-10-25 21:07:51.212534 +0900 JST)
Pulumi version used: v3.89.0
Current stack resources (7):
TYPE NAME
pulumi:pulumi:Stack quickstart-dev
├─ azure-native:resources:ResourceGroup resourceGroup
├─ azure-native:storage:StorageAccount saiturupulumi
├─ azure-native:storage:StorageAccountStaticWebsite staticWebsite
├─ azure-native:storage:Blob index.html
├─ pulumi:providers:azure-native default_2_12_0
└─ pulumi:providers:azure-native default
Current stack outputs (4):
OUTPUT VALUE
ResourceGroup rg_ituru_pulumi
StorageAccount saiturupulumi7bc3549e
primary_storage_key e8xELGxafP6ot7QxCtrw0vXFFmx+DHZ/jXzXppkijGx4hcAJ658bIZz5mscA3bwaDPj+AUzac14y+AStxRiamg==
staticEndpoint https://saiturupulumi7bc3549e.z11.web.core.windows.net/
Use `pulumi stack select` to change stack; `pulumi stack ls` lists known ones
Stack一覧の取得
$ pulumi stack ls
NAME LAST UPDATE RESOURCE COUNT
dev* 19 minutes ago 7
後片付け
リソースの全削除
$ pulumi destroy
Enter your passphrase to unlock config/secrets
(set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember): **************
Enter your passphrase to unlock config/secrets
Previewing destroy (dev):
Type Name Plan
- pulumi:pulumi:Stack quickstart-dev delete
- ├─ azure-native:storage:Blob index.html delete
- ├─ azure-native:storage:StorageAccountStaticWebsite staticWebsite delete
- ├─ azure-native:storage:StorageAccount saiturupulumi delete
- └─ azure-native:resources:ResourceGroup resourceGroup delete
Outputs:
- ResourceGroup : "rg_ituru_pulumi"
- StorageAccount : "saiturupulumi7bc3549e"
- primary_storage_key: "e8xELGxafP6ot7QxCtrw0vXFFmx+DHZ/jXzXppkijGx4hcAJ658bIZz5mscA3bwaDPj+AUzac14y+AStxRiamg=="
- staticEndpoint : "https://saiturupulumi7bc3549e.z11.web.core.windows.net/"
Resources:
- 5 to delete
Do you want to perform this destroy? yes
Destroying (dev):
Type Name Status
- pulumi:pulumi:Stack quickstart-dev deleted (0.00s)
- ├─ azure-native:storage:Blob index.html deleted (0.51s)
- ├─ azure-native:storage:StorageAccountStaticWebsite staticWebsite deleted (0.15s)
- ├─ azure-native:storage:StorageAccount saiturupulumi deleted (3s)
- └─ azure-native:resources:ResourceGroup resourceGroup deleted (15s)
Outputs:
- ResourceGroup : "rg_ituru_pulumi"
- StorageAccount : "saiturupulumi7bc3549e"
- primary_storage_key: "e8xELGxafP6ot7QxCtrw0vXFFmx+DHZ/jXzXppkijGx4hcAJ658bIZz5mscA3bwaDPj+AUzac14y+AStxRiamg=="
- staticEndpoint : "https://saiturupulumi7bc3549e.z11.web.core.windows.net/"
Resources:
- 5 deleted
Duration: 20s
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`.
まとめ
Terraformも良いですが、後発のPulumiも良いです。
参考記事
以下の記事を参考にさせていただきました。感謝申し上げます。
PulumiはIaCの革命児になれるか