この記事は3-shake Advent Calendar 2023の16日目の記事です。
この内容はSRETT #8で発表した内容に補足しています。
- 前提
- 語らないこと
- モチベーション
- Pulumiとは
- Pulumiのアーキテクチャ
- Pulumiのコンポーネント
- Pulumi Cloud
- Pulumi Cloud 料金
- Pulumi操作方法
- まとめ
前提
筆者は以下の背景を持っています。
- 普段はAWSをメインに触っている
- 普段はTerraformをメインで使ってる
- Pulumiはプロダクションでは使ったことがない
- ちゃんとは把握できてない
語らないこと
以下のようなPulumi以外の基本的なことは語りません
- IaCとは
- 概要、特徴、メリット・デメリット
- Terraformとは
- 概要、特徴、メリット・デメリット、操作方法
モチベーション
なんでPulumiを今回調べようかと思った動機について書こうと思います。
Terraformの記述力に限界を感じていたというところが大きいです。以下の点がつらいかなと思っていたところです。
- 足りない関数
- 二重ループのためのModule使用
- 分岐処理のためのcountと三項演算子
とはいえ、記述力が低いからこそ複雑なことを抑制できて可読性が上がっている面もあると思います。 冗長でも、可読性が高いというのはメリットではあります。
他の選択肢としては以下のものがあるかと思います。
- CDK
- AWSに限定される
- CDKTF(CDK for Terraform)
- 結局terraformのJSONコードに変換されるので、terraformに依存します
- それ自体は悪くないが、どうせならTerraformから離れたものを学びたい
そこでなにか良いものがないかと思い当たったところにPulumiがあったので調べてみようとなりました。
Pulumiとは
Pulumiはプログラミング言語でインフラを構築可能なプロビジョニングツールです。
Terraformと同じようにProviderを通して複数のクラウドに対応しています。
TerraformはHCLという宣言的言語を使用するのに対し、Pulumiは汎用的なプログラミング言語を使用してインフラリソースを定義します。
Pulumi - Infrastructure as Code in Any Programming Language
対応言語
参考: Pulumi Languages & SDKs | Pulumi Docs
Pulumiのアーキテクチャ
以下のようの構成になっています。
参考: How Pulumi Works | Pulumi Docs
- Language host
- インフラリソースの定義を
Program
(後述)として好きな言語で定義します。
- インフラリソースの定義を
- Deployment Engine
- 希望する状態に変更するための操作セットを実行する役割を果たします。
- Resource Provider
- クラウドサービスとの通信を処理して、Programで定義したリソースの変更処理を行います。
上記の例だと、Programにリソースの定義がある場合、Stateと比較して、管理されているリソースであるかを確認します。
存在すれば、プロバイダーを通して実際のクラウドのリソースの状態と比較して差分があれば適用。
存在しない場合、プロバイダーを通してリソースを作成。
Pulumiのコンポーネント
Pulumiのコンポーネントは以下のようになっています。
- Project
- Program
- インフラのあるべき姿を定義したもの
- Resource
- インフラを構成するオブジェクト。ResourceのプロバティはOutputとして他のResourceのInputに使用することができます
- Stack
- Programを実行すると作成されるインスタンス。同一のProgramから開発、ステージング、本番環境のStackを個別に作成することができます。
Pulumi Cloud
Terraform Cloudのようなものと考えていただいて良いです。 デプロイの状態、履歴やシークレットを管理して、CI/CDやGitHubと連携してデプロイを実行することもできます。 Pulumi CLIはバックエンドを明示的に指定しない限りはでデフォルトでPulumi Cloudを使用します。
Terraformはデフォルトでlocalバックエンドを使用します。
以下はPulumi Cloudの画面です。
Pulumi Cloud 料金
個人で使う限りは無料で使用することができます。
※2023/12/18現在
Pulumi操作方法
ここからPulumiの操作方法を見て行きたいと思います
Pulumiインストール
個人的にはバージョン管理したいのでasdfでインストールします。brewでもインストールできます。
# .tool-versions
pulumi 3.97.0
asdf install
Pulumi Cloudへログイン
デフォルトではPulumi Cloudへログインします。以下のコマンドを実行するとブラウザが起動するので、ログイン処理をします。
pulumi login
Pulumi Cloudを使わず、ローカルにstateを保存したい場合は以下のとおりです。
pulumi logout pulumi loign --local
Projectの作成
pulumi new
コマンドで新しいProjectを作成できます。同時にStackも作成されます。引数にテンプレートを指定できます。
ウィザード形式で設定をすることができます。
以下の例は awsプロバイダーを使用して、言語はTypeScriptを使用するテンプレートとなります。
ディレクトリ内にはPulumi実行に必要な各種ファイルが生成されます。 ここで見るべきは以下の3ファイルです。
# Pulumi.yaml name: sample runtime: nodejs description: A minimal AWS TypeScript Pulumi program
# Pulumi.dev.yaml config: aws:region: us-east-1
// index.ts import * as pulumi from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; import * as awsx from "@pulumi/awsx"; // Create an AWS resource (S3 Bucket) const bucket = new aws.s3.Bucket("my-bucket"); // Export the name of the bucket export const bucketName = bucket.id;
変更を確認
plumi preview
コマンドでStackの変更差分を確認できます。 terraform plan
を似ていますが、こちらは差分の詳細は表示されません。
Stackデプロイ
pulumi up
コマンドでStackをデプロイできます。 terraform plan
と terraform apply
を組み合わせた挙動になります。
実行すると選択肢が出ます。
details
を選択すると変更差分の詳細が表示されます。
yes
を選択すると、変更が適用されます。
リソース削除
pulumi destroy
でStackを削除できます。
pulumi up
と同じようにdetailsで詳細表示、 yes
で削除実行ができます
state操作
PulumiではStackごとにStateが保存されています。 Stateを操作するコマンドは以下のとおりです。
- state出力(
terraform state pull
相当 )pulumi stack export
- state インポート(
terraform import
相当)pululmi import <TYPE> <NAME> <ID>
- state 削除(
terraform state rm
相当)pulumi state delete <URN>
Terraformからの移行
Terraformからの移行オプションは以下の通りとなります。
- terraformとPulumiを共存する
- Pulumiからtfstateを参照する
- tfstateからリソースをPulumiへインポートする
- TerraformのコードをPulumiのコードに変換する
参考: Adopting Pulumi | Pulumi Docs
参考: Migrating from Terraform | Pulumi Docs
TerraformとPulumiを共存する(tfstateを参照)
networkリソースに関しては既存のterraformを使いつつ、そのoutputをPulumiで使うイメージになります。 以下のようなコードでlocalのtfstateが参照できるので、値を参照して利用することができます。
import * as aws from "@pulumi/aws"; import * as terraform from "@pulumi/terraform"; // Reference the Terraform state file: const networkState = new terraform.state.RemoteStateReference("network", { backendType: "local", path: "/path/to/terraform.tfstate", }); // Read the VPC and subnet IDs into variables: const vpcId = networkState.getOutput("vpc_id"); const publicSubnetIds = networkState.getOutput("public_subnet_ids"); // Now spin up servers in the first two subnets: for (let i = 0; i < 2; i++) { new aws.ec2.Instance(`instance-${i}`, { ami: "ami-7172b611", instanceType: "t2.medium", subnetId: publicSubnetIds[i], }); }
tfstateからインポート
pulumi import --from terraform ./terraform.tfstate
のようにすることによってtfstateからリソースをインポートすることができます。
terraformからコード変換
pulumi convert --from terraform
コマンドを使用することで、既存のTerraformのコードをPulumiのコードに変換することができます。
ただし、変換できないコードはTODOコメントが付く。90%~95%は変換が対応しているとのこと。
pulumi convert --from terraform --language typescript
まとめ
Pulumiの概要と基本操作をTerraformと対比しながら説明してきました。
- 新規プロジェクトである程度複雑な処理をしたい。
- プログラミング言語に精通している人がメンバーにいる。
そういった場合にはPulumiは良さそうに思えます。
しかしながら、ある程度Terraformで出来上がっているプロジェクトをPulumiに移行するのはそれなりに大変なので、プロジェクトの規模感とコストに見合うかを考えて導入するか考えると良いでしょう。
また、複雑なことをしたいというのは、本当に必要とされていることなのでしょうか?冗長でも簡易的な書き方をした方が望ましい場合もあるかと思います。そのあたりの目利きをちゃんと考えたいところです。
自分自身まだまだ使いこなせていないですし、追いきれてないPulumiのトピックもあるので、今後も選択肢の一つとして調べていきたいところです。