こんにちは。InflabのDevOpsエンジニア、SunBです。
今回は、AWS CDKからTerraformへの記事で取り上げたAWS CDK/Terraform、そしてINFCON 2022で発表したTerragruntを経て、Pulumiに落ち着くことになったInflabのIaC構築記をお話ししたいと思います。
今回のPart 1では、Terragruntを離れ、再び新しいツールに移ることになった背景と経緯、そして今度こそ定着できると考えている理由をお話しします。
IaC?
まず、この記事で初めてIaCに触れる方のために、IaCを簡単に紹介し、InflabのDevOpsチームがなぜIaCをこれほど重視しているのかをお話しします。
IaCはInfrastructure as Code(コードとしてのインフラ)の略で、コードによってインフラを管理することを意味します。IaCは、インフラ管理を自動化するさまざまな方法の中でも、ソフトウェア開発方法論などソフトウェア開発のための数多くの技術やツールをインフラ管理に適用できるようにするため、特に強力な方法だと言えます。
私がInflabに入社した2021年9月の時点では、Inflabのインフラ構成はメインサービスのコンテナとRedisキャッシュ、PostgreSQLデータベース、いくつかのLambda関数程度で、それほど複雑ではありませんでした。また、変更が発生することも多くなかったので、当時のインフラ構成作業はほとんどがWebコンソールから手動で行われており、一部のリソースだけをAWS CDKで構成している状態でした。
しかし、2021年末からRallitの開発が始まると、インフラ構成の業務が急速に増え始めました。
当時の私はDevOpsとしてInflabに入社したばかりで、チーム内の非効率を技術で解決しようと意気込んでおり、2年以内に次の2つを作ることに集中していました。
- 専門知識がなくてもメンバーが高度な自動化を自ら構築できるよう支援する、うまく抽象化された信頼できるパイプラインシステム
- メンバーが方向性の設定やモチベーションに活用できるあらゆるデータを、一貫した方法で収集・可視化するモニタリングシステム
いくつか調査した結果、短期間でこれらの目標を達成するのは難しいという結論に至りました。同時に、達成するには、第一に個人ではなくチームとして効率よく連携できること、第二に明日は今日より効率よく働ける環境が整っていることが欠かせないと考えるようになりました。
つまり、試行錯誤で得た情報をその場限りで活用するだけでなく業務フローに反映し、メンバーの努力を着実に積み重ねていける仕事の進め方を土台にすべきだと考えたのです。
そこで、急ぎの業務を除くほとんどの時間と労力を仕事の進め方の改善に投資することにしました。IaCの導入は、その中でも最も中核となる施策でした。
このとき考えていた、目指すレベルのIaCは次のようなものでした。
- 特別な場合を除いて、すべてのインフラ構成をIaCで行える。
- チームで一度構築したことのある構成のインフラは、誰でも簡単かつ迅速に再構築できる。
- インフラ構成の要件を満たしているか、社内ポリシーを遵守しているか、構成ミスがないかは、一次的には人ではなくコンピューターが確認する。
実のところ、導入を試み始めた当初は、こうした考えは身の丈に合った技術の範囲を超えた、行き過ぎた技術的こだわりなのかもしれないと思っていました。
しかし、私たちのチームはこうした技術的な試みに比較的オープンでした。何より、これが実現すれば得られる実質的なメリットは本当に大きいと確信していたので、少なくともできるところまではやってみようと、できる限り時間をひねり出してさまざまな実験をしました。
現在は開発チームが複数の目的別チームに分かれ、インフラ構成が非常に複雑になりました。さらに目的別チームとは別に、検索機能・動画処理・字幕機能などの作業も並行して進んでおり、構成作業が爆発的に増えています。こうした状況を見ると、準備をしておいたのは正しい選択だったと思います。
まだテストの自動化やデプロイパイプラインの構築など、いくつかの作業が残っていますが、インフラのポリシーや試行錯誤で得たノウハウを書き留めておいて一つひとつ探していた頃とは比べものにならないほど、速く正確にインフラを構成しています。
Terraform、Terragruntで実現できなかったこと
AWS CDKからTerraformへの記事とINFCON 2022の発表では、私たちがAWS CDKをやめてTerraformを使うことにした決定的な要因として、CloudFormationレイヤーの存在によるDriftの検出と解決の難しさを挙げていました。
以下は2021年末にメンバーと交わした会話です。上記の問題のせいで、メンバーはすでにAWS CDKとIaCに強い不信感を抱いていました。
メンバー: Route 53のHosted Zoneはどうやってつなぎましたか?
SunB: AWS CDKでImportしてつなぎました。
メンバー: えっ??? いや、削除されたらどうするんですか???
SunB: なんで削除されるんですか…?
幸い、Terraformを使い始めてからは、IaCがやると言った動作だけをすると信頼できるようになり、仕事の進め方の土台として使える段階になったと考えました。
しかし、Terraformにも物足りない点があり、中でもHCLというドメイン固有言語を使うという特徴に起因する、次のような不満を強く感じていました。
- コードを書く際にIDEの支援(自動補完、型ヒント、リファクタリングなど)を受けにくいこと
- 簡単な条件文を使うだけでもコードの可読性が大きく下がり、モジュールやスタックの目的が把握しにくくなること
- Terraformがサポートしていない場合、簡単な追加機能でも自分で実装して使うのが難しいこと
私たちはこうした不満を和らげるために、Terragruntを使ったラッパースタックパターン1で重複したコードを可能な限り排除し、Go言語ベースのTerratestでTerraformモジュールのテストを自動化しました。
これにより、各インフラスタックとモジュールの用途を明確にし、メンバーが修正する際に苦労しないようにしようとしました。
しかし、TerragruntとTerratestをもってしても、使い勝手の良いIaC環境を構築するには力不足でした。メンバーだけでなく私自身にとっても、IDEの支援なしにHCLのコードを行き来しながらインフラ構成を理解するのはあまりにも大変でした。また、Terratestは実質的にGo言語でTerraformスタックを実行するツールにすぎず、コードの単体テストができなかったうえに、結合テストだけですべてのインフラ構成をテストするには時間がかかりすぎました。
IDEの支援がない中でTerragruntを使って進めたDRY化は、かえってプロジェクト構成を分かりにくくしてしまいました。
そのほかにも、悪名高いnode_modulesに匹敵する.terragrunt-cacheのディレクトリ構造と遅い動作速度は、スタックやモジュールの依存関係をもっとうまく管理する方法はないかと考えるきっかけになりました。
さらに、Terragrunt run-allの出力がスタックごとに混ざって読みにくかったことや、AtlantisベースのCI/CD構築がさまざまなバグのせいで想定より長引いていたことなどが重なり、INFCON 2022で発表してから間もなく、TerragruntベースのIaC構成に疑問を感じて代替案を探し始めることになりました。
そんな中、2022年8月末に『Infrastructure as Code, 2nd Edition』の韓国語翻訳版が出版されるという知らせを聞いて予約注文し、出版されてすぐに読みました。本当に運良く、当時の私にまさに必要だった内容ばかりが詰まった本で、IaCについて疑問に思っていたことや悩んでいたことに答えを出すことができました。
そしてこの時点で、満足できるIaC構成についてのより具体的な条件を定め、Pulumiを使ってそれを満たすインフラプロジェクトを構築し始めました。
Pulumiで得られたもの
- 汎用プログラミング言語ベース
- 関数など一般的なプログラミングの知識に基づいたインフラコードの抽象化
- パッケージマネージャー、テスティングフレームワークなど、その言語のエコシステムの活用
- 自動補完、型ヒントなどIDEの支援を受けながらの開発
- Slackへのメッセージ送信、カスタムロギング、シークレット値の読み込み、複合テストなど、思いどおりに拡張可能
- IaCを介さずに作成したリソースを、IaCに簡単にImportできること
- SaaSを使わずに、Amazon S3をStateの保存先として使うように構成
Pulumiで最初からすべてをうまく解決できたわけではありません。
Node/TypeScript環境で、パッケージマネージャー、モノレポ管理ツール、テスティングフレームワークなどを組み合わせてPulumiのIaCプロジェクトを構成する際には、想像以上に試行錯誤を重ねました(詳しくは後続の記事で取り上げます)。その過程で、ソースマップが正しく動作しないなど、さまざまな問題にも遭遇しました。
また、Pulumi自体にも次のような問題がありました。
- #2522 のように、Pulumi Cloud SaaSを使わないとStackReferenceを正しく使えない問題(現在は解決済み)
- Pulumi Automation APIをベースにスタック間の入出力を管理するようにしたものの、自動補完や型ヒントなどIDEの支援を受けられない問題
- スタックのテスト時に、スタックの設定値をモックしにくい問題
これらの問題は現在すべて解決済みです。どのような試みを経てどう解決したのかは、今後の記事で一つずつ詳しくお伝えする予定です。
これからしばらくはPulumiに腰を据えて、記事の冒頭でお話しした目標の達成に集中できると考えています。
現在のIaC構成が上で述べた条件を満たせたことも理由の一つです。加えて、今後どんな要件が出てきても、TypeScriptという汎用プログラミング言語なら解決できるという確信があります。Pulumi自体に問題が起きない限り、別のツールに乗り換えずに改善を続けていけそうです。
以下は、Terragruntを使っていた頃に切望していたことのいくつかです。
Pulumi Automation APIとTypeScriptのGenericsを活用して、コードのあらゆる箇所で自動補完と型ヒントが効くように構成しました。
Pulumi Mockをベースに、設定値やリソース構成に対する単体テストを構成しました。
テストフィクスチャのリソースを使い、最小限のコストでスタックに対する複雑な結合テストも構成できるようにしました。
Pulumiの実行はまだ一元化されたデプロイパイプラインに限定できておらず、各DevOpsエンジニアのPCで実行しています。そこで最低限の安全策として、誰がどのスタックを実行したのかをSlackに通知するようにしました。
シークレット値をAWS Secrets Managerから読み込んでキャッシュし、利用する仕組みを自前で実装して使っています。(Infisicalへの移行を検討しています。)
さらに、エラーメッセージなどを抽象化して、わかりやすく出力するように構成しました。
Nxを使って、単一のNodeパッケージ内でスタックとコンポーネント間の依存関係を管理しています。
続く記事では、興味のある方が実際に試せるように、Pulumi Automation APIベースのインフラプロジェクトの構成から、型ヒントを有効にするためのジェネリクスを用いたコード構成、Jestベースのテスト構成、Pulumi TypeScript vs Golang、Nxを使ったスタックの依存関係管理、スタックの命名規則、IaCの外で作成したリソースのCodegenとState Importの方法などについて、具体的に取り上げていきます。
余談ですが、2023年8月10日にTerraformのライセンスがHashiCorpによってMPLからBUSLに変更されたことで、オープンソースのフォークであるOpenTofuが登場するなど、Terraformのエコシステムが少し揺らいでいます。その影響を受けずに済むというのも、Pulumiへの移行による予想外のメリットだと思います。
結論
約2年間、InflabのIaCがどのような道のりをたどってきたのかについて、簡単にお話ししました。
今になって振り返ると、AWS CDK、Terraform、Terragruntを使い続けていたとしても、それぞれの短所を抱えながら最善の方法で使うやり方はきっとあったと思います。
それでも乗り換えを実行できたのは、より良い作業環境の必要性と可能性を強く感じていたこと、運良く適切なタイミングで考えを整理して明確な要件にできたこと、そして私たちの組織がそのニーズを満たすための挑戦を後押ししてくれるチームだったことが大きかったと思います。
今年からは、この2年間の準備を足がかりに、IaCのような基盤がなければ不可能だったさまざまな取り組みを進めていく予定です。
ありがとうございました。
※この記事は2024年2月1日に執筆されたものです。
-
パラメーター変数を使うスタックコードのモジュールが1つ存在し、このモジュールを参照して実際のパラメーター値を含むスタックプロジェクトが複数存在する形。(Kief Morris『Infrastructure as Code, 2nd Edition』、第7章「Configuring Stack Instances」) ↩




















