Skip to content

リレーショナルデータベース

Filter this guide Pick generator option values to hide sections that don't apply.

このジェネレーターは、Amazon Aurora(PostgreSQLまたはMySQL)とPrisma ORMを使用した新しいリレーショナルデータベースプロジェクトを作成します。AWS CDKまたはTerraformを使用してデータベースをプロビジョニングおよび管理するために必要なアプリケーションコードとインフラストラクチャを生成し、宣言的なスキーマ定義、自動マイグレーションデプロイ、型安全なORMクライアントを提供します。

リレーショナルデータベースの生成

Section titled “リレーショナルデータベースの生成”

新しいリレーショナルデータベースプロジェクトは2つの方法で生成できます:

  1. インストール Nx Console VSCode Plugin まだインストールしていない場合
  2. VSCodeでNxコンソールを開く
  3. クリック Generate (UI) "Common Nx Commands"セクションで
  4. 検索 @aws/nx-plugin - ts#rdb
  5. 必須パラメータを入力
    • クリック Generate
    パラメータ デフォルト 説明
    name 必須 string - 生成するデータベースプロジェクトの名前
    directory string packages アプリケーションを保存するディレクトリ
    subDirectory string - プロジェクトが配置されるサブディレクトリ。デフォルトではプロジェクト名になります。
    service 必須 string Aurora プロビジョニングするリレーショナルデータベースサービス
    engine 必須 string PostgreSQL 選択したサービスで使用するデータベースエンジン
    databaseUser string dbadmin データベース管理者のユーザー名。デフォルトは 'dbadmin' です。
    databaseName string - 初期データベース名。デフォルトではプロジェクト名になります。
    ormFramework 必須 string Prisma 生成されるプロジェクトで使用するORMフレームワーク
    iacProvider string Inherit 優先するIaCプロバイダー。デフォルトでは初期選択から継承されます

    ジェネレーターは<directory>/<name>ディレクトリに以下のプロジェクト構造を作成します:

    • Directoryprisma
      • Directorymodels
        • example.prisma サンプルモデル定義
      • schema.prisma メインPrismaスキーマ(モデルを参照)
    • Directoryscripts
      • docker-pull.ts ローカル開発用のデータベースDockerイメージをプル
      • docker-start.ts ローカルデータベースコンテナを起動
      • wait-for-db.ts ローカルデータベースの準備完了を待機
    • Directorysrc
      • index.ts プロジェクトのエントリーポイント
      • constants.ts ローカル開発接続の詳細とランタイム設定キー
      • prisma.ts Prismaランタイムクライアントラッパー
      • utils.ts ランタイム設定とシークレットヘルパー
      • create-db-user-handler.ts デプロイ時にアプリケーションデータベースユーザーを作成するLambdaハンドラー
      • migration-handler.ts デプロイ時にデータベースマイグレーションを実行するLambdaハンドラー
    • .gitignore 生成されたPrismaクライアント出力を含むGit無視エントリ
    • Dockerfile マイグレーションハンドラー用のコンテナイメージ定義
    • project.json プロジェクト設定とビルドターゲット
    • prisma.config.ts Prisma CLIの設定

    このジェネレータは選択した iacProvider に基づいてInfrastructure as Codeを生成するため、packages/common に関連するCDKコンストラクトまたはTerraformモジュールを含むプロジェクトを作成します。

    共通のInfrastructure as Codeプロジェクトは以下の構造を持ちます:

    • Directorypackages/common/constructs
      • Directorysrc
        • Directoryapp/ プロジェクト/ジェネレータ固有のインフラストラクチャ用コンストラクト
        • Directorycore/ app 内のコンストラクトで再利用される汎用コンストラクト
        • index.ts app からコンストラクトをエクスポートするエントリーポイント
      • project.json プロジェクトのビルドターゲットと設定
    • Directorypackages/common/constructs/src
      • Directoryapp
        • Directorydbs
          • <name>.ts データベース固有のインフラストラクチャ
      • Directorycore
        • Directoryrdb
          • aurora.ts 汎用Auroraデータベースコンストラクト

    デプロイされたデータベースは以下のアーキテクチャを持ちます。デフォルトでは、Amazon RDS ProxyがAuroraクラスターの前に配置され、接続をプールし、IAM認証を有効にします。代替案についてはRDS Proxyの無効化を参照してください。PostgreSQLまたはMySQLエンジンのどちらを選択してもアーキテクチャは同じで、Auroraエンジンのフレーバーのみが異なります。

    Application(Lambda, Agent, ...)Migrations LambdaRDS ProxyAurora(PostgreSQL or MySQL)Secrets Manager(DB credentials) SQL (IAM auth) Schema migrations Master credential rotation

    生成されたプロジェクトはPrisma ORMを使用してデータベーススキーマを定義し、型安全なクライアントを生成します。ワークフローはモデルファーストです:データベースプロジェクトのprisma/models/ディレクトリ配下にPrismaモデルファイルを追加または更新し、それらのモデル変更からマイグレーションを生成します。

    Userモデルの例:

    packages/postgres/prisma/models/user.prisma
    model User {
    id Int @id @default(autoincrement())
    firstName String
    lastName String
    }

    詳細については、公式のPrismaデータモデリングガイドを参照してください。

    データベースクライアントの生成

    Section titled “データベースクライアントの生成”

    ジェネレーターは、プロジェクトをビルドするたびに型安全なTypeScript Prismaクライアントを作成するgenerateターゲットを自動的に設定します。クライアントはgenerated/prismaに書き込まれます(.gitignoreに追加されます)。

    いつでも手動でクライアントを生成することもできます:

    Terminal window
    pnpm nx generate <your-db-project-name>

    ワークスペースルートからPrisma CLIコマンドを実行するには、prismaターゲットを使用します:

    Terminal window
    pnpm nx run <project>:prisma generate

    src/prisma.tsのランタイムラッパーは以下をエクスポートします:

    • DB_PACKAGE_NAME - AWS AppConfigのdatabaseランタイム設定名前空間で使用されるキー
    • getPrisma() - AWS AppConfigからデータベース接続設定を読み込み、IAM認証を使用してPrismaクライアントを作成

    クライアントは自動的に:

    • RUNTIME_CONFIG_APP_ID環境変数を使用してAWS AppConfigからデータベース設定を取得
    • IAM認証用にAWS RDS Signerを介して一時的な認証トークンを生成
    • 証明書検証付きのSSL/TLS接続を管理
    • 永続的なデータベース接続プールを通じて接続プーリングを処理

    prisma/models/配下のモデルを追加または更新した後、migrate devを使用してマイグレーションファイルを生成し、同時にローカルデータベースに適用します。

    生成されたprismaターゲットは、実行前にDocker経由でローカルデータベースを自動的に起動します:

    Terminal window
    pnpm nx run <project>:prisma migrate dev

    ローカルデータベースに適用せずにマイグレーションファイルのみを生成したい場合は、--create-onlyを追加します:

    Terminal window
    pnpm nx run <project>:prisma migrate dev --create-only

    これにより、スキーマが変更されるたびにprisma/migrationsに新しいマイグレーションフォルダが生成されます:

    • Directoryprisma
      • Directorymigrations
        • Directory20260405013911_initial_migrations
          • migration.sql
        • migration_lock.toml
      • schema.prisma

    AWSスタックをデプロイすると、生成されたインフラストラクチャが生成されたマイグレーションをデプロイされたデータベースに自動的に適用します。

    既存のマイグレーションの適用

    Section titled “既存のマイグレーションの適用”

    他の開発者が作成したマイグレーションファイルをプルした場合、migrate deployを使用してそれらの既存のマイグレーションをローカルデータベースに適用します。

    Terminal window
    pnpm nx run <project>:prisma migrate deploy

    このローカル開発フローでは、migrate deployはマイグレーションファイルをローカルデータベースに適用します。AWSにデータベースをデプロイするわけではありません。

    生成されたprismaターゲットはPrisma CLIを公開しているため、ローカルデータベースに対してPrismaがサポートする任意のコマンドを実行できます。利用可能なコマンドについては、Prisma CLIリファレンスを参照してください。

    Terminal window
    pnpm nx run <project>:prisma <prisma-command>

    Prisma Studioは、ローカルデータベース用のビジュアルエディタです。テーブルの閲覧、レコードの検査と編集、データのフィルタリング、リレーションのフォロー、組み込みSQLコンソールを介した生SQLの実行に使用できます。開発中のマイグレーションの検証とテストデータのシードに便利です。以下で起動します:

    Terminal window
    pnpm nx run <project>:prisma studio

    任意のTypeScriptプロジェクトで、データベースパッケージからgetPrismaをインポートして呼び出すと、型安全なPrismaクライアントが取得できます:

    import { getPrisma } from ':my-scope/db';
    const prisma = await getPrisma();
    const users = await prisma.user.findMany({ orderBy: { id: 'asc' } });

    getPrisma()は遅延初期化されたキャッシュされたクライアントを返します。同じLambda実行コンテキスト内での後続の呼び出しは、新しい接続を開くのではなく、既存の接続プールを再利用します。

    Prismaクライアントはprisma/models/スキーマから派生した完全に型付けされたモデルを公開し、データベースからAPIレスポンスまでのエンドツーエンドの型安全性を提供します。

    特定のプロジェクトタイプの場合、connectionジェネレーターを使用してデータベースを自動的に接続できます。インポート、コンテキストインジェクション、ローカル開発の依存関係を処理します:

    リレーショナルデータベースジェネレーターは、選択したiacProviderに基づいてCDKまたはTerraformインフラストラクチャを作成します。

    CDKコンストラクトはcommon/constructsに作成されます。使用例:

    packages/infra/src/stacks/application-stack.ts
    import { MyDatabase } from ':my-scope/common-constructs';
    export class ApplicationStack extends Stack {
    constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    ...
    const db = new MyDatabase(this, 'Db', {
    vpc,
    vpcSubnets: {
    subnetType: SubnetType.PRIVATE_ISOLATED,
    }
    });
    }
    }

    これにより、RDS Proxy、管理者認証情報、アプリケーションデータベースユーザー、ランタイム設定登録、マイグレーションハンドラーを備えたAuroraクラスターがプロビジョニングされます。

    生成されたインフラストラクチャは2つのデータベースユーザーを作成します:

    • 管理者ユーザー - クラスタープロビジョニング時に作成され、認証情報はAWS Secrets Managerに保存されます
    • アプリケーションユーザー - Lambda カスタムリソースを介して作成され、IAM認証が有効化され、アプリケーションデータベースに対する完全な権限を持ちます

    アプリケーションユーザーは、ランダムな名前とIAM認証で自動的に作成されます。getPrisma()は、短期間有効なRDSトークンを使用してこのユーザーとして認証するように既に設定されているため、アプリケーションコードはデータベースパスワードを処理する必要がありません。

    VPCには、パブリックサブネット、エグレス付きプライベートサブネット、プライベート分離サブネットを含める必要があります。データベースはプライベート分離サブネットで実行でき、API Lambda関数はAppConfigなどのAWSサービスに到達できるように、エグレス付きプライベートサブネットで実行する必要があります。

    packages/infra/src/stacks/application-stack.ts
    const vpc = new Vpc(this, 'Vpc', {
    subnetConfiguration: [
    {
    name: 'public',
    subnetType: SubnetType.PUBLIC,
    },
    {
    name: 'private_with_egress',
    subnetType: SubnetType.PRIVATE_WITH_EGRESS,
    },
    {
    name: 'private_isolated',
    subnetType: SubnetType.PRIVATE_ISOLATED,
    },
    ],
    });

    アプリケーションスタックで、APIをデータベースと同じVPCにデプロイし、allowDefaultPortFromgrantConnectを呼び出して、ネットワークパスを開き、各LambdaハンドラーにIAM rds-db:connect権限を付与します:

    packages/infra/src/stacks/application-stack.ts
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', { vpc, ... });
    const api = new Api(this, 'Api', {
    integrations: Api.defaultIntegrations(this)
    .withDefaultOptions({
    vpc,
    vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS },
    })
    .build(),
    });
    Object.entries(api.integrations).forEach(([operation, integration]) => {
    db.allowDefaultPortFrom(integration.handler, `Allow ${operation} to connect to the database`);
    db.grantConnect(integration.handler);
    });

    API Lambda関数は、エグレス付きプライベートサブネット(推奨)またはパブリックサブネットにデプロイし、プライベート分離サブネットにはデプロイしないでください。実行時に、getPrisma()はAWS AppConfigからデータベース接続の詳細を取得します。これはパブリックAWSサービスエンドポイントです。プライベート分離サブネット内のLambda関数は、アウトバウンドインターネットアクセスがなく、AppConfigに到達できません。エグレス付きプライベートサブネットは、パブリックサブネットにあるNAT Gatewayを介してアウトバウンドトラフィックをルーティングします。

    生成されたインフラストラクチャには、デフォルトでRDS Proxyが含まれており、アプリケーションとAuroraクラスターの間に配置されます。RDS Proxyは以下のような利点を提供します:

    • 接続プーリング - アプリケーションインスタンス間で共有できるデータベース接続のプールを維持し、新しい接続を確立するオーバーヘッドを削減します
    • 接続の回復力 - Auroraインスタンスの交換またはメンテナンス中のフェイルオーバーと再接続を自動的に処理します
    • IAM認証 - IAMベースのデータベース認証をサポートし、アプリケーションコードでデータベース認証情報を管理する必要がなくなります
    • セキュリティの向上 - すべての接続にTLS暗号化を強制します

    RDS Proxyは以下のように無効化できます:

    packages/infra/src/stacks/application-stack.ts
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', {
    ...
    enableRdsProxy: false,
    });

    RDS Proxyが無効になっている場合、アプリケーションはAuroraクラスターエンドポイントに直接接続します。

    Node.js 20以降のLambdaランタイムからAuroraクラスターに直接接続する場合、NODE_EXTRA_CA_CERTSを設定してAmazon RDS CAバンドルを読み込みます:

    packages/infra/src/stacks/application-stack.ts
    const api = new Api(this, 'Api', {
    integrations: Api.defaultIntegrations(this)
    .withDefaultOptions({
    environment: {
    NODE_EXTRA_CA_CERTS: '/var/runtime/ca-cert.pem',
    },
    })
    .build(),
    });

    詳細については、AWS LambdaのAmazon RDS接続のSSL/TLS要件およびAmazon RDS ProxyのTLSドキュメントを参照してください。RDS Proxyを使用する場合、Lambda関数でRDS CAバンドルを設定する必要はありません。

    生成されたインフラストラクチャは、ワークロード要件に合わせてカスタマイズできます。以下の例は、利用可能な一般的なカスタマイズオプションのいくつかを示しています。

    Auroraクラスターのライターとリーダーインスタンスを設定します。

    packages/infra/src/stacks/application-stack.ts
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', {
    ...
    writer: ClusterInstance.serverlessV2('writer'),
    readers: [ClusterInstance.serverlessV2('reader')],
    });

    Aurora Serverless v2のスケーリング制限を制御して、ワークロードに合わせます。

    packages/infra/src/stacks/application-stack.ts
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', {
    ...
    serverlessV2MinCapacity: 0.5,
    serverlessV2MaxCapacity: 8,
    });

    特定のAuroraエンジンバージョンを固定します。

    デフォルトでは、生成されたローカルDockerデータベースイメージはデフォルトのAuroraエンジンバージョンと一致します。Auroraエンジンバージョンを変更する場合は、最大限の互換性のために、一致するローカルDockerデータベースバージョンも使用することをお勧めします。対応するコミュニティデータベースバージョンを特定するには、Aurora PostgreSQLバージョンAurora MySQLバージョンのAWSリリースノートを参照してください。

    ローカルデータベースイメージは、生成されたデータベースプロジェクトのproject.jsonserve-localターゲットで設定されます。エンジンバージョンを変更する際は、scripts/docker-start.tsに渡されるイメージ引数を更新してください。

    engine = PostgreSQL
    packages/infra/src/stacks/application-stack.ts
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', {
    ...
    engineVersion: AuroraPostgresEngineVersion.VER_17_7,
    });
    engine = MySQL
    packages/infra/src/stacks/application-stack.ts
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', {
    ...
    engineVersion: AuroraMysqlEngineVersion.VER_3_12_0,
    });

    削除保護はデフォルトで有効になっており(CDKではdeletionProtection: true、Terraformではdeletion_protection = true)、Auroraクラスターを誤って削除から保護します。

    短期間の開発環境やプレビュースタックなど、データベースの削除が予想される環境では、削除保護を無効にできます。

    packages/infra/src/stacks/application-stack.ts
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', {
    ...
    deletionProtection: false,
    });

    CDKコンストラクトはデフォルトでAuroraクラスターを保持します(removalPolicy: RemovalPolicy.RETAIN)。CDKスタックの削除時にクラスターをスナップショットまたは破棄したい場合は、これを変更します。

    RemovalPolicy.DESTROYを使用する場合、クラスターを削除する前に削除保護も無効にする必要があります。

    packages/infra/src/stacks/application-stack.ts
    import { RemovalPolicy } from 'aws-cdk-lib';
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', {
    ...
    removalPolicy: RemovalPolicy.SNAPSHOT,
    });

    スタックと共にデータベースを削除する必要がある一時的な環境の場合:

    packages/infra/src/stacks/application-stack.ts
    import { RemovalPolicy } from 'aws-cdk-lib';
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', {
    ...
    deletionProtection: false,
    removalPolicy: RemovalPolicy.DESTROY,
    });

    Auroraクラスターとその認証情報シークレットの暗号化に使用されるKMSキーは、デフォルトで自動キーローテーションが有効になっています。セキュリティポリシーが外部でローテーションを管理している場合は、無効にします。

    packages/infra/src/stacks/application-stack.ts
    import { MyDatabase } from ':my-scope/common-constructs';
    const db = new MyDatabase(this, 'Db', {
    ...
    enableKeyRotation: false,
    });
    engine = MySQL

    MySQL: API Gatewayストリーミングモード

    Section titled “MySQL: API Gatewayストリーミングモード”

    Aurora MySQLをAPI Gatewayストリーミングレスポンス(例:tRPCのhttpBatchStreamLink)と共に使用する場合、Prisma MySQLクライアントはクエリ完了後もNode.jsイベントループを保持し続け、Lambdaがストリームをフラッシュしてリクエストを終了できなくなります。

    これを回避するには、各クエリ後にfinallyブロックでクライアントを明示的に切断し、イベントループが終了してストリーミングレスポンスが完了できるようにします。

    オプション1: プロシージャごと

    export const listExampleTable = publicProcedure
    .output(z.array(ExampleTableSchema))
    .query(async () => {
    const prisma = await getPrisma();
    try {
    return await prisma.exampleTable.findMany();
    } finally {
    await prisma.$disconnect();
    }
    });

    オプション2: tRPCミドルウェア

    ミドルウェアパターンを使用している場合は、ミドルウェアに$disconnect()呼び出しを追加して、それに基づいて構築されたすべてのプロシージャが自動的にカバーされるようにします:

    packages/api/src/middleware/db.ts
    import { getPrisma } from ':my-scope/db';
    import { initTRPC } from '@trpc/server';
    export interface IDbContext {
    db: Awaited<ReturnType<typeof getPrisma>>;
    }
    export const createDbPlugin = () => {
    const t = initTRPC.context<IDbContext>().create();
    return t.procedure.use(async (opts) => {
    const db = await getPrisma();
    try {
    return await opts.next({
    ctx: {
    ...opts.ctx,
    db,
    },
    });
    } finally {
    await db.$disconnect();
    }
    });
    };

    RDS IAM認証トークンは15分後に期限切れになります。MySQL Prismaクライアントは、getPrisma()が呼び出された時点でIAMトークンを静的な値としてキャプチャします。既存の開いている接続は影響を受けませんが、トークンの期限が切れた後に新しい接続を確立する必要がある場合、認証は失敗します。PostgreSQLアダプターは、プールが新しい接続を開くたびにトークンを動的に更新することでこれを回避しますが、MySQLアダプターには同等のメカニズムがありません。

    バッチジョブやデータマイグレーションなどの長時間実行タスクの場合は、操作全体に対して一度ではなく、各作業単位の開始時にgetPrisma()を呼び出します。getPrisma()はMySQLに対して常に新しいクライアントを作成し、新しいIAMトークンを取得するため、各接続が有効なトークンで認証されることが保証されます。