こんにちは。InflabのDevOpsエンジニア、SunBです!
Inflabに入社してから、毎日さまざまな楽しい経験をしています。今日はその中でも、コードとしてのインフラストラクチャ(Infrastructure as Code, IaC)に関するお話をしようと思います。
昨年11月まではIaCツールとしてAWS CDKを使っていたのですが、当時私を悩ませていた問題と、今はなぜTerraformを使うようになったのかをご紹介します。
コードとしてのインフラストラクチャ
私たちは、ユーザーに質の高いサービスを安定して提供するためにインフラを構成しています。素早い変化に対応しやすいよう、クラウド環境でインフラを構成しています。
多くのクラウドサービスプロバイダーは、顧客がインフラを素早く簡単に構成できるようWebコンソールを提供しています。おそらく小規模な組織や、クラウドサービスを導入したばかりの組織では、ほとんどのインフラをWebコンソールで構成していることでしょう。
しかし、組織やサービスの規模がある程度大きくなると、Webコンソールだけでインフラを緻密に構成するのは難しくなります。このような場合に導入を検討できるのが、コードでインフラを構成できるIaCです。
IaCを使うと、インフラ構成の段階で条件分岐や繰り返しを扱いやすくなり、バージョン管理、テスト、CI/CDなど、これまでサービス開発で使ってきた技術を同じように使えるため、ヒューマンエラーの防止や、多人数での同時並行の共同作業において有利になります。
私たちはクラウドサービスとしてAWSのみを使っており、サービス開発にTypeScriptを使っていたため、IaCツールとしてAWS CDKを採用していました。
AWS CDKから離れた理由
業務を進めるうえで使うツールを選ぶときは、さまざまな条件を検討することになります。
その中には「技術的にどれだけ進んだツールなのか?」や「誰がそのツールを作ったのか?」といった条件もあるでしょうが、最終的に選ばれるのは「今、この状況で最も役に立つツール」でしょう。
私たちがIaCツールに求めていたことは、次のとおりです。
- すでに多くの人が使っており、それゆえ多くの情報がインターネット上に公開されていること。
- 直感的かつシンプルで、応用や拡張がしやすいこと。
- 想定外の状況が起きても、柔軟に安定性を取り戻せること。
AWS CDKは、これらの条件を十分に満たしていませんでした。
ドキュメントとコミュニティ
AWS CDK Reference Documentation
AWS CDKの公式ドキュメントは、まだかなり不十分な状態です。
コードを書きながら必要な情報を探すのが大変でした。ときにはAWS DevOps Blogのようなところで良い記事が見つかることもありましたが、悩んだり検索したりすることに多くの時間を費やしても、正確なドキュメントや事例が見つからず、結論を出せないことがよくありました。
特に、これをTerraformの公式ドキュメントと比べると、品質にやや差があることが分かります。Terraformの場合、IntroドキュメントにTerraformに初めて触れる人が知りたい情報がよくまとめられており、Get Startedには、手順どおりに進めるだけでよいユーザーフレンドリーなチュートリアルが整理されていました。
書籍についても、TerraformにはTerraform Up & Runningという書籍があり、第2版の韓国語翻訳版まで出ているのに対し、AWS CDKを紹介する書籍はまだ見つけられませんでした。
AWS CDKは使っている人が多くないため、コミュニティから欲しい情報を得るのも簡単ではありませんでした。2つのツールに対する人々の関心や利用状況を正確に測ることは不可能ですが、2021年11月時点で公開されている情報をざっと数えてみると、次のとおりです。
- TerraformのGitHub Repositoryのスター数は30k
- Terraform AWS ProviderのGitHub Repositoryのスター数は6.5k
- Stack Overflowの検索結果数は26,929件
- 2016年から現在まで、Googleの検索指数でAWS CDKとPulumiを継続して大きく上回っている
それに比べると、AWS CDKの数値は比較的低めです。
- GitHub Repositoryのスター数は7.8k
- Stack Overflowの検索結果数は8,558件
Terraformが2014年、AWS CDKが2018年にリリースされたことを考えると、AWS CDKが爆発的に成長しているのは確かですが、少なくとも現時点でのコミュニティの規模はTerraformのほうがはるかに大きいと言えます。
現在、InflabにはDevOpsエンジニアの数が少ないため、ドキュメントがよく整備されていてコミュニティが大きいというTerraformの長所は、AWS CDKをTerraformに置き換えると決めるのに十分な理由でした。
参入障壁
Terraformでは、HCL(HashiCorp Configuration Language) という言語でコードを書く必要があります。
AWS CDKでは、TypeScriptやPythonなど、よく知られたプログラミング言語を使ってコードを書くことができます。
ただ、AWS CDKをPythonで使ってみようとしたことがあるのですが、JavaScriptおよびTypeScript以外の言語向けのAWS CDKライブラリは、各言語の特性を十分に反映して移植されたライブラリではなく、AWSが独自に開発したJSIIベースの互換ライブラリであるため、クラスの継承をアノテーションで行わなければならないなど、ぎこちない部分がある状態でした。そのため、AWS CDKを使うのであれば、言語にはTypeScriptを使うことをおすすめしたいです。
ドメイン固有言語であるHCLは別途学習する必要があるのに対し、TypeScriptは似た言語をすでに知っていればすぐに使えるため、AWS CDKのほうがTerraformよりも参入障壁が低いと考えることもできます。
しかし、それはあくまでスタート地点だけを考えた場合の話で、運用成熟度の4段階に到達するまでを考えると、むしろTerraformのほうがAWS CDKよりも参入障壁が低いと言えます。
HCLは文法やルールが少なく、応用するのも非常にシンプルな言語です。HashiCorpが公式に公開しているチュートリアルやサンプルだけでなく、多くのユーザーが進めているTerraformベースのプロジェクトをインターネット上で参考にできるため、良いTerraformのIaC構成は真似しやすいのです。
AWS CDKの場合、TypeScriptで書けるという点は、初期には慣れた感覚で作業できるというメリットになりますが、しっかりとした構造を作り、チームで共同作業する段階にたどり着くまでにはデメリットになります。
HCLは宣言的で複雑なロジックを受け付けないため、インフラの設計と構造の確立に完全に集中できますが、TypeScriptのAWS CDKでインフラを構成する場合は、インフラの構造とTypeScriptプロジェクトの構造の両方を考慮しなければならないため、多くの検討と試行錯誤が必要になります。
また、Terraformは多くの場合、コードと実際のリソースが1対1で対応する関係になるので、コードを見るだけで
実際のインフラがどのように構成されているかを明確に把握できます。
AWS CDKは、利便性のためにIAMポリシーなど一部のリソースを別途定義しなくても自動的に構成します。これはインフラを素早く構成しなければならない場合にはメリットとして働くこともありますが、結局はコードを見るだけでは実際のインフラがどう構成されているのかを正確に把握できないため、時間が経つほどデメリットになります。
そのため、AWS CDKはTerraformと違って事例が少なく、複雑なプロジェクト管理を必要とし、
自動で生成されるリソースが不明確なので、使い続けるのは難しいと判断しました。
IaCと現実の間のギャップ
Terraformは、以下のように自ら実際のインフラの状態を取得し、IaCコードとの差分を把握して実際のインフラ構成を変更する方式で、インフラをデプロイします。
...
aws_route53_zone.this: Refreshing state... [id=SECRET]
aws_vpc.this: Refreshing state... [id=SECRET]
aws_internet_gateway.this[0]: Refreshing state... [id=SECRET]
aws_subnet.private["0"]: Refreshing state... [id=SECRET]
aws_subnet.private["1"]: Refreshing state... [id=SECRET]
aws_subnet.public["1"]: Refreshing state... [id=SECRET]
aws_subnet.public["0"]: Refreshing state... [id=SECRET]
...
# aws_vpc.this has changed
~ resource "aws_vpc" "this" {
...
AWS CDKも全体的にはTerraformと似た方式ですが、重要な違いが1つあります。インフラの状態を取得して構成を変更する作業を、CDKが直接行うのではなく、CloudFormationが行うという点です。
つまり、AWS CDKではインフラのデプロイが必要になると、CDKのコードをCloudFormation Templateに変換してCloudFormation Stackとしてデプロイし、実際のインフラはこのCloudFormation Stackによって変更されることになります。
この構造は一見すると特に問題がないように見えますが、実は重要な2つの問題を引き起こします。
CDKから現実を追跡できない
1つ目は、CDKを経由しない実際のインフラの変更が、CDKに反映されにくいという点です。
まず、CDKでインフラの変更を確認するdiffコマンドを実行すると、CDKのコードと現在デプロイされているCloudFormation Templateとの差分がユーザーに表示されます。
重要なのは、このときCDKは実際のインフラの状態を取得しないということです。
実際のインフラの変更に気づく方法は、CloudFormation StackでDrift Detectionを実行する方法しかありません。CDKでインフラをデプロイするたびにDrift Detectionを実行するのは難しいでしょう。
しかも、検出したDriftをCloudFormation TemplateやCDKのコードに反映する方法はサポートされておらず、実際のインフラを変更前の状態に戻すことでDriftを取り除いて解決する方法しかサポートされていません。
すべてのインフラ変更をCDK経由で行うよう強制することも考えられますが、このような制約は想定外の状況が起きたときには守られない可能性が高く、またDriftには人が変更したものだけでなく、AMIの最新イメージIDのようなAWSがポリシー上起こした変化や、RDSのDBエンジンのマイナーアップデートのような自動で起きた変化も存在するため、Driftを完全に防ぐことは事実上不可能です。
こうしたCDKの特性は、インフラ管理を本当に難しくします。
CDKのdiff結果を信頼できない
2つ目の問題は、CDKが把握していないCloudFormationの動作が発生しうるという点です。
これは1つ目の問題とつながっているのですが、次のような状況を想定してみましょう。
- CDKでリソースを1つ作成し、ある引数の値が1でした。(この引数の値が大きくなるインフラ変更はリソースの再作成なしにin-placeで行われますが、引数の値を小さくするにはリソースの再作成が必要です。RDSのEngine Versionがその例です。)
- 時間が経つうちに、CDKを経由しないインフラ変更が発生し、そのリソースの引数の値が3になりました。
- 手順2の変化を知らない誰かが、CDKでそのリソースの引数の値を2に変更しようとします。
- CDKはCloudFormation Templateとコードの差分を報告するので、1から2になる正常なin-place updateとして表示します。インフラのデプロイを進めます。
- CloudFormationは、変更されたTemplateを処理するためにリソースの更新を行おうとします。
- 実際のリソースを確認すると引数の値は3で、変更後の値は2なので、リソースを削除して作り直します。
このように、CDKでは意図していない変更がCloudFormation側で起きることがあります。もちろん、CloudFormationが常に必ずReplaceを行うわけではありませんが、CDKが警告しなかった変更が、外部要因とCloudFormationの判断によって実行されうることは確かです。
インフラ管理者にとって、このようなことが起こりうるということはとてつもない不安をもたらします。
さらに、こうした状況についてリソースごと・引数ごとに定義したドキュメントのようなものはなく、あるときはCloudFormationがReplaceを防いでくれるのに、またあるときは有無を言わさずリソースを削除して作り直すなど……一貫性も見いだしにくく、なおさら困ることがよくありました。
さまざまなケースごとのCloudFormationの挙動を一つひとつ記録する方法もあったでしょうが、
それよりも、このような問題が最初から存在しないツールを使うことにしたほうがはるかに合理的だと考えました。
そのため、IaCと現実の間にCloudFormationが挟まっているという事実から、
AWS CDKを使い続けるのは難しいという判断に至りました。
おわりに
ここまで、InflabがAWS CDKからTerraformに移行するまでにどのような経緯をたどってきたかを見てきました。
現在は、上で述べた多くの悩みが解消された状態で、幸せにインフラのコーディングをしています。
また、この記事を最初に書いたときよりもTerraformについてさらに深く調べ、現在はTerragruntとTerratestをベースにしたモジュール化と自動テストまで導入しましたが、これについては次回、別の記事でご紹介したいと思います。
ありがとうございました。




