ECS, Fargateで立てたサーバーをPrismaでRDSにつなぐ

使用技術

TS, Node(Hapi), Prisma, ECS, Fargate, RDS(MySQL)

現在既にAWS上でサーバーが起動しているものとする。

index.ts

import Hapi from "@hapi/hapi";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const init = async () => {
  const server = Hapi.server({
    port: 3030,
  });

  server.route([
    {
      method: "GET",
      path: "/",
      handler: () => {
        console.log("run");
        return "Hello World!";
      },
    },
    {
      method: "GET",
      path: "/users",
      handler: async () => {
        console.log("users");
        const users = await prisma.user.findMany();

        return users;
      },
    },
  ]);

  await server.start();
  console.log("サーバー起動");
  console.log("Server running on %s", server.info.uri);
};

init();

schema.prisma

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
 // ローカルでエラー起きたのでここ書いてる。いらないかも
  binaryTargets = ["native", "debian-openssl-1.1.x"]
}

model User {
  id  Int @id @default(autoincrement())
  name String?
  age Int?
}

Dockerfile

FROM node:12
RUN apt-get update
RUN apt-get install -y openssl
WORKDIR /app
COPY package*.json /app
RUN npm install
COPY . /app
EXPOSE 3030
EXPOSE 5555
CMD npx ts-node src/index.ts

ローカルでは.envファイルやdocker-composeにDATABASE_URLを定義すればPrismaがそれを読み取ってくれる。だが、AWS上ではそのようなものを持たせてないので環境変数を別途AWS上で定義する。

方法はいくつかあると思うがSystems Managerを使うことにする。公式にも

Amazon ECS を使用すると、AWS Systems Manager パラメータストア パラメータに機密データを保存してコンテナの定義でそれを参照することによって、コンテナに機密データを挿入できます。

とあるのでECSとの相性は良さそう。

パラメータストアにパラメータを定義

Systems Managerという機能群の中の1つであるパラメータストアを使い実際に環境変数を定義していく。

f:id:ri99:20211012131012p:plain

↑ここから作成

ここでは sampleServerDatabaseUrl というキーで作成する

f:id:ri99:20211012135055p:plain

コンテナに環境変数を定義

作成したキーを実際にコンテナから使用する

タスク定義を修正する必要があるので対象のタスク定義から「新しいリビジョンの作成」をクリック。

現在のコンテナをクリックして、モーダルの下の方にある「環境変数」の部分で指定する。

この時、ValueFromを選択するよう気を付ける

f:id:ri99:20211012140527p:plain

使用するタスク定義の変更

最初に書いた通り、今回はすでにサーバーが動いている状態からの変更である。

先程タスク定義の新たなリビジョンを作成したが、サービスが使用しているタスク定義は依然として古いもののままである。

なのでサービスが使うタスク定義を最新のものに変更する

変更は↓から行うことができる

f:id:ri99:20211012141137p:plain

f:id:ri99:20211012141350p:plain

なお、ここで権限のエラーが出た場合

ECSからSystems Managerの値参照しようとしたらResourceInitializationErrorが出た - プログラミングとかのお雑な備忘録

を参照

Prismaマイグレーション

今のままだとmigrateできてないのでする。DockerfileのCMDで行うことにする。CMDで複数コマンド実行したい場合は自分はシェルで定義しているのでここでもそうする。

start.sh

if [ "$NODE_ENV" = "development" ]
then
npx prisma migrate dev
npx ts-node src/index.ts
elif [ "$NODE_ENV" = "production" ]
then
npx prisma migrate deploy
npx ts-node src/index.ts
fi

Prismaは環境によってマイグレーション方法が prisma migrate dev とprisma migrate deployで別れるので環境変数NODE_ENVを定義して、その値で判断させることにする。

なのでまた「新しいリビジョンの作成」-> 既存コンテナクリック -> 環境変数のとこで追加する

f:id:ri99:20211012165034p:plain

ローカルでは.envファイルやcomposeなどにdevelopmentを定義

次に上記Dockerfileの

CMD npx ts-node src/index.ts

CMD ["./start.sh"]

に変更する。

権限を与えるため

chmod 744 ./start.sh

を実行

ECRの「プッシュコマンドの表示」に従い新たなImageをプッシュする。

タスク定義から「新しいリビジョンの作成」で先程プッシュしたImageのURIに更新。

サービスで使用するリビジョンを更新したバージョンに変更。

そうしてログを見てみると

f:id:ri99:20211012175816p:plain

こんな感じのエラーが出る。

セキュリティグループを修正してこのエラーに対応する。

セキュリティグループの修正

ECSとFargateとALBでNodeサーバーを立てる - プログラミングとかのお雑な備忘録

ここでも書いたのと同じような要領で修正セキュリティグループを修正していく。

まずサービスのセキュリティグループを確認。

ここではSample-6411

次にRDSのセキュリティグループを修正する。

[Eidit inbound rules]をから修正ページに入る。

↓このルールを追加

f:id:ri99:20211012182550p:plain

この中の選択されているグループは先程確認した Sample-6411

これで修正はOK

強制的に再デプロイして確認

↓強制的に再デプロイする方法

AWSコンソールでサービスを見つけます。 右上隅にある[更新]をクリックします。 [新しい展開を強制する]チェックボックスをオンにします。 他の構成をスキップして、[サービスの更新]をクリックします。 サービスは再デプロイされます。

<ALBのDNS>/users をブラウザのURL欄に打ち込んで確認

エラーが出ずに[]が帰って来れば無事成功!

TODO

DBは多分パブリックでアクセスできる必要ないのでプライベートにする。

プライベートバージョンからちゃんと接続できるか確認

Route53を用いた独自ドメインでの構築

参考

AWS ECS(バックエンド編)|Nuxt.js + Ruby on Rails + AWS Fargate の開発・デプロイチュートリアル

AWSの公式の記事色々