Pulumiを使用する上での実践的なTips

はじめに

実践的なTipsと書いてありますが、まだ本番環境をPulumiで構築した経験はありません。今までCloudFormationやTerraformで構築した経験を元にPulumiでこういう事ってどうやるのかな?を調べてみました。
その結果をまとめていきます。
Pulumi自体については、下記のブログを参照ください。

これが次世代プロビジョニングツールの実力か!? PulumiでAWSリソースを作成してみた

環境の分割

Pulumiにおいて環境(dev, stg, prd)はStackとして扱います。

Stackの新規作成

Stack名はプロジェクト内で一意である必要があります。

pulumi stack init stg

新規作成された環境には一切の変数がセットされていません。AWSの場合は以下をセットします。

pulumi config set aws:region <aws-region>

Stack一覧

Stack一覧を確認できます。NAME末尾に*が付いているのが現在選択されているStackです。

pulumi stack ls
NAME  LAST UPDATE   RESOURCE COUNT  URL
dev   20 hours ago  0               https://app.pulumi.com/<username>/pulumi-aws-typescript/dev
stg*  n/a           n/a             https://app.pulumi.com/<username>/pulumi-aws-typescript/stg

Stackの選択

Stackの選択を行う方法です。

pulumi stack select dev

環境ごとの変数

プレーンテキスト

devはkeynameがAAAで、stgはBBBといった環境毎の変数は、基本的に必要になります。
下記のコマンドで変数を作成できます。

pulumi config set Key Value

変数はPulumi.stack-name.yamlに保存されます。コマンドを使用せず、直接ファイルに書き込んでもOKです。

config:
  aws:region: ap-northeast-1
  <project-name>:Key: Value

環境変数はコード内でnew pulumi.Config("<project-name>");で取り出す事が可能です。

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const config = new pulumi.Config("<project-name>"); // <project-name> is name defined in Pulumi.yaml
const bucket = new aws.s3.Bucket(config.require("Key"));

シークレット

Pulumiではシークレットを暗号化して管理する事も可能です。暗号化はスタック毎にpulumi.comが管理している固有の鍵によって行われます。

pulumi config set --secret SecretKey SecretValue
config:
  aws:region: ap-northeast-1
  <project-name>:Key: Value
  pulumi-aws-typescript:SecretKey:
    secure: AAABABBCHknbIDFb8pGJFytxqZ5K5MT5uvy75AluXUfZUSIoUPlipxKJOg==

コード内での取り出し方法はプレーンテキストの場合と同じです。

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const config = new pulumi.Config("<project-name>"); // <project-name> is name defined in Pulumi.yaml
const bucket = new aws.s3.Bucket(config.require("SecretKey"));

シークレットを確認する場合は、--show-secretsを追加する必要があります。

pulumi config --show-secrets
KEY          VALUE
aws:region   ap-northeast-1
Key          Value
SecretKey    SecretValue

なお、暗号化する際にランダムなソルトが追加されます。よって同じ値であっても生成される暗号文は異なります。

pulumi config set --secret SecretKey2 SecretValue
config:
  aws:region: ap-northeast-1
  <project-name>:Key: Value
  pulumi-aws-typescript:SecretKey:
    secure: AAABABBCHknbIDFb8pGJFytxqZ5K5MT5uvy75AluXUfZUSIoUPlipxKJOg==
  pulumi-aws-typescript:SecretKey2:
    secure: AAABAKZ0WIYxFEh15XGMqbBClvNunKFdTinmps7DnSlylpQYUcz6k20zyA==

環境名の取得

リソースにXXX-dev-YYYと命名したい事はよくありますね。環境名(= Stack名)の取り出すにはconst env = pulumi.getStack();を使います。

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const config = new pulumi.Config(""<project-name>"); // "<project-name> is name defined in Pulumi.yaml
const env = pulumi.getStack();

const bucket = new aws.s3.Bucket(env + "-" + config.require("SecretKey"));

Local State

PulumiはState(現在の構成情報)をPulumi.com、つまりクラウド上の保存できる事がメリットですが、ローカルに保存する事も可能です。
Localに保存する場合は、WebブラウザでのActivityの確認が行えなくなります。

Local Stateの使用

pulumi login --localコマンドでローカルにログインができます。このコマンドの場合は、~/.pulumi/stacksにStateが保存されます。
今回はプロジェクトディレクトリに保存したかったので、パスをしました。

mkdir -p .pulumi/stacks/
pulumi login file://./

Stackを作成し、環境の変数をセットします。

pulumi stack init dev
pulumi config set aws:region ap-northeast-1
pulumi config set bucketName demo

S3バケットを作成してみます。

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const env = pulumi.getStack();
const config = new pulumi.Config("pulumi-aws-typescript"); // pulumi-aws-typescript is name defined in Pulumi.yaml

const bucket = new aws.s3.Bucket(`xxx-${env}-${config.require("bucketName")}`);
pulumi up

検証は行っていませんが、ドキュメントを確認する限りStateを共有フォルダに保存や同期する事で複数人での構築が可能です。

Local Stateにおけるシークレット

Local Stateでもシークレットを利用する事が可能です。この場合、パスフレーズを使って暗号化を行います。Stackのプレビュー・更新・削除の際にパスワード入力が求められます。
環境変数PULUMI_CONFIG_PASSPHRASEに、パスフレーズをセットして置くことで、入力を省略する事が可能です。

pulumi config set --secret SecretKey2 SecretValue
Enter your passphrase to unlock config/secrets
    (set PULUMI_CONFIG_PASSPHRASE to remember):

# 環境変数にセットしている場合は確認されない
export PULUMI_CONFIG_PASSPHRASE='password'
pulumi config set --secret SecretKey3 SecretValue
unset PULUMI_CONFIG_PASSPHRASE

pulumi up
Previewing update (dev):
Enter your passphrase to unlock config/secrets
    (set PULUMI_CONFIG_PASSPHRASE to remember):

     Type                 Name                       Plan
     pulumi:pulumi:Stack  pulumi-aws-typescript-dev

Resources:
    2 unchanged

Do you want to perform this update? yes
Updating (dev):
Enter your passphrase to unlock config/secrets
    (set PULUMI_CONFIG_PASSPHRASE to remember): 

     Type                 Name                       Status
     pulumi:pulumi:Stack  pulumi-aws-typescript-dev

Resources:
    2 unchanged

Duration: 4s

Permalink: file:///workdir/pulumi-aws-typescript/.pulumi/stacks/dev.json

あとがき

PulumiのTipsをまとめてみました。個人的に残り気になるのは、GitHubでコード管理 & CircleCIなどでCI/CDする際の設計ですね。良い構成にたどり着いたらブログを書きたいです。
Pulumi触っていて楽しいので、今後も積極的に続けて行きたいお気持ちです!