運用における成功1 プロジェクトに関わるリソースを可能な限りCDKで管理した

吉川幸弘氏(以下、吉川):ではアジェンダの2点目、これまでの運用における成功と失敗について。

まず成功したこと。プロジェクトに関わるリソースを可能な限りCDKで管理したことです。

これはちょっと比較するにはズルいかもしれませんが、Excel手順書でリリースを作業していたプロジェクトと、CDKを用いた今回のプロジェクトで、リリースコストを比較してみました。

昔、Excel手順書を利用したプロジェクトに携わったことがありますが、レビュー対象は手順書のExcelで、実際の手順はレビュアーに判断基準を一任していたため、何が正しいかが文書化できなかったり、実際に行われる操作が手順書以外だったり、レビューコストがかなり高いという問題がありました。

また、リリース作業は手作業だったため、作業者が作業を誤る可能性も拭いきれませんでした。ほかにも、緊急対応として履歴に残らない操作がその場で行われる可能性もありました。このように、リリース作業におけるメンバーの負荷が高かったことを覚えています。

それに対して、CDKを導入した今回のプロジェクトでは、レビュー対象はソースコードになります。また、事前にテストやデプロイをすることによって、再現性を確認することができます。そのうえ、CloudFormationとは異なり、CDKはコードが簡潔になっているため、レビュアーのレビューコストもかなり低かったです。

リリース作業は、自動化されたCI/CDによるデプロイにより手作業がなくなるため、ヒューマンミスを排除できました。また、こちらもIaCの特徴ですが、過去の対応をすべてGitの変更履歴に残すことで、あとから対応を追うこともできました。そうしたことが、プロダクトとメンバー、両方を守ることにつながりました。

運用における成功2 メンバーのスキル習得ルートの具体化を実現できた

吉川:次に、メンバーがスキル習得ルートを具体化できたこと。こちらも大きかったです。

そもそもですが、経験者の採用は難しいと感じていました。私のやっていたプロジェクトは規模の問題上、フロントエンドもバックエンドも両方対応できる人が必要でした。フロントエンドはTypeScriptで記述されており、バックエンドはGoで記述されているため、両方の経験者を探すのはかなり難しかったです。

また、ビジネス上いくらでもお金が出せるわけではないため、まずそういったスキルを持たない方を採用して、誰でもスキルアップできる環境を作ることが大事だと考えました。

実際にスキルアップできる環境作りですが、先ほど説明したTypeScriptとGoに加え、さらにInfrastructureのAWSの知識も必要となるため、どういった順序で覚えてもらったらいいのか、それぞれの知識を他の知識の習得に活かせないかを考えました。その時に、CDKは複数言語で記述できるため、言語間のクッションになっていることに気づきました。そこから私は、段階的成長のストーリーを作成しました。

これは段階的成長をイメージした図です。プロジェクトにアサインされたメンバーがスキルを持っていないとします。まずはフロントエンド開発を経験することで、TypeScriptの知識を得てもらいます。

次に、そのフロントエンドのCDKをメンテナンスして、AWSとCDKの知識を得てもらいます。次にGoで記述されたバックエンドのCDKをメンテナンスしてもらいます。私のプロジェクトではCDKをGoで記述しています。

なお、CDKのGoはまだ開発者プレビューなので、本番利用する際は厳重に注意してください。このようにCDKを利用することにより、同じインターフェイスでの言語間の違いに焦点を当てて学習することができました。

最後に、バックエンドのGoのメンテナンスをしてもらうことで、メンバーのスキル習得ルートの具体化を実現できました。

運用における失敗 初期にスナップショットテストを入れていなかった

吉川:逆に失敗したことを説明していきます。

過去にAPI Gateway V2を含むAPIプロジェクトを持っていた時の運用の失敗ですが、初期にスナップショットテストを入れていなかったことです。

CDKのバージョンアップをした際、デフォルトオーソライザーの実装が変更されたことにより、APIの呼び出しがすべて失敗するようになってしまいました。CDKの単体テストだと我々が期待値として掲げていた内容に含まれていなかったため、検知できませんでした。

幸いE2Eテストで検知できましたが、これが大きな教訓となりました。みなさん、スナップショットテストは必ず入れましょう。CDKを使う際は必ず入れてください。

ここに関して先ほど亀田さんも紹介されていましたが、V2以降における実験的モジュールの扱いが変わっています。これは私の資料の中で、唯一CDK V2に触れる部分です。

先ほど問題になったAPI Gateway V2は、実験的モジュールと言われるものでした。この実験的モジュールの扱いはV2で変わっています。具体的には、V1では安定モジュールと実験的モジュールが@aws-cdkパッケージに混在していましたが、V2ではこれが分離しています。

安定モジュールはaws-cdk-libパッケージ、実験的モジュールは末尾にalphaと付くパッケージに分けられたことにより、開発者が意図せず実験的モジュールを使用する可能性がなくなりました。それでもみなさん、スナップショットテストは必ず入れてください。

開発のポイントとおすすめの機能

吉川:ではもう時間がありませんので、最後にプレカンファレンスでいただいた質問を紹介していきます。

「RUMのように、L2 Construct開発は必須ですか」という質問です。構成次第だと思いますが、よくある構成だと今は必要ないと思っています。初期のL2実装は多くありませんでしたが、今はかなりのL2 Constructがそろっており、L2 Constructを使用するだけで、簡単なアプリケーションの構築を実現できます。

次に、「どんな粒度でスタックを分割していますか」という質問です。私のプロジェクトでは、基本的にスタックを分割しません。例外的として、API Gatewayのようにリソース数が多い場合、もしくは、RDSのようにアプリケーションと別のライフサイクルで管理したいという理由がある時だけ、分割をしています。

最後に、CI/CDの構成について紹介していきます。我々のプロジェクトでは、GitLab CIを利用しています。その時のポイントについて、次のスライドで説明していきます。

我々のプロジェクトでは、まずGitLab Runnerをセルフホスティングしています。これはAWS上に構築しており、これもCDKで管理しています。CDKで管理するEC2も、かなりお手軽でした。また、常設しているのは真ん中に見える管理用のRunnerのみにしており、T4G.microを使用することで、コストをかなり抑えています。

画面右側に見えるこれらの実際のタスクを処理するRunnerは、ゼロ台からX台でスケールしており、RunnerをIAMロールごとにタグ付けしています。このようにグルーピングをすることによって、コストと権限を最適化しています。

デプロイのポイントですが、我々のプロジェクトではタグ付けトリガーにおいてデプロイをするようにしています。こうすることによって、複雑なブランチ運用を排除しています。また、タグを付ける際にリリースすることでリリースノートを自動生成し、過去の対応について参照性をよくしています。

環境ごとの差は環境変数で注入するようにしています。(スライドの)左側の画面下のコードのように、環境変数をスタック名に利用することによって、シングルアカウントの場合でも重複を回避しています。

また、環境変数を利用する際、ベストプラクティスにも記載されていますが、スタック内で直接参照せず、Propsを用いてアプリケーションのトップレベルから渡すことが重要です。

ほかにも、おすすめのポイントとして、GitLab備わっているReview Appsという機能を紹介します。これは、マージリクエストをする際に、マージリクエストごとに一時的な環境をデプロイできる機能です。こうすることで変更内容の事前検証ができます。CDKやCloudFormationといったリソースは、実際にデプロイをするまで成功するかどうかわからないという唯一の弱点がありましたが、そういった弱点をカバーします。

また、EC2のようにプロビジョニングをしている間に課金が発生してしまうものに対して、時間制限を設けることでコストカットをしています。

前回プレカンファレンスで紹介したRUMのようなリソースは自動化テストが難しいですが、このように環境ごとに一時的な環境を用意する、デプロイすることで、そういった自動化できない部分のテストにも重宝しています。

最後に、CI/CDの知識を持つメンバーがいない場合におすすめする、CDKパイプラインについてお話しします。

CDKパイプラインとは、CodePipelineの高度なConstructです。CDKアプリをデプロイすることに特化しており、自身を動かすパイプラインを、そのCDKアプリの中に定義することが特徴です。右のサンプルをご覧ください。このように、アカウントのIDを指定することで、マルチアカウントによるデプロイも簡単にできます。

CDKで実現できたこと

吉川:最後に、ここまで実現できたことについて振り返ります。

まず、初心者でも素早くIaCを導入できたこと。AWSの世界に楽しく入門できたこと。初心者が作ったようなプロジェクトでも、3年目になっても運用が苦になっていないところ。RUMのように、新しいAWSサービスのスムーズな導入。

これらができているのは、すべてCDKのおかげだと私は考えています。AWSもIaCも始めたい方、まずCDKからスタートしてみてはいかがでしょうか。以上です。ありがとうございました。

質疑応答

吉田真吾氏(以下、吉田):はい、ありがとうございました。

新居田晃史氏(以下、新居田):ありがとうございました。

藤井貴昭氏(以下、藤井):ありがとうございました。

吉田:すばらしいです。なぜCDKを使わなきゃいけないのかとか、それで何が解消するのかとか、みんなよく理解できたと思います。

吉川:ありがとうございます。

吉田:質問が来ていますね。「さっきコード補完をしていたのはどのプラグインですか」という話だと思うんですけど。

吉川:拡張機能は、VSCodeの標準の機能だと思います。特に追加の機能は入れていません。また、どんな拡張機能を入れているかですが、私の場合は、VSCodeのRemote DevelopmentおよびRemote Containersというものを使用して、みなさんに運用だけでなく、開発環境の作成も自動化してもらっています。こんな感じでよろしいでしょうか。

吉田:なるほど。ありがとうございます。

藤井:次の質問です。「サーバーレスフレームワークのローカルテストのように、CDKでAPI GatewayとLambdaをローカルテストしたい場合は、どのようにされていますか」という質問です。

吉川:私はCDKを導入する際に、AWSのSAM、SAM CLIも同時に並行してテストしていたのですが、CDKのリポジトリにも同様の質問がありました。

その際に、ローカルではやはりLambdaは単体テストとして実行し、API GatewayとLambdaを実行する際は、ローカルではなくAWS上にデプロイして確認することを強く推奨すると答えられていたため、私はローカルでは単体テストレベル、または結合テストレベルといったところに留めています。答えになっていますか(笑)。

藤井:理解できました。ローカルでもやりつつ、最終的にはAWS上でテストをしてくださいという話ですね?

吉川:そうです。

吉田:まずAPI GatewayのURLが出てこないと、HTTPS経由で叩くの、難しいですもんね。やり方は僕もわからないですね。他でローカルでやる伝(つて)。ローカルホストにAPI Gatewayっぽいものを立ち上げるのかという話ですもんね。

吉川:CDKのカンファレンスのあとのほうにSAMについて触れられている部分があったので、もしかしたらそのセクションで有益な情報が得られるかもしれないですね(笑)。ありがとうございます。

藤井:たぶんroleの権限とかも、ローカルでやる時とAmazon上でやる時で違うと思うので、そこらへんも踏まえて使い分けかなとは思います。

吉田:ああ、そうですね。ついていないと結局API Gatewayから叩いて、なぜか502 Bad Gatewayが返ってくるあるある(笑)。

吉川:(笑)。

吉田:ありますもんね。ちょっとそこの使い分けは後ほどまた聞きましょうか。そろそろ時間なので、いったんここまでとしたいと思います。追加で質問があったら、Twitterでまた反応していただければと思います。ということで、ゆっきーさん、ありがとうございました。

吉川:ありがとうございました。