大規模プロジェクトにおける基盤の構成管理を開発状況に合わせて抜本的に見直した話

はじめに

こんにちは、エス・エム・エスの小笠原です。以前2つのカイポケSREチームを兼務している話を紹介しましたが、現在はカイポケリニューアル側のSREを担当しています。

今回は介護/障害福祉事業者向け経営支援サービス「カイポケ」の開発におけるSREの活動事例として、基盤の構成管理を抜本的に見直した話を紹介します。

リニューアルプロジェクトの概要

最初に私が関わっているカイポケリニューアルプロジェクトについて簡単に紹介します。

このプロジェクトは継続的な事業成長を目的としてサービスの安定性やプロダクトの優位性を高めることを目的とした「新カイポケ」の開発プロジェクトで、2021年に始動しました。

アーキテクチャから見直し、「拡張性」・「スケーラビリティ」・「開発並列性」をキーワードにした「新アーキテクチャ」を設計し、開発を進めています。

私もこのプロジェクトに2022年の年末ごろからSREとして開発に携わってきました。

プロジェクト開始時の基盤開発の方針

最初にプロジェクト開始時の基盤開発の方針について説明します。プロジェクト開始当初、開発メンバーの中でインフラを専門として動くメンバーは1人だけでありかつ、他部署の業務を一部兼任している都合もあり、SREとして一般的に期待される仕事をすべて担うにはリソース不足でした。

一方、アプリケーション開発を主に行うチーム(以降、アプリ開発チーム)には元インフラチームのメンバーや基盤開発に知見のあるエンジニアが複数人いたこともあり、基盤の開発・管理をアプリ開発チームとSREの間で以下のように担当分けする方針が敷かれました。

プロジェクト開始時点の管理範囲

土台となるAWSアカウントを始め、全体のネットワーク設計(VPCやsubnetなど)や横断で利用されるリソースをSREが管理し、それ以外のリソースはすべてアプリ開発チームで面倒を見るという役割分担です。

この役割分担を前提として、技術スタックについて開発チームの管理範囲はAWS CDK(以降、CDK)を、SREチームの管理範囲はTerraformを採用することになりました。

技術選定の背景

アプリ開発チームでCDKを採用したのには大きく3つ理由があります。1つ目はアプリ開発チームで基盤開発を主導していたメンバーがCDKに習熟していたこと。2つ目は使い慣れているプログラミング言語であるTypeScriptで開発できること。3つ目はSecurityGroupの設定など基盤の詳細について抽象化されていて基盤に詳しくないエンジニアにとって扱いやすいことです。これらは開発速度を上げるうえで大きな優位性になると考えていました。

一方、SREチームでTerraformを採用した理由は運用時の細かな取り回しの良さと規模の拡張に対応しやすいと判断したためです。特にSREが担当するレイヤ(AWSアカウントやネットワーク基盤など)の運用ではこの性質と相性が良いと考えました。

AWS CDKとTerraformの連携と拡張方針について

CDKとTerraformは以下のようにParameter Storeを介してそれぞれの世界を接続させる形で連携することにしました。

CDKとTerraformの連携

リソース間に依存関係があるため、以下の順番で構築を進めることになりました。

  1. SREがTerraformでネットワークリソースを作成する
  2. CDKで参照したい定数をTerraformを使ってParameter Storeに作成する
  3. 開発チームで定数を参照してサービスごとのAWSリソースをCDKで作成する

両者の責任分界点は明確なため、あとは各チームがそれぞれの担当するCDKのstackやTerraformのroot moduleを適切な粒度に分割・管理していけば将来的なシステムのスケールに対応できると考えていました。

開発初期は見立て通りうまく開発できた

開発初期からしばらくの間は基盤開発の状況は良かったことを覚えています。特にアプリ開発チームにおけるCDKを利用した基盤開発は以下の点でよく機能していました。

  1. 開発者が抵抗なく基盤開発に貢献できる
    • TypeScriptで書かれた豊富な実装例
    • コードの書き味の良さ
  2. 試行錯誤のしやすさ
    • cdk deploy → cdk destroy で片付けが簡単
    • 個別のAWSリソースの詳細について深く考えなくて済む
      • 詳細が抽象化された構成セット(construct)が公式から多数提供されており、それを少し修正するだけで基盤構築ができる
  3. アプリ開発者だけで開発を進められる
    • レビューをすべてアプリ開発チーム内で済ませられる
      • 当時は基盤の構成や設定をレビューできるメンバーが限られており、レビュー待ちが発生することが多かったのですが、アプリ開発チーム内でレビューを完結させることでスムーズに開発を進められることが大きなメリットと認識されていました

この点についてはアプリ開発チームでは当初期待していたCDKのメリットを享受できていたと言えそうです。SREとしてもアプリ開発チームが自立して基盤の構築・管理のタスクを進めてくれるため負担が少なく助かっていました。

開発中盤からCDK開発に暗雲が立ち込めた

一方で、開発が中盤に差し掛かる段階でCDK開発に暗雲が立ち込めます。具体的には本番環境を作り始める頃に様々な課題が見えてきました。特に大きかったものは以下です。

  1. デプロイが一大イベントになった
    • 一回のcdk deployにすべての変更を押し込めた結果、アプリのデプロイと構成変更が同時に実行されるデプロイフローになってしまいました
    • アプリの変更と構成変更が同時に行われることでデプロイ時の事故が起きやすくなったりstack更新のオーバーヘッドでデプロイ時間が全体的に長くなりました
  2. CDKで状態を持つリソースの管理がうまくできなかった
    • 状態を持つリソースに関してstackの更新処理が途中でコケた際にエラー原因が特定できず、困ったらcdk destroyして作り直すという対処をしていました
    • これは本番系では許容できない解決方法ですが、CloudFormationのトラブルシューティングが難しく、一つ一つ適切に対処することができませんでした
  3. CDKで作られるAWSリソースの品質が本番に持って行くには不安があった
    • 例えばSecurityGroupの作り方に不備があり、意図した通りのアクセス制限が行えてないといった不備が見つかることがありました
    • PRのレビューでは正常系の確認が主で、作成される実リソースの詳細に関するレビューはおざなりになっていました

多くの課題はCDK開発の知見を深める施策(技術的な投資)を増やせば解決できる可能性はあったものの、プロジェクトのボトルネックがアプリケーションの機能開発にあったこともあり、なかなかそちらにリソースを振ることも難しい状況が続いていました。

また、この問題に拍車を掛ける形で、アプリ開発チームでの基盤開発を主導していたメンバーの離脱があり、CDKの技術課題解決の推進力が大きく損なわれる事態になりました。

長期のプロジェクトなのでメンバーの入れ替わりがあることは仕方のないことなのですが、抜けた穴を補填できない状況ができたことは特に大きな問題でした。

基盤の開発・管理の立て直しを行うことになった

多くの課題が認識されるなかで基盤の開発・管理に関して抜本的な改善を図ることにしました。

愚直なアプローチとしては基盤開発の責務を現状維持しつつ、SREチームがCDK開発の課題解決に助力するという方法が考えられました。当時のSREチームは私が参加して二人になっていたこともあり、その選択肢もあり得たと思います。

しかし、SREチームには(開発の中で知見はある程度溜まっていたものの)本番系でのCDKの運用知見が少なく、またCDKのバックエンドであるCloudFormationをうまく扱っていくには相応の学習コストが必要なことが見えていました。

そして、今後基盤開発の課題の多くをSREチームが担っていくことを考えると、CDKとTerraformの2つの技術スタックを無理に維持していくよりは、SREが運用知見を多く持ち合わせていて既に基盤も整っているTerraformに統一していく方が効率的で、かつ将来のスケールにも対応しやすくなると考えました。

そこで、基本的に基盤の運用管理の責務をSREチームに全面的に移譲して、かつ技術スタックも統一していく方針で立て直すことが決まりました。

基盤の開発・管理の責務を全面的にSREに移した

役割としては以下のように基盤管理のほとんどをSREが担う形に変更しました。構成管理ツールはTerraformを主体に据えました。

プロジェクト中期の管理範囲

ただし、アプリケーションのデプロイについては構成変更と分離するためにecspressoを利用し、一部のAWSリソースはアプリ開発チームが手を入れやすいようTerraformのroot moduleを分ける工夫を行いました。

当時、サービスリリース前ではあったものの、多くのAWSリソースがCDKで構築・管理されていたため、CDK stackを段階に分けて少しずつTerraform化する対応を行いました。

結果

ツールの移行は開発に支障が出ないように段階的に行ったこともあり、全体で数ヶ月かかってしまいました。

移行期間中は基盤リソースが一時的に多重化されてコストがかかったり、デプロイ時間が遅くなったり過渡期の問題はある程度発生しましたが、移行を終えることによりそれまで抱えてきたCDKの技術課題を一気に解消することができたのはプロジェクトにとって中長期的な目線で大きなメリットを与えることができたと考えています。

移行後、顕著に改善できた点は以下です。

  1. デプロイを高速化できた
    • デプロイ時間を当初の約半分程度に削減できました
  2. デプロイ時の事故が減った
    • 構成変更とアプリのデプロイを分離することで事故が少なくなりました
  3. 基盤構成のガバナンスを高めることができた
    • Terraform管理時のプラクティスをそのまま横展開することでガバナンスを強化できました
    • 大きな変更を入れる際にSRE(有識者)のレビューを入れることで品質の底上げがなされるようになりました
  4. 基盤に手を加えるオペレーションがしやすくなった
    • CDK(開発チーム管理のリソース)への影響を考えながらオペレーションを組む必要がなくなり、Terraformで構成管理する際のオペレーションを考えるだけでよくなりました

SREの動きやすさが大きく改善したことに加えて、デプロイの苦痛を減らすことができたことはプロダクト開発にとって地味ですが効果の大きな施策だったのではないかと考えています。

まとめと振り返り

大規模プロジェクトにおいてアプリ開発チームに基盤開発を任せる開発スタイルを試してみましたが、開発中盤でアプリ開発チーム単体での対応が難しい技術課題が増えたためSREに管理を任せる形に切り替えました。

この事例から得られる学びとしては、開発人員が多く期間の長いプロジェクトでは技術選定が当時の見立て通りにうまく進むとは限らないということです。

「最初からTerraformですべて管理していればよかったのではないか」という意見もあり、個人的にそれも一理あるなとは思います。しかし一方で、開発側にCDKの技術課題に取り組める人員を増やしたり、アプリ開発チームの中でCDK開発に関する知見を増やす取り組みに投資できていれば状況が大きく変わっていた可能性もありましたし、プロジェクト開始当初は基盤構成についてどのような形が良いかを開発チーム主体で機動的に模索したいという要望もあったりするなかで、Terraformからはじめる意思決定を最初から選択することは合理的ではなく難しかったと思います。

開発が進み、徐々に体制の変化や開発のボトルネックなどがわかってくる中で初めてこれまでの技術選定について振り返りや比較検討ができ、今後どうしていくのが良いかという確度の高い議論や意思決定ができたと考えています。

今回の事例を通して、先が読みにくい不確実性の高いプロジェクトでは完璧な技術選定よりは技術の評価や振り返りをしっかり行って、開発状況に応じて柔軟に技術の切り替えをすることが大切ではないかと感じました。

補足: CDKに関する技術的な所見

CDKに関して今回の事例を通して気付いた技術的な所見としては、小規模でシンプルな構成の基盤開発にCDKはよく向いているということです。

立ち上げまでの初速が非常に早く、スクラップ&ビルドしたいときにはうってつけだと感じました。TypeScriptの型情報にAWSのベストプラクティスが書かれていたり、強力な型補完の恩恵があるため非常に楽しく基盤開発に取り組めることができました。これはTerraformにはない開発体験でした。

一方で、規模が大きく複雑な要件の求められる基盤開発で使っていくには相応の技術的投資が求められるため、構成変更を頻繁にいれたくなるようなメインのサービス・システムの管理には入れたくないと感じました。

特にCDKで細かくスタック分割したくなるときに運用・メンテコストが跳ね上がるように見受けられました。スタック分割をうまく行うにはL1 constructをはじめとしてCDKやCloudFormationの独特の設計や扱い方に習熟する必要があるのですが、これが非常に厄介なためです。

もちろん、ツールに深く習熟してさえいればどちらを使っても構わないのでしょうが、そうではない開発メンバーが多いプロジェクトの場合はツールの特性を理解して導入していくことが大切だと思いました。