AWSサーバレスアーキテクチャをMonorepoツール - Nxとterraformで構築してみた!
AWSサーバレスアーキテクチャをMonorepoツール - Nxとterraformで構築してみた!
こんにちは。DevOpsで開発者を幸せにしたい。KINTO テクノロジーズのCCoEチーム所属の栗原です。
AWS Summit Tokyo 2023:クルマのサブスク「KINTO」のアジリティとガバナンスを両立する DBRE の取り組みでも発表しましたが、弊社DBREチームではSlackからのリクエストをトリガーに、一時的な踏み台サーバーを払い出すプラットフォーム(以降DBREプラットフォーム)を全社に展開しています。
DBREプラットフォームはAWSのサーバレスサービスを組み合わせて実装されています。同サーバレス部分をチームの使い慣れたterraformでIaCしつつ、NxというMonorepoツールで開発者体験の向上に成功した話をこの記事で紹介します。サーバレスに限らず、Monorepoでの開発フローに興味がある方にも参考になるかと思います。
背景、課題
DBREプラットフォームのアーキテクチャは以下のようになっています。
上記に加え運用関連も含めるとGolangのLambdaが20個ほどあり、それらをオーケストレーションするStep Functions、DynamoDB、スケジュールトリガーをするEventBridge等の組み合わせで構築しています。
開発を進めるにあたり以下のような課題、要望がありました。
- terraformのplan、applyのワークフローと統合し安全なデプロイを実現したい
- Formatter、Linter等の静的コード解析を適切に組み込みたい
サーバレスアーキテクチャを開発するのであれば、SAMやserverless frameworkが検討されるかと思いますが、terraformでIaCしたいという要望をクリアできませんし、GolangでのLambdaはケアしてくれない等の理由から別の開発アーキテクチャを検討することになりました。
terraformのlambdaモジュールを眺めてみます。とかくterraformに参照させるLambdaコードのZip
を事前に作れていれば、terrafromでIaCしたい問題はクリアできるだろうと考えました。
resource "aws_lambda_function" "test_lambda" {
# If the file is not in the current working directory you will need to include a
# path.module in the filename.
filename = "lambda_function_payload.zip"
function_name = "lambda_function_name"
role = aws_iam_role.iam_for_lambda.arn
handler = "index.test"
source_code_hash = data.archive_file.lambda.output_base64sha256
runtime = "nodejs16.x"
environment {
variables = {
foo = "bar"
}
}
}
更に後者の静的コード解析を適切に組み込みたい要望を考えてみます。サーバレス開発は言うならば小さいコードベースを組み合わせたもの
です。つまりコードベース群の境界をはっきりさせることで開発ツールとの統合を容易にし、ビルドスクリプトもシンプルに保てるのではという考えからMonorepoツールの導入を検討しました。
Monorepoツールとは
結論から言うと、NxというTypeScript製のMonorepoツールを導入しました。
導入理由はmonorepo.toolsというMonorepoツール比較ページでの機能の網羅性が高かったのと、将来の横展開を考えた際Javascript製というのも魅力を感じたためです。(フロントエンド界隈への導入障壁が低いという仮定。)
実例は次の章で説明しますが、前提としてMonorepoとはなんなのか?またNxは何をしてくれるのか?を簡単に説明します。
用語定義
Nxの用語に合わせ、本資料で使う用語を定義します。
プロジェクト
: monorepo内の1つのリポジトリのような塊(例: 単一のLambdaコード、共通モジュール)タスク
: テスト、ビルド、デプロイなどアプリケーションを構築するうえで必要な処理の総称
Monorepoとは
関連するプロジェクトがisolated(独立性を保ちつつ)
でかつwell-defined relationships(依存関係は適切に定義されている)
な状態で格納されている単一リポジトリと説明されています。対してWeb界隈では良くみられるマルチリポジトリの構成をpolyrepo
と呼ぶそうです。
出典: monorepo.tools
monorepo.toolsを要約すると、以下の様なメリットがあります。
- コミットがシステム単位でアトミックになる
- 共通モジュールの展開が容易(共通モジュールを更新した際、取り込みなど不要ですぐに利用可能)
- (マインドセット的に)縦割りにならず、システム全体に意識が向きやすい
- 新しいリポジトリを立ち上げる時の工数が減る
Monorepoツールではないですが、AWSのcdkでもIaCとアプリケーションコードの単一リポジトリ管理を推奨していることもあり、Monorepo化への潮流は一つの流れだと考えられます。
We discovered that failures are often related to "out-of-band" changes to an application that aren't fully tested, such as configuration changes.
Therefore, we developed the AWS CDK around a model in which your entire application is defined in code, not only business logic but also infrastructure and configuration.
…and fully rolled back if something goes wrong.
- https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html
Nxがしてくれること
大雑把にいうと、プロジェクト毎
に自身のタスク
と依存関係
を定義していけば、Nxがいい具合にタスクをオーケスレーションしてくれる
ということになります。
以下はterraformプロジェクトのタスク、依存関係の定義の例です。このように定義すると、plan-development
タスクを実行すると、定義した依存関係のLambdaコードのビルド(コンパイル、zip化)が先に実行され、その後terraformのplanを走らせてくれます。fmt
やtest
などもterraform専用のタスクとしてシンプルに定義することができます。
このように各コードベースの責務を明確化していくことで、コード全体の見通しをよくしていくことができます。
プロジェクト単位で、それぞれの開発言語にあった開発ツールを組み込むことが可能ですし、ビルド職人に頼らなくとも適切な開発フローを構築していくことが可能になります。
KINTO テクノロジーズでの実用例
前述のDBREプラットフォームの一部を抜粋し、簡素化したうえで実用例を説明していきます。
GolangのLambdaコードが二つあり、双方同じ共通モジュールを利用しています。terraformからデプロイできるように、Lambdaコードのプロジェクトは自身のコードをコンパイルし、Zipファイルを作成するまでが責務となります。
ディレクトリ構成はこのようになります。
プロジェクト定義
上記4プロジェクトの各プロジェクト定義をそれぞれ記載します。
①: 共通モジュール
- Golangでは共通モジュールは利用側で参照できれば良いので、ビルドは不要で静的解析、UTのみをタスクとして定義します
projects/dbre-toolkit/lambda-code/shared-modules/package.json
{
"name": "shared-modules",
"scripts": {
"fmt-fix": "gofmt -w -d",
"fmt": "gofmt -d .",
"test": "go test -v"
}
}
②、③: Lambdaコード
- 共通モジュールを依存プロジェクトとして登録することで、
共通モジュールのコードが変更されるた場合、タスクの実行が必要
といった定義になります build
タスクはgo buildを実行して生成されたバイナリーをZip化するまでが責務になり、後にterraformプロジェクトで利用されます
projects//dbre-toolkit/lambda-code/lambda-code-01/package.json
{
"name": "lambda-code-01",
"scripts": {
"fmt-fix": "gofmt -w -d .",
"fmt": "gofmt -d .",
"test": "go test -v",
"build": "cd ../ && GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o lambda-code-01/dist/main lambda-code-01/main.go && cd lambda-code-01/dist && zip lambda-code.zip main"
},
"nx": {
"implicitDependencies": [
"shared-modules"
]
}
}
④: IaC
plan-${env}
、apply-${env}
を実行すると、依存関係に指定されているLambdaコードのbuild
が先に実行されます(plan、apply実行時には必要なzipが生成されている状態になる)
projects//dbre-toolkit/iac/package.json
{
"name": "iac",
"scripts": {
"fmt": "terraform fmt -check -diff -recursive $INIT_CWD",
"fmt-fix": "terraform fmt -recursive -recursive $INIT_CWD",
"test": "terraform validate",
"plan-development": "cd development && terraform init && terraform plan",
"apply-development": "cd development && terraform init && terraform apply -auto-approve"
},
"nx": {
"implicitDependencies": [
"lambda-code-01",
"lambda-code-02"
],
"targets": {
"plan-development": {
"dependsOn": [
"^build"
]
},
"apply-development": {
"dependsOn": [
"^build"
]
}
}
}
}
terraformのモジュールからは、以下の様に前段で生成されているZipファイルを参照させます。
local {
lambda_code_01_zip_path = "${path.module}/../../../lambda-code/lambda-code-01/dist/lambda-code.zip"
}
# 中略
resource "aws_lambda_function" "lambda-code-01" {
function_name = "lambda-code-01"
architectures = ["x86_64"]
runtime = "go1.x"
package_type = "Zip"
filename = local.lambda_code_01_zip_path
handler = "main"
source_code_hash = filebase64sha256(local.lambda_code_01_zip_path)
}
タスク実行
各プロジェクトの分割、タスク定義ができたので、タスクの実行について見ていきます。
Nxではrun-many
サブコマンドで特定プロジェクトの特定タスク、全プロジェクトの特定タスクの実行が可能です。依存関係に基づき、可能な場合はパラレルに実行されるので速度も高速です。
nx run-many --target=<定義したタスク名> --projects=<プロジェクト名のカンマ区切り>
nx run-many --target=<定義したタスク名> --all
iac
プロジェクトのplan-development
を実行する例。依存関係があるタスクは、定義した依存関係に基づいてタスクを実行してくれる
まさにやりたかったポイントです。依存プロジェクトのタスクを先行して実行してくれるため、terraform実行時には適切にLambdaのコードがZip化されている状態を担保することができます。
$ nx run-many --target=plan-development --projects=iac --verbose
> NX Running target plan-development for 1 project(s) and 2 task(s) they depend on:
- iac
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> nx run lambda-code-01:build
updating: main (deflated 56%)
> nx run lambda-code-02:build
updating: main (deflated 57%)
> nx run iac:plan-development
Initializing modules...
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v4.39.0
terraform has been successfully initialized!
〜〜中略
}
Plan: 0 to add, 2 to change, 0 to destroy.
test
タスクを実行する例。タスクに依存関係がないので全てパラレルに実行される
全プロジェクトのUTなど依存関係がないタスクはパラレルに実行できます。
CIでの実行はもちろん、『GitHubにpushする前に必ずUTを実行する』といった開発ルールがあった場合も一つのコマンドで解決することができます。
$ nx run-many --target=test --all --verbose
> NX Running target test for 4 project(s):
- lambda-code-01
- lambda-code-02
- shared-modules
- iac
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> nx run shared-modules:test
? github.com/kinto-dev/dbre-platform/dbre-toolkit/shared-modules [no test files]
> nx run lambda-code-01:test
=== RUN Test01
--- PASS: Test01 (0.00s)
PASS
ok github.com/kinto-dev/dbre-platform/dbre-toolkit/lambda-code-01 0.255s
> nx run iac:test
Success! The configuration is valid.
> nx run lambda-code-02:test
=== RUN Test01
--- PASS: Test01 (0.00s)
PASS
ok github.com/kinto-dev/dbre-platform/dbre-toolkit/lambda-code-02 0.443s
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target test for 4 projects
> nx run lambda-code-02:test
Nx、Monorepoツールの強力な機能
プロジェクトを適切に定義していくとことで、タスクをオーケストレーションできる様子が伝わったかと思います。
ただし、これだけでは普通のタスクランナーと変わらないので、Nx、Monorepoツールを使う大きなメリットをいくつか紹介します。
変更プロジェクトのみタスク実行
最も早いタスク実行とはそもそもタスクを実行しないこと
です。affected
コマンドという変更プロジェクトのみのタスクを実行してくれる機構が用意されており、CIを高速に完了することが可能です。
以下がコマンドのシンタックスです。2つのGitポインターを渡してあげることで、同ポインター間で変更があったプロジェクトのタスクのみ実行してくれます。
nx affected --target=<タスク名> --base=<two dots diffのbase> --head=<two dots diffのhead>
# lambda-code-01にだけ変更がある状態
$ git diff main..feature/111 --name-only
projects/dbre-toolkit/lambda-code/lambda-code-01/main.go
$ nx affected --target=build --base=main --head=feature/111 --verbose
> NX Running target build for 1 project(s):
- lambda-code-01
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> nx run lambda-code-01:build
updating: main (deflated 57%)
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target build for 1 projects
依存先のプロジェクトに変更があれば、依存関係に基づきタスクを実行してくれます。
# shared-moduleにだけ変更がある状態
$ git diff main..feature/222 --name-only
projects/dbre-toolkit/lambda-code/shared-modules/utility.go
# shared-moduleに依存しているプロジェクトのタスクが実行される
$ nx affected --target=build --base=main --head=feature/222 --verbose
> NX Running target build for 2 project(s):
- lambda-code-01
- lambda-code-02
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> nx run lambda-code-01:build
updating: main (deflated 56%)
> nx run lambda-code-02:build
updating: main (deflated 57%)
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target build for 2 projects
CI/CDパイプラインの簡素化
タスク名が変わらなければ、プロジェクトを追加していってもCI/CDパイプラインの変更が不要なため、メンテナンスコストが下がります。
加えて、前述のaffected
コマンドにより、CI/CDの処理を高速化することができます(変更したプロジェクトのタスクのみ実行してくれるため)。
以下はGitHub ActionsのCIの例です。
name: Continuous Integration
on:
pull_request:
branches:
- main
- develop
types: [opened, reopened, synchronize]
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
# --immutable オプションは、yarn.lockに記載の固定バージョンのdependenciesをインストールさせるオプション
- name: install npm dependencies
run: yarn install --immutable
shell: bash
- uses: actions/setup-go@v3
with:
go-version: '^1.13.1'
- uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.3.5
- name: configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1-node16
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: 'ap-northeast-1'
# タスク実行箇所はこの記述量で完了する
- name: format check
run: nx affected --verbose --target fmt --base=remotes/origin/${{ github.base_ref }} --head=remotes/origin/${{ github.head_ref }}
- name: test
run: nx affected --verbose --target test --base=remotes/origin/${{ github.base_ref }} --head=remotes/origin/${{ github.head_ref }}
- name: build
run: nx affected --verbose --target build --base=remotes/origin/${{ github.base_ref }} --head=remotes/origin/${{ github.head_ref }}
- name: terraform plan to development
run: nx affected --verbose --target plan-development --base=remotes/origin/${{ github.base_ref }} --head=remotes/origin/${{ github.head_ref }}
Git Hookと組み合わせてさらに生産性の向上
『Gitでpushする前に静的解析とUnit Testくらいはローカルでやってほしい。Gitの履歴も汚れるし』といった開発ルールも簡単に解決することができます。
affected
コマンドの--files
、--uncommitted
オプションと、Git Hookを組み合わせることで、変更ファイルが属するプロジェクトのみを対象にでき、開発者のストレスを最小限に(実行に時間をかけずに)実現が可能です。
例えば以下の様なaffected
コマンドをpre-commit
フックに仕込んでおけば、コミット履歴も汚れず、レビューのノイズも軽減することができます。
nx affected --target lint --files $(git diff --cached --name-only)
:nx affected --target unit-test --files $(git diff --cached --name-only)
nx affected --target fmt-fix --files $(git diff --cached --name-only)
その他のメリット
タスクの実行結果はプロジェクトのコードに変更がなければキャッシュされる
タスクの実行結果は、生成されたファイル、標準出力/エラーともキャッシュされます。(詳細はこちら)
$ tree .nx-cache/
├── ce36b7825abacc0613a8b2c606c65db6def0e5ca9c158d5c2389d0098bf646a1
│ ├── code
│ ├── outputs
│ │ └── projects
│ │ └── dbre-toolkit
│ │ └── lambda-code
│ │ └── lambda-code-01
│ │ └── dist
│ │ ├── lambda-code.zip
│ │ └── main
│ └── terminalOutput
├── ce36b7825abacc0613a8b2c606c65db6def0e5ca9c158d5c2389d0098bf646a1.commit
├── nxdeps.json
├── run.json
└── terminalOutputs
├── 1c9b46c773287538b1590619bfa5c9abf0ff558060917a184ea7291c6f1b988c
├── 6f2fbb5f2dd138ec5e7e261995be0d7cddd78e7a81da2df9a9fe97ee3c8411c5
├── 88c7015641fa6e52e0d220f0fdf83a31ece942b698c68c4455fa5dac0a6fd168
├── 9dc8ebe6cdd70d8b5d1b583fbc6b659131cda53ae2025f85037a3ca0476d35b8
├── c4267c4148dc583682e4907a7692c2beb310ebd2bf9f722293090992f7e0e793
├── ce36b7825abacc0613a8b2c606c65db6def0e5ca9c158d5c2389d0098bf646a1
├── db7e612621795ef228c40df56401ddca2eda1db3d53348e25fe9d3fe90e3e9a1
├── dc112e352c958115cb37eb86a4b8b9400b64606b05278fe7e823bc20e82b4610
└── eb94fd3a7329ab28692a2ae54a868dccae1b4730e4c15858e9deb0e2232b02f3
これをCI/CDでもキャッシュしておけば、例えばコードレビューで一部分だけ修正が必要になった場合、修正後のPushに対するCI処理のタスクの大部分はキャッシュが使われるため、更に高速に開発を回すことが可能です。
- name: set nx cache dir to environment variables
id: set-nx-version
run: |
echo "NX_CACHE_DIRECTORY=$(pwd)/.nx-cache" >> $GITHUB_ENV
shell: bash
# nxのキャッシュをGitHubのキャッシュに登録
- name: nx cache action
uses: actions/cache@v3
id: nx-cache
with:
path: ${{ env.NX_CACHE_DIRECTORY }}
key: nx-cache-${{ runner.os }}-${{ github.sha }}
restore-keys: |
nx-cache-${{ runner.os }}-
graph
コマンドにより、プロジェクトの依存関係をビジュアライズできる
コードベースの境界が明確になったとはいえ、依存関係を網羅的に確認したい時はあります。graphサブコマンドが整備されており、プロジェクト間の依存関係を可視化することができます。そのあたりもケアしてくれている点もNxの魅力の一つです。
DBREプラットーフォームの現状
DBREプラットフォームでは現状28プロジェクトを有するMonorepoとなっています。前述の例だとプロジェクト数が少なかったため、メリットがわかりづらかったかもしれませんが、これくらいの規模になってくるとaffected
コマンド等の恩恵を十二分に享受できています。
$ yarn workspaces list --json
{"location":".","name":"dbre-platform"}
{"location":"dbre-utils","name":"dbre-utils"}
{"location":"projects/DBREInit/iac","name":"dbre-init-iac"}
{"location":"projects/DBREInit/lambda-code/common","name":"dbre-init-lambda-code-common"}
{"location":"projects/DBREInit/lambda-code/common-v2","name":"dbre-init-lambda-code-common-v2"}
{"location":"projects/DBREInit/lambda-code/push-output","name":"dbre-init-lambda-code-push-output"}
{"location":"projects/DBREInit/lambda-code/s3-put","name":"dbre-init-lambda-code-s3-put"}
{"location":"projects/DBREInit/lambda-code/sf-check","name":"dbre-init-lambda-code-sf-check"}
{"location":"projects/DBREInit/lambda-code/sf-collect","name":"dbre-init-lambda-code-sf-collect"}
{"location":"projects/DBREInit/lambda-code/sf-notify","name":"dbre-init-lambda-code-sf-notify"}
{"location":"projects/DBREInit/lambda-code/sf-setup","name":"dbre-init-lambda-code-sf-setup"}
{"location":"projects/DBREInit/lambda-code/sf-terminate","name":"dbre-init-lambda-code-sf-terminate"}
{"location":"projects/PowerPole/iac","name":"powerpole-iac"}
{"location":"projects/PowerPole/lambda-code/pp","name":"powerpole-lambda-code-pp"}
{"location":"projects/PowerPole/lambda-code/pp-approve","name":"powerpole-lambda-code-pp-approve"}
{"location":"projects/PowerPole/lambda-code/pp-request","name":"powerpole-lambda-code-pp-request"}
{"location":"projects/PowerPole/lambda-code/sf-deploy","name":"powerpole-lambda-code-sf-deploy"}
{"location":"projects/PowerPole/lambda-code/sf-notify","name":"powerpole-lambda-code-sf-notify"}
{"location":"projects/PowerPole/lambda-code/sf-setup","name":"powerpole-lambda-code-sf-setup"}
{"location":"projects/PowerPole/lambda-code/sf-terminate","name":"powerpole-lambda-code-sf-terminate"}
{"location":"projects/PowerPoleChecker/iac","name":"powerpolechecker-iac"}
{"location":"projects/PowerPoleChecker/lambda-code/left-instances","name":"powerpolechecker-lambda-code-left-instances"}
{"location":"projects/PowerPoleChecker/lambda-code/sli-notifier","name":"powerpolechecker-lambda-code-sli-notifier"}
{"location":"projects/dbre-toolkit/docker-image/shenron-wrapper","name":"dbre-toolkit-docker-image-shenron-wrapper"}
{"location":"projects/dbre-toolkit/iac","name":"dbre-toolkit-iac"}
{"location":"projects/dbre-toolkit/lambda-code/dt-list-dbcluster","name":"dbre-toolkit-lambda-code-dt-list-dbcluster"}
{"location":"projects/dbre-toolkit/lambda-code/dt-make-markdown","name":"dbre-toolkit-lambda-code-dt-make-markdown"}
{"location":"projects/dbre-toolkit/lambda-code/utility","name":"dbre-toolkit-lambda-code-utility"}
terraformでのIaCもコンポーネント単位で4つのプロジェクトに分割しています。このように気軽にプロジェクトを分割できることで、単一リポジトリでも各コードベースのサイズをスリムに保つことが可能です。affected
コマンドによりCI/CDも高速に完了するため、開発体験を下げることなく生産性を上げることができています。
$ yarn list-projects | grep iac
{"location":"projects/DBREInit/iac","name":"dbre-init-iac"}
{"location":"projects/PowerPole/iac","name":"powerpole-iac"}
{"location":"projects/PowerPoleChecker/iac","name":"powerpolechecker-iac"}
{"location":"projects/dbre-toolkit/iac","name":"dbre-toolkit-iac"}
課題
この開発アーキテクチャが完成するまでに課題になった点と、どう解決したかも紹介させていただきます。
導入で触れた様にLambdaコードのZip化が重要ポイントだったのですが、実行環境やZipのメタデータ(更新日時等)を完全に同じにしないと、コードに変更がなくてもterraformで差分が発生してしまうという課題がありました。解決策として、コードのビルド、Zip化はコンテナ内で実行し、タスク定義からはそれを呼ぶことで解決しました。
Dockerfile
FROM golang:1.20-alpine
RUN apk update && \
apk fetch zip && \
apk --no-cache add --allow-untrusted zip-3.0-r*.apk bash
COPY ./docker-files/go-single-module-build.sh /opt/app/go-single-module-build.sh
./docker-files/go-single-module-build.sh
#!/bin/bash
set -eu -o pipefail
while getopts "d:m:b:h" OPT; do
case $OPT in
d) SOURCE_ROOT_RELATIVE_PATH="$OPTARG" ;;
m) MAIN_GO="$OPTARG" ;;
b) BINARY_NAME="$OPTARG" ;;
h) help ;;
*) exit ;;
esac
done
shift $((OPTIND - 1))
cd "/opt/mounted/$SOURCE_ROOT_RELATIVE_PATH" || exit 1
rm -f ./dist/*
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o "./dist/$BINARY_NAME" "$MAIN_GO"
cd ./dist || exit 1
# for sha256 diff
chown "$HOST_USER_ID":"$HOST_GROUP_ID" "$BINARY_NAME"
touch --no-create -t 01010000 "$BINARY_NAME" ./*.tmpl
zip "$BINARY_NAME.zip" "$BINARY_NAME" ./*.tmpl
chown -R "$HOST_USER_ID":"$HOST_GROUP_ID" ../dist
他にもローカル実行が現状できていないなどの課題もあります。今後terraformに限らず、SAM
やcdk
のMonorepo化もチャレンジしていきたいと思っています。
まとめ
本記事ではMonorepoツールでAWSのサーバレスの管理方法の紹介をベースに、Nxの強力な機能について紹介させていただきました。コードベースの境界が明確になったことで、プロジェクト毎に適切な開発ツールとの統合、terraformでのIaCを実現することができました。僕も、私もMonorepoしたい!と思っていただけた方は是非プラットフォームGで一緒に働きませんか?ご拝読ありがとうございました。
関連記事 | Related Posts
Building an AWS Serverless Architecture Using Nx Monorepo Tool and Terraform
ECS環境のAuto Provisioningを実現する仕組み
Aurora MySQL におけるロック競合(ブロッキング)の原因を事後調査できる仕組みを作った話
GitHubActions+ECSでBlueGreenDeploymentを実装するお話
データベースのパスワードを安全にローテーションする仕組みの導入
生成 AI × DB テーブル設計レビュー:Serverless & GitHub Actions での自動化と生成 AI アプリケーションの評価事例
We are hiring!
【DBRE】DBRE G/東京・名古屋・大阪
DBREグループについてKINTO テクノロジーズにおける DBRE は横断組織です。自分たちのアウトプットがビジネスに反映されることによって価値提供されます。
【プラットフォームエンジニア】プラットフォームG/東京・大阪
プラットフォームグループについてAWS を中心とするインフラ上で稼働するアプリケーション運用改善のサポートを担当しています。