インフラのプロビジョニングは長い進化を遂げてきました。最初は物理的なハードウェアの設置から始まり、仮想化の登場でUI上の数クリックで済むようになりました。その後、クラウドプロバイダーがプロビジョニング用のREST APIを提供するようになり、現在ではコードによって環境のあるべき状態を宣言的に定義できます。こうしてInfrastructure as Code(IaC)が定着しました。代表例にはTerraform、Cloudformation、ARMテンプレートなどがあります。
Infrastructure as Codeの実情
Infrastructure as Codeは再現性に優れています。ヒューマンエラーを減らし、不変性(イミュータビリティ)を高めてくれるうえ、ドキュメントとしての役割も果たします。Terraformはインフラを段階的にプロビジョニング・変更でき、各実行後に状態(state)を保存します。しかし、エンタープライズ環境で本格的に使い込むと、その弱点が見えてきます。
まず、if文のようなロジックを組み込むのが難しい点が挙げられます。TerraformのHCLにも最終的にif文やforループが追加されましたが、HCLにとっての第一級の機能というよりは後付けの印象が拭えません。Infrastructure as Codeのフレームワーク自体には、ネイティブのテスト機能も備わっていません。HCL、Cloudformation、Azure Resource Managerテンプレートにはそれぞれ独自の学習コストがあり、各エコシステムへのロックインも生じます。
Pulumiという絶妙な落としどころ
一方、対極には主要なプログラミング言語向けのクラウドSDKがあります。大手クラウドプロバイダーはいずれもCDK(Cloud Development Kit)と呼ばれるSDKを提供しています。CDKはプログラミング言語の利点をフルに活かせる点で優れていますが、Terraformのような状態管理の概念がありません。状態管理があってこそ、インフラへの段階的な変更が扱いやすく、予測可能なものになります。
そこに登場するのがPulumiです。Pulumiはフル機能のプログラミング言語と状態管理の両方を兼ね備えています。
たとえば、複数のif条件を素のJavaScriptで書くと次のようになります:
switch (ostype){
case 'linux':
Userdata = userdata
break;
case 'windows':
Userdata = windowsuserdata
break;
}
同じロジックをTerraformのHCLで表現すると次のようになります:
Linux = var.ostype == "linux" ? true : false
Windows = var.ostype == "windows" ? true : false
ご覧の通り、HashicorpのHCLよりも、誰もが慣れ親しんだJavaScriptの記法のほうが圧倒的に読みやすくなっています。HCLはドメイン固有言語であり、汎用言語のような柔軟性は持ち合わせていません。だからこそ、汎用言語を使うことで、Infrastructure as Codeにより高度なロジックを盛り込めるのです。
Pulumiは、ソフトウェア開発ライフサイクルのその他のメリットももたらします。テスト駆動開発、継続的インテグレーション、バージョン管理されたリリース、パッケージ管理などです。
これにより、アプリケーションのソフトウェアとインフラのソフトウェアを並べて扱えるようになります。同じプログラミング言語で書かれた両者を、ひとつのGitリポジトリで管理することも可能です。
Pulumiのコンセプト
Terraformにはprovider、module、stateといった概念があります。同様に、Pulumiもこれらの概念を再構成し、シンプルにまとめ直しています。
Stacks(スタック)
スタックとは、同じ環境変数を共有する関連インフラリソースの集合です。dev、stage、prodといった環境に近い概念で、各スタックはそれぞれ異なる環境変数のセットを持ちます。これらの変数は「Pulumi.dev.yaml」「Pulumi.stage.yaml」などで個別に定義します。
Projects(プロジェクト)
プロジェクトとは、スタックを内包するインフラリソースを論理的に分離したグループです。チーム単位、施策単位、あるいはインフラの種類(コンテナ、サーバーレス、ネットワーキングなど)で対応付けられます。どのようなグルーピングが組織に適しているかは、解釈の余地があります。
Backends(バックエンド)
バックエンドは、Pulumiの実行状態を永続的なストレージに保存する仕組みです。バックエンドにはいくつかの種類があります:
1. サービスバックエンド: Pulumi Cloud(SaaS)、またはセルフホスト版のPulumi。サービスバックエンドの利点は、インフラのスナップショットを定期的に取得できる点です。これにより、プロビジョニング中に致命的なエラーが発生しても、ロールバックや復旧が容易になります。
2. 自己管理型のオブジェクトストレージ(AWS S3、GCP GCS、Azure Blobなど)。
Providers(プロバイダー)
Pulumiは複数のプラットフォーム上でインフラやサービスをプロビジョニングできます。現時点でAWS、GCP、Azure、Kubernetes、Cloudflareをはじめ、多数のプロバイダーに対応しています。
付録
比較表

次回予告
本記事の第2部では、自律的なチームがアプリケーションと共に自分たちのインフラをプロビジョニング・運用できるようにする、Pulumiの高度な機能を取り上げます。さらに、AWS上にEKSクラスターをプロビジョニングするコードベースも紹介する予定です。「Hello World」レベルにとどまらず、ハードニングや本番運用への備えを盛り込んだEKSクラスターです。どうぞお楽しみに!
最新情報は DoiT Engineering Blog 、 DoiT LinkedInチャンネル 、 DoiT Twitterチャンネル でご覧いただけます。採用情報は https://careers.doit-intl.com をご確認ください。
HCLと汎用プログラミング言語の言語仕様を細かく比較すれば、技術的にそれほど大きな差はないかもしれません。しかし、同じ結果を得るために、十分に成熟し広く使われている汎用プログラミング言語と、ベンダー独自の新しいドメイン固有の宣言型言語とを選べるなら、わざわざ知名度の低い方を選ぶ理由があるでしょうか。HCLでも汎用言語でも、仕事はこなせます。ただ、汎用言語を取り巻く確立されたエコシステムや、市場で確保しやすい人材のことを考えれば、TerraformよりもPulumiのようなフレームワークを採用するのが理にかなっていると言えるでしょう。