selmertsxの素振り日記

ひたすら日々の素振り内容を書き続けるだけの日記

チームみんなが参加しやすくなるIaC設計の工夫

モチベーション

私は「インフラ」という言葉は、人によって受け取り方が大き違う言葉だと思ってます。 「よく分からないけど責任が重いので出来れば触りたくない」という人や、「本質的に難しいものなので訓練された人にしか触らせたくない」という人、 「IaaS、PaaSはインフラと認めない!」という人にも会ったことがあります。

「よく分からないなんとなく難しいもの」である「インフラ」は、多くの人に敬遠されがちなので、 中小規模の開発組織では1人のエンジニアがひっそりと孤独に作ってるケースがままあるのではないでしょうか。 私も3年間ほど、やりたがる人がいない...という理由でPMとインフラエンジニアを兼務してきました。

この記事では、一人でひっそりとインフラを作ってた私が、 それでもなんとか触れる人を増やしたいと思って工夫したIaC設計のアイデアを記述しようと思います。

言葉の定義

インフラ

IaCで扱う「インフラ」の定義について。 言葉の定義を探していくつか書籍を漁ってみましたが、なかなかコレといった文書を見つけられませんでした。

OSを作るようなソフトウェアエンジニアからすればマシンそのものがインフラですし、 Webアプリケーションをつくるソフトウェアエンジニアは、AWSGCPなどクラウド上で構築された、サーバー、ネットワーク、 ストレージなどのコンピューティングリソースをインフラと呼びがちです。 より一般向けの記事を読むと、社内のソフトウェアエンジニアが作成した管理画面や社内のCRMなどをITインフラと呼ぶこともあるようです。

ここでは「インフラ」という言葉の定義を、便宜的に「ソフトウェア開発に利用する、IaCで管理できるものすべて」とさせていただこうと思います。 なので、AWS等で構築するネットワークやDBだけでなく、エラー監視用のSentry、パフォーマンス監視に使うNewRelic、CI/CDとして利用するGitHub Actions、 その他様々なサービス群をインフラと呼ばせていただきます。

インフラのスタック

数々存在しているインフラリソースを任意のまとまりを、この記事では参考にした書籍にならって「スタック」と呼ばせていただきます。 この概念はCloudFormationのStackから来ており、スタックで管理されているリソースは一緒にデプロイされます。

設計について

設計の方針

私は「安全性」を最優先、「開発効率の維持」を2番めの優先事項としてIaCを設計します。

「安全性」は下記2点によって実現します

  • 設定の再現性・冪等性を担保するため、多少開発工数が掛かっても、できる限りのクラウドリソースをコード化
  • 障害発生時の影響範囲を限定的にするため、開発効率が多少下がっても初期からスタックを分割し、軽量なスタックを維持

「開発効率の維持」は下記2点によって実現します

  • 役割・技術要素軸でスタックを分割し、スタックを更新する上で必要な学習コストを軽減
  • スタックを小さく保ち、インフラタスクを複数人が並行して着手できる状態を維持

スタックの分割

上図のように、インフラを複数のスタックに分割します。

ここで簡単にいくつかのスタックについて説明します。 Appは、AWSなどクラウド上で構築しているネットワークやDB、バックエンドのサーバーを含む最も巨大なスタックです。 Frontは、フロントエンドのアプリケーションが構築されるスタックになります。最近だとVercelや Next.js をECS上で動かすことが多いです。 Monitoringは、監視に纏わる諸々を管理するスタックです。DatadogやCloudWatch等のインフラを管理します。

スタックは、ソフトウェアにおけるコンポーネントと同様の基準で分割しています。 再利用・リリース等価の原則 に従い、利用される単位とリリースの単位は等価になっており。 閉鎖性共通の原則 に従い、同じ理由、同じタイミングで変更されるものをまとめており。 非循環依存関係の原則 に従い、スタックの依存グラフは循環しない(必ず下の方向にのみ依存させる)ようになっています。

分割による狙い

分割の狙いは3つあります。

1つは 「変更容易性の確保」 です。 長大なスタックは把握しなければならないコード量と、変更による影響範囲が大きくなります。 すると、多くの人は怖がって触らないようになり、一部のエンジニアがお腹を痛めながら必要な修正をし続けることになります。 スタックを小さく保つことで、把握しなければならないコード量と変更による影響範囲を小さくし、高い頻度で継続して更新し続けられる状態を保ちます。

2つめは 「開発効率の維持」 です。 長大な1つのスタックは共同編集することができません。 インフラの変更を要する機能開発の要望が増えたとき、スタックが1つでは1人のエンジニアしか開発に参加できなくなります。 開発のボトルネックとなり、開発効率の低下を招きます。

3つめは 「開発組織の冗長性を高める」 ことです。 1つめの狙いに重なりますが、スタックの目的や影響範囲を限定することで、必然そのスタックに纏わる機能開発をする上で必要な前提知識も限定されます。 そうすることで開発に参加するための敷居を下げ、多くのメンバーがインフラの開発に参加できるような環境を整えます。

スタックの開発に参加する上で必要な知識の学習コストと、スタックを壊してしまったとき復旧にかかる時間をマッピングした図が下記のようになります。

右上にないものは学習コストが低い。 もしくは壊してもダメージ少ないものです。 それらはチームメンバーが開発に参加する上で心理的ハードルも低くなります。 そのため「初めての人は左下にあるものから入って、徐々に領域を広げて貰う」のような成長設計をしやすくなります。

IaCで採用するツールについて

私個人としては、スタックが適切に分割されていること。スタック間の依存が把握できていること。 この2点さえ守れるならば、IaCツールは何でも良いしと思っています。 どれか一つに統一する!と考えすぎず、各々のスタックの管理に適した(道具としての性質だけでなく、開発者の親和性含め) IaCツールを利用すれば良いのではないでしょうか。

私一人で利用する場合は、スタック間の依存関係を把握しやすく、リファクタリングも容易という理由でcdkを好んで使いますが、 下記の記事にも書きましたが terraformと比較すると cdk はそれなりに学習コストはあります。 なので、そこはチーム内で話し合ってチームに適したものを選べると良いかなと思います。

selmertsx.hatenablog.com