Slide 1

Slide 1 text

© 2022 LayerX Inc. Monorepo on AWS LayerX @y_matsuwitter 2022.10.26

Slide 2

Slide 2 text

自己紹介

Slide 3

Slide 3 text

© 2022 LayerX Inc. 3 自己紹介 松本 勇気 (@y_matsuwitter) 株式会社LayerX 代表取締役CTO 株式会社三井物産デジタル・アセットマネジメント 取締 役 日本CTO協会 理事 Fintech/PrivacyTechを主に管掌 趣味は筋トレと料理

Slide 4

Slide 4 text

課題背景

Slide 5

Slide 5 text

© 2022 LayerX Inc. 5 リアーキテクチャへの柔軟性 プロダクトが日々進化・複雑化するため、状況に合わせた適切なアーキテクチャへの変化が必須。 柔軟なリアーキテクチャや相互依存の可視化・検証を可能とする仕組みへの投資が求められる。 App API Product A App API Product A App API Product B App API Product A App API Product B App API Product C API API 共有するロジックの 切り出し サービス間の参照 拡大 拡大

Slide 6

Slide 6 text

Monorepoとは

Slide 7

Slide 7 text

© 2022 LayerX Inc. 7 Monorepoの定義 関連するソースコードを一つの repositoryに閉じ込める コードで表現されたサービス間依 存(grpc等)をCI/CDで検証でき る。 プロダクトに関わる全てのソースコードを一つのrepositoryに含める開発手法をここではMonorepoと呼称する。 構成するシステム間の依存も含めて全てコードに表現されるため、構成変更の検証が簡単。 Monorepo Polyrepo ServiceA repo ServiceB repo Shared Library repo Product repo ServiceA ServiceB Shared Library 一般的手法に取られる管理手法。 サービスや言語・PFごとに repositoryを構築する。

Slide 8

Slide 8 text

© 2022 LayerX Inc. 8 Monorepo利用時の要求 開発者に認知的・技術的負担を強いることなく、システム間の依存の検証と運用を可能とする開発者体験を求めたい。 そのためにサービス間依存のCIでの検証やテストの差分実行、deployの効率化などが必須。 サービス間依存の検証 ● grpcやgraphqlなどで Server-Client間のIFを定義 ● 定義変更時に、依存する Clientサービスを全てユニッ トテスト等で検証することで、 変更影響を理解しやすくした い。 テストの差分実行 ● 一つのrepositoryにたくさん のサービスや言語が含まれる。 ● repositoryが拡大し続けるた め、毎度単純なテストを回すと 破綻する。 ● 変更が影響する箇所のみを検 証したい。 Deployの効率化 ● 一つのrepositoryが全ての サービスのDeployソースとな る。 ● 変更にて影響あるものだけを 効率的にDeployしたい。

Slide 9

Slide 9 text

とあるプロジェクトの Monorepo

Slide 10

Slide 10 text

© 2022 LayerX Inc. 10 Makefileベースの単純なmonorepo 初期のMonorepo導入プロジェクトではbazelとMakefileの2つの選択肢の中でMakefileベースの手法を選択した。 仕組みとしては単純で、各言語に合わせてCIなどの対応処理をMakefileで実装、開発を効率化。 ./typescript ./go ./terraform └package.json └Makefile └Makefile 言語やPFごとに要件は異なる。 それぞれの言語ごとに合わせた Makefileやpackage.jsonを 用意。 Setup, Build, Run, Test, Lintなどの機能をそれぞれで愚 直に実装する方法を取る。 . ├── Makefile ├── README.md ├── containers │ ├── api │ └── migration ├── docker-compose.yml ├── go │ ├── Makefile │ ├── README.md │ ├── cmds │ ├── ent │ ├── go.mod │ ├── go.sum │ ├── gqlgen.yml │ ├── graph │ ├── pkg │ ├── sam │ ├── seed │ ├── services │ └── tools.go ├── package.json ├── terraform │ ├── Makefile │ ├── README.md │ ├── aws │ ├── buildspec.yml │ └── policy ├── typescript │ ├── README.md │ ├── buildspec.yml │ ├── codegen.yml │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── src │ ├── tsconfig.json │ └── yarn.lock └── yarn.lock 図:とあるプロダクトの構成

Slide 11

Slide 11 text

© 2022 LayerX Inc. 11 Bazel等のツールを使うケースとの比較 Bazelには依存関係の細かな検知を元にしたmonorepo開発における大きなメリットがある。 一方、小規模な組織にとってBazel利用は対応コストが重く、爆速なサービスリリースを目指しMakefileでの対応を選択。 ● OSSのmonorepoに向 いたビルドツール ● プロジェクト内の全ての ファイルの依存関係を明示 的に指定。 ● 依存関係に応じたビルドや テストの実行をサポートす る。 ● ビルドやテストの効率化をツールレベルでサポートし てくれる。 ● 様々な言語にプラグインで効率的に対応可能。Goで あればgazelleとの組み合わせ。 メリット 課題 ● ツール自体の学習コスト・運用コストの高さ。bazel独 自の記法による依存関係定義が必要。 ● typescript等、言語によってはそれぞれに合わせた ツールを用いたほうが管理しやすいケースも。

Slide 12

Slide 12 text

とあるプロジェクトにおける AWSでの取り組みと課題

Slide 13

Slide 13 text

© 2022 LayerX Inc. 13 deployの効率化 変更されたコードとCodepipelineの対応関係を考慮したDeployフロー構築が必要。 DBスキーマ変更があればマイグレーションとAPI及びLambdaのdeployを行うといったもの。 webapp api_A terraform api_B db_migration lambda_A lambda_B ● サービスごとに一つのCodePipelineを運用 ● 効率化のため、サービス間の依存に応じて、依存先のサービスも同期・非同期を選択し つつ順次deployしたい。 ● Githubフックな実行だと、全てのCodePipelineが実行されてしまい非効率… 例:各AppのDeploy依存関係

Slide 14

Slide 14 text

© 2022 LayerX Inc. 14 API Gateway + LambdaでCodePipelineを起動 CodePipelineをベースとしているため、Pipeline実行のフック方法を変更することで対応。 柔軟なルール設定のために、API GatewayとLambdaでGithubのWebhookを作成、Pipelineを実行する形に。 Github Hook API Gateway API Gateway Lambda CodePipeline CodePipeline CodePipeline CodePipeline 変更されたソース情報 を受領 変更内容に対応する CodePipelineを選 択的に実行

Slide 15

Slide 15 text

© 2022 LayerX Inc. 15 deployスピード vs 丁寧な依存関係の対応 現時点では、deployスピードとdeployの冪等性にまかせてシンプルなdeployを実装。 一方で今後の課題として、より正確なdeployに向けては依存を考慮した順序制御なども検討したい。 ● ConditionalにStageやStepを実行・ス キップできる機能がほしい… ● 一つのCodePipelineに複数のPipeline を並べたい… 理想の世界 ● 実現しているのは、API Gatewayを 通じて、実行対象のCodePipelineを 絞るという仕組みのみ。 現状 ● サービス間の依存がある場合、実行タイ ミングによってはdeploy失敗、再デプ ロイが要求される。 ○ 例: terraformでのインフラ変 更に巻き込まれる…等 課題 ● Lambdaにて、実行順序も加味して deployを実行する。 ○ 単体のLabmdaの実行時間上限アリ ● CodePipelineにて承認ステップを挟み、 手動で順序を担保する。 解決手法

Slide 16

Slide 16 text

まとめ

Slide 17

Slide 17 text

© 2022 LayerX Inc. 17 Monorepoの旅は続く… リアーキテクチャしやすさを求めてMonorepoを採用。 AWSらしいMonorepoの実装に向けては、特にDeploy面などまだ改善の余地がある。今後も模索していきたい。 リアーキテクチャのために ● サービスの分割容易性を担保 するには、サービス間依存を検 証しやすい仕組みが必要。 ● MonorepoはCI段階でそうし た手当が可能であり有力な選 択肢となりうる。 MakefileによるMonorepo ● Bazelの学習・運用コストを勘 案し、Makefile等各言語ごと の実行定義を愚直に作成。 ● 結果、サービスリリースまでを 小さなチームで迅速に進めら れた。 ● 今後、より効率的なビルドなど を踏まえると課題は残る。 Deployの効率化課題 ● 変更内容に対応する依存サー ビスのみをDeployしたい。 ● 現状はGithub Hook + API Gateway + Lambdaの組 み合わせで実行制御。 ● 将来的には、CodePipeline 内で解決できると理想…

Slide 18

Slide 18 text

ご静聴ありがとうございました