この記事は、Pulumi dotnet Advent Calendar 2019の1日目です。
Pulumiの .NET Core対応版がPreviewリリースされました。
Getting Startedから、実際に環境を構築したり疑問点の解決を回を重ねながらみていきましょう。
- 概要
- Pulumi Getting Started
- Login
- 事前準備
- Create a New Project
- 仮実行とエラー解消
- リソースを作成してみる
- リソースを削除してみる
- さらにリソースを追加
- stack destroy
- TODO
概要
実際にPulumi x .NET Core 3.0 (C#) で使ってみていますがそのまとめをざっくり。
- まだPreviewなので、TypeScriptやPythonと比べてできない機能も数多い
- 動作もいくつかバグが残っていたりして、NuGetのPreviewパッケージが週一でどんどん改善されている
- 現状はVisual Studioで実行まで完結するわけではないので注意
- 型は偉大、terraformのようにドキュメントを見る手間が格段に減った
- 型でわからないときでもterraformのドキュメントをみればok
- ドキュメントのメソッドやクラスは結構古かったりする
Getting Startedはいい出来にはなっているので見てみるといいでしょう。
Pulumi Getting Started
これに基づいて進めていく。
Login
まずは何はともあれアカウントを作る。

アクセストークンを作ることで、pulumi cliとアカウントが紐づいて操作できるようになる。
事前準備
install .NET Core 3.0 SDK
Pulumiの実行は、コンパイルしてから実行されます。 このコンパイル、実行のために .NET Core 3.0 SDKが必要です。
Install Pulumi cli
Windows
scoopに対応したので、これでpulumi cliを入れましょう。main bucketで利用できます。(scoopインストールしたらすぐにつかえるということです)
scoop install pulumi
cliでログインします。これでCLIがWebと紐づいて、ログが記録されたりリソースが可視化されます。
pulumi login
macOS
Homebrewでどうぞ。
brew install pulumi
更新はupgradeで。
brew upgrade pulumi
linux
curlで拾ってきて、実行するだけです。
curl -fsSL https://get.pulumi.com | sh
アクセストークン の生成方法
3つあります。アクセストークンを管理したくないので、自動生成がお勧めです。
- (recommended)
pulumi loginでログインしたら、何も入力せずにEnter。ブラウザが立ち上がるので、ログインすると自動的にアクセストークンが生成

- アクセストークンを
pulumi loginで入れる - アクセストークンを
PULUMI_ACCESS_TOKEN環境変数に入れる
Language Support
- GA:
TYPESCRIPT,JAVASCRIPT,PYTHON - PREVIEW:
C#(.NET Core 3.0 SDK or later.), Golang
Configure AWS
AWSを操作する前に、認証だけ解決しておくこと。 defaultプロファイルを使わない場合、権限のあるUserを以下の環境変数に入れておくのが手っ取り早い。
AWS_PROFILE
Visual StudioのLaunch Profileで環境変数に入れてもokです。 pulumi upでdotnet buildされるので、それが使われます。
Create a New Project
AWS C# projectを作成します。
mkdir pulumi cd pulumi pulumi new aws-csharp
デフォルトだと次のようになる。
> pulumi new aws-csharp 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: (pulumi) project description: (A minimal AWS C# Pulumi program) Created project 'pulumi' 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' aws:region: The AWS region to deploy into: (us-east-1) ap-northeast-1 Saved config Your new project is ready to go! To perform an initial deployment, run 'pulumi up'
これで自動的にcsprojやProgram.cs、 yamlが生成される。
$ ls -la drw-rw-rw- 6 S07671 0 4096 2019-11-13 10:21 . drw-rw-rw- 6 S07671 0 4096 2019-11-12 18:33 .. -rw-rw-rw- 1 S07671 0 6401 2019-11-12 18:41 .gitignore -rw-rw-rw- 1 S07671 0 318 2019-11-12 18:41 Infra.csproj -rw-rw-rw- 1 S07671 0 1115 2019-11-12 19:00 Infra.sln -rw-rw-rw- 1 S07671 0 1357 2019-11-13 10:21 Program.cs -rw-rw-rw- 1 S07671 0 37 2019-11-12 18:41 Pulumi.dev.yaml -rw-rw-rw- 1 S07671 0 74 2019-11-12 18:41 Pulumi.yaml

ファイルは次の通り。
- Pulumi.yaml defines the project
- Pulumi.dev.yaml contains configuration values for the stack we initialized
- Program.cs is the Pulumi program that defines our stack resources. Let’s examine it
name: pulumi runtime: dotnet description: A minimal AWS C# Pulumi program
config: aws:region: ap-northeast-1
using System.Collections.Generic;
using System.Threading.Tasks;
using Pulumi;
using Pulumi.Aws.S3;
class Program
{
static Task<int> Main()
{
return Deployment.RunAsync(() => {
// Create an AWS resource (S3 Bucket)
var bucket = new Bucket("my-bucket");
// Export the name of the bucket
return new Dictionary<string, object>
{
{ "bucketName", bucket.Id },
};
});
}
}
1.8.0
仮実行とエラー解消
この状態でpulumi upとするとスタックがどう生成されるか表示される。
Config に aws:region の設定が抜けているとエラーが発生する
と思いきや、エラー。
$ pulumi up
Previewing update (sandbox):
Type Name Plan Info
pulumi:pulumi:Stack pulumi-sandbox 'dotnet build -nologo .' completed successfully
ms
+ pulumi:pulumi:Stack pulumi-sandbox create 1 error; 2 messages
����ł����B Name Plan Info
+ └─ pkg:component:ekscluster sandbox create
Diagnostics:
pulumi:pulumi:Stack (pulumi-sandbox):
�N���v���t�@�C�� "(����)" ���K�p�ł��܂����ł����B
�g�p�\�ȋN���v���t�@�C�����������܂����ł����B
error: Running program 'C:\git\infra\pulumi\sandbox\bin\Debug\netcoreapp3.0\Infra.dll' failed with an unhandled exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at Pulumi.Deployment.InvokeAsync[T](String token, ResourceArgs args, InvokeOptions options, Boolean convertResult)
at Infra.EksClusterComponent.CreateAsync() in C:\git\infra\pulumi\sandbox\EksClusterComponent.cs:line 25
at Program.<>c.<<Main>b__0_0>d.MoveNext() in C:\git\infra\pulumi\sandbox\Program.cs:line 39
--- End of stack trace from previous location where exception was thrown ---
at Pulumi.Stack.RunInitAsync(Func`1 init)
at Pulumi.Output`1.GetValueAsync()
at Pulumi.Deployment.RegisterResourceOutputsAsync(Resource resource, Output`1 outputs)
at Pulumi.Deployment.Runner.WhileRunningAsync()
エラーは、System.NullReferenceException: Object reference not set to an instance of an object.。リソースの読み取りを使用とする時点で怒られる。
原因は、pulumiでAWSのRegion情報aws:regionをconfigに設定していないため。
なので、Config設定する。
$ pulumi config set aws:region ap-northeast-1
AWS Profile の指定が抜けているとエラーが発生する
configにaws:regionの設定後、再実行するとまた失敗する。
$ pulumi up
Previewing update (dev):
Type Name Plan Info
pulumi:pulumi:Stack pulumi-dev .NET Core ���� Microsoft (R) Build Engine �o�[�W���� 16.3.0+0f pulumi:pulumi:Stack pulumi-dev C:\git\xxx\infra\pulumi\Infra.csproj �̕����� 45.39 ms �Ŋ�� pulumi:pulumi:Stack pulumi-dev 'dotnet build .' completed successfully
[resource plugin aws-1.8.0] installing
Downloading plugin: 61.24 MiB / 61.24 MiB [=========================] 100.00% 5s
Moving plugin... done.
Type Name Plan Info
+ pulumi:pulumi:Stack pulumi-dev create
└─ aws:s3:Bucket my-bucket 1 error
Diagnostics:
aws:s3:Bucket (my-bucket):
error: unable to discover AWS AccessKeyID and/or SecretAccessKey - see https://pulumi.io/install/aws.html for details on configuration
エラーはerror: unable to discover AWS AccessKeyID and/or SecretAccessKey - see https://pulumi.io/install/aws.html for details on configurationなのでAWSプロファイルがないことを示す。
ということで、aws configureでdefault profileの認証を設定する。
https://www.pulumi.com/docs/intro/cloud-providers/aws/setup/
もし複数プロファイルがあり、任意のプロファイルを参照したい場合は、AWS_PROFILE環境変数にプロファイルを指定する。
リソースを作成してみる
これでpulumi upすると、yes / noが選択できる。
yesでリソースが作成、削除される。
$ pulumi up
Previewing update (dev):
Type Name Plan Info
pulumi:pulumi:Stack pulumi-dev .NET Core ���� Microsoft (R) Build Engine �o�[�W���� 16.3.0+0f pulumi:pulumi:Stack pulumi-dev C:\git\infra\pulumi\Infra.csproj �̕����� 34.9 ms �Ŋ�� pulumi:pulumi:Stack pulumi-dev 'dotnet build .' completed successfully
Type Name Plan
+ pulumi:pulumi:Stack pulumi-dev create
+ └─ aws:s3:Bucket my-bucket create
Resources:
+ 2 to create
Do you want to perform this update? yes
Updating (dev):
Type Name Status Info
pulumi:pulumi:Stack pulumi-dev .NET Core ���� Microsoft (R) Build Engine �o�[�W���� 16.3.0+ pulumi:pulumi:Stack pulumi-dev C:\git\infra\pulumi\Infra.csproj �̕����� 32.92 ms �Ŋ� pulumi:pulumi:Stack pulumi-dev 'dotnet build .' completed successfully
Type Name Status
+ pulumi:pulumi:Stack pulumi-dev created
+ └─ aws:s3:Bucket my-bucket created
Outputs:
bucketName: "my-bucket-626a03e"
Resources:
+ 2 created
Duration: 9s
Permalink: https://app.pulumi.com/guitarrapc/pulumi/dev/updates/1
リソースを見てみると、後ろにハッシュがつくことで名前の重複が防がれていることがわかる。

リソースを削除してみる
消すと、pulumi upで実行したときに消える
// Create an AWS resource (S3 Bucket) //var bucket = new Bucket("my-bucket");
> pulumi up
Previewing update (dev):
Type Name Plan Info
pulumi:pulumi:Stack pulumi-dev 'dotnet build .' completed successfully
����܂
Type Name Plan
pulumi:pulumi:Stack pulumi-dev
- └─ aws:s3:Bucket my-bucket delete
Outputs:
- bucketName: "my-bucket-626a03e"
Resources:
- 1 to delete
1 unchanged
Do you want to perform this update? yes
Updating (dev):
Type Name Status Info
pulumi:pulumi:Stack pulumi-dev 'dotnet build .' completed successfully
�����
Type Name Status
pulumi:pulumi:Stack pulumi-dev
- └─ aws:s3:Bucket my-bucket deleted
Outputs:
- bucketName: "my-bucket-626a03e"
hogemoge : "piyopiyo"
Resources:
- 1 deleted
1 unchanged
Duration: 5s
Permalink: https://app.pulumi.com/guitarrapc/pulumi/dev/updates/3
余談: VS での F5 実行
F5で実行はまだ無理げ。
Complete Support for .NET · Issue #3470 · pulumi/pulumi https://github.com/pulumi/pulumi/issues/3470
VS上のPulumi_Monitorとかも環境変数仕込むとgRPCのchannelがフックされるのでいったんなしがよさそう。
new Pulumi.Aws.Provider()で指定できる? 例えば、pulumi-sandbox profileのap-northeast-1 regionならこう。-> profile参照されてないときと同じエラーでダメだった。
new Pulumi.Aws.Provider("sandbox", new Pulumi.Aws.ProviderArgs() { Profile = "pulumi-sandbox", Region = "ap-northeast-1", });
さらにリソースを追加
KMSを追加してみる。
static Task<int> Main() { return Deployment.RunAsync(() => { // Create a KMS Key for S3 server-side encryption var key = new Pulumi.Aws.Kms.Key("my-key"); // Create an AWS resource (S3 Bucket) var bucket = new Pulumi.Aws.S3.Bucket("my-bucket", new Pulumi.Aws.S3.BucketArgs { ServerSideEncryptionConfiguration = new Pulumi.Aws.S3.Inputs.BucketServerSideEncryptionConfigurationArgs { Rule = new Pulumi.Aws.S3.Inputs.BucketServerSideEncryptionConfigurationRuleArgs { ApplyServerSideEncryptionByDefault = new Pulumi.Aws.S3.Inputs.BucketServerSideEncryptionConfigurationRuleApplyServerSideEncryptionByDefaultArgs { SseAlgorithm = "aws:kms", KmsMasterKeyId = key.Id, }, }, }, }); // Export the name of the bucket return new Dictionary<string, object> { { "bucket_name", bucket.Id }, }; }); }
追加される。
pulumi up
Previewing update (dev):
Type Name Plan Info
pulumi:pulumi:Stack pulumi-dev 'dotnet build .' completed successfully
����܂
Type Name Plan
pulumi:pulumi:Stack pulumi-dev
+ ├─ aws:kms:Key my-key create
+ └─ aws:s3:Bucket my-bucket create
Outputs:
+ bucket_name: output<string>
- hogemoge : "piyopiyo"
Resources:
+ 2 to create
1 unchanged
Do you want to perform this update?
kmsを見ると、nameに指定した文字列がどこにもないのが気になる。

stack destroy
$ pulumi destroy
Previewing destroy (dev):
Type Name Plan
- pulumi:pulumi:Stack pulumi-dev delete
- ├─ aws:s3:Bucket my-bucket delete
- └─ aws:kms:Key my-key delete
Outputs:
- bucket_name: "my-bucket-c3f5c37"
Resources:
- 3 to delete
Do you want to perform this destroy?
yes
> no
details
Duration: 24s Permalink: https://app.pulumi.com/guitarrapc/pulumi/dev/updates/5 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'.
TODO
Getting Startedの中で幾つもわからないことが出てきました。 次回から順にみていきましょう。
- pulumi up時の文字化け対策
- Pulumi Web UIでできること
- 後ろのハッシュはずすのどうするの?
- IAM Document PolicyのようなJSONをいい感じで型から生成できるの?
- リソース作成後の型が
Output<string>だけどいい感じに変換できるの? - Terraform Module的な仕組みどうするの?
- 既存リソースのimportどうするの?
- よく使うコマンドは?
- stateってどうなってるの?
- 他のstate参照どうするの?
- VS上でF5実行のステータスどうなってる?