0
0

コストをちょっと削減したプロダクトの形

Last updated at Posted at 2024-08-15

前書き

仲間と一緒に、カツカツで起業活動を行っています。
AWSを使用しているため、最近の円安により頭を悩ませていました。
どうにかランニングコストを下げるため、行った一部の施策を記録します。
img-mv01-19.jpg

使用する技術は以下の通りです。。

言語 Typescript
フレームワーク tRPC Express Turborepo Prisma
インフラ・ミドルウェア Docker AWS CDK PostgreSQL

既存構成

リポジト管理はモノレポ形式を採用してます、モノレポの簡単な説明は下記に載せます。

モノレポとは、アプリケーションやマイクロサービスの全コードを単一のリポジトリに保存するパターン。

共用ライブラリはpackagesフォルダに集約し、各アプリケーションはappsフォルダに配置しています。
例えば、ログ機能はpackagesフォルダに置き、各アプリケーションから利用できるようにしています。デプロイ時には、Turborepo の機能で効率よくコンテナ化され、最適な状態で展開されます。

7801E701-6544-4C03-90CF-EC0D3FAD7846_4_5005_c.jpeg

インフラ構成は、以下の図に示すように、ベーシックな構成になっています。
C22FF4EE-C471-4B09-9BFB-660D6953CD2A.jpeg

サービスのアクセス数がまだ少ないため、サーバーレス化を決定しました。

ただし、サーバーレス化はあくまで暫定的な対処です。今後、ユーザー数が増加した場合には、コストを抑えるためにECSへ戻すことも考慮しています。

サーバーレス化

domain層のパッケージ化

正直、「domain層」という命名が正しいのか不安はありますが、
フロントエンドからパラメーターを受け取り、最初に処理を行う層として意識しています。

DB処理(infra層)のコードは最初からパッケージ化されているため、controller層が変更されてもアプリ全体への影響は少なく済みます。

879CFCD1-77FE-4D30-9E96-DCC1F2E65DB9_4_5005_c.jpeg

この構造にすれば、今後移行作業が発生しても、人力コストをある程度削減できるはずです。

ALB + ECSからAPIGatway + Lambdaへ変更

変更前はExpressを採用してましたが、よく調べてみたら、tRPCAWS APIGatwayをサポートしてるらしく、公式ドキュメント通りにtRPC使って置き換えました。

ただし、通常の.zipファイルを使用したLambdaデプロイではサイズ制限に引っかかってしまったため、Express採用時のDockerfileを改造して運用しました。
.zipの場合、解凍後サイズ250MBが上限ですが、イメージの場合は10GBです。

使用するDockerfileの一部抜粋を以下に載せておきます。

Turborepo流儀の通常ステージビルド
...

FROM public.ecr.aws/lambda/nodejs:20
COPY --from=installer --chown=app:nodejs /app/pruned .
COPY --from=builder --chown=app:nodejs /app/apps/serverless-api/dist .

ENV NODE_ENV=production
CMD [ "index.handler" ]

サーバーレス化されたイメージのECRへのプッシュと別に、LambdaのデプロイにはCDKを採用しています。
使用したcdkのコードの抜粋も載せておきます。

cdk.ts
import {
  aws_iam as iam,
  aws_lambda as lambda,
  aws_apigateway as apigateway,
  Stack,
  StackProps,
} from "aws-cdk-lib";
import { Handler, Runtime } from 'aws-cdk-lib/aws-lambda';
import { Construct } from "constructs";
import * as path from "path";

export class FormationStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    ... ecrvpcrdsなど

    const tRpcLambda = new lambda.Function(this, "TRpcLambda", {
      runtime: Runtime.FROM_IMAGE,
      handler: Handler.FROM_IMAGE,
      code: lambda.Code.fromEcrImage(ecrRepo, {
        tagOrDigest: 'latest',
      }), 
      vpc,
      role: lambdaRole,
      environment: {
        NODE_ENV: "production",
        DATABASE_URL: "",
      },
    });

    dbSecret.grantRead(tRpcLambda);

    const api = new apigateway.RestApi(this, "TRpcApi", {
      restApiName: "TRpcApi",
      description: "TRpcApi",
      endpointTypes: [apigateway.EndpointType.EDGE],
      deployOptions: { stageName: "v1" },
    });

    const apiResource = api.root.addResource("api");
    const anyResource = apiResource.addResource("{path+}");
    anyResource.addMethod("any", new apigateway.LambdaIntegration(tRpcLambda))

  }
}

コスト削減の効果

48565060-2A7F-44A1-8E4C-C0E2F804B822.jpeg

単純計算すると2.93 + 5.14 = 8.07%となります。
しかし、無料利用枠や従量課金制があるとはいえ、API Gateway と Lambda の構成も無料ではありません。
そのため、実際のコスト削減率はさらに少ないかもしれません:joy:

今後もコストに気を配りながら開発していきたいです。

終わりに

今は若干円高に戻りましたが、2024年7月10日前後には約161円になり、
サーバー代だけで倒産しそうになって冷や汗をかきました:scream:

コスト削減したことは無駄にはならないと思います、
コストを低く抑えられれば、サービスも長続きし、成功する可能性も上がると思います:relaxed:

欲を言えば、インフラをcloudflare利用すればもう少し安価にできたのかもしれません、今度試してみたいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0