KINTO Tech Blog
DevOps

AWSサーバレスアーキテクチャをMonorepoツール - Nxとterraformで構築してみた!

Cover Image for 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プラットフォームのアーキテクチャは以下のようになっています。

archtecture-1

archtecture-2

上記に加え運用関連も含めるとGolangのLambdaが20個ほどあり、それらをオーケストレーションするStep Functions、DynamoDB、スケジュールトリガーをするEventBridge等の組み合わせで構築しています。

開発を進めるにあたり以下のような課題、要望がありました。

  • terraformのplan、applyのワークフローと統合し安全なデプロイを実現したい
  • Formatter、Linter等の静的コード解析を適切に組み込みたい

サーバレスアーキテクチャを開発するのであれば、SAMserverless 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
出典: 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を走らせてくれます。fmttestなどもterraform専用のタスクとしてシンプルに定義することができます。

package.json

このように各コードベースの責務を明確化していくことで、コード全体の見通しをよくしていくことができます。
プロジェクト単位で、それぞれの開発言語にあった開発ツールを組み込むことが可能ですし、ビルド職人に頼らなくとも適切な開発フローを構築していくことが可能になります。

KINTO テクノロジーズでの実用例

前述のDBREプラットフォームの一部を抜粋し、簡素化したうえで実用例を説明していきます。

GolangのLambdaコードが二つあり、双方同じ共通モジュールを利用しています。terraformからデプロイできるように、Lambdaコードのプロジェクトは自身のコードをコンパイルし、Zipファイルを作成するまでが責務となります。

work-flow

ディレクトリ構成はこのようになります。
directories

プロジェクト定義

上記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の魅力の一つです。

graph

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に限らず、SAMcdkのMonorepo化もチャレンジしていきたいと思っています。

まとめ

本記事ではMonorepoツールでAWSのサーバレスの管理方法の紹介をベースに、Nxの強力な機能について紹介させていただきました。コードベースの境界が明確になったことで、プロジェクト毎に適切な開発ツールとの統合、terraformでのIaCを実現することができました。僕も、私もMonorepoしたい!と思っていただけた方は是非プラットフォームGで一緒に働きませんか?ご拝読ありがとうございました。

Facebook

関連記事 | Related Posts

We are hiring!

【DBRE】DBRE G/東京・名古屋・大阪

DBREグループについてKINTO テクノロジーズにおける DBRE は横断組織です。自分たちのアウトプットがビジネスに反映されることによって価値提供されます。

【プラットフォームエンジニア】プラットフォームG/東京・大阪

プラットフォームグループについてAWS を中心とするインフラ上で稼働するアプリケーション運用改善のサポートを担当しています。