Skip to content

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

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

リレーショナルデータベースを生成する

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

このジェネレーターを実行@aws/nx-plugin:py#rdb

pnpm nx g @aws/nx-plugin:py#rdb
コマンドを組み立てる10

必須

ジェネレーターオプション10 オプション
name必須string

生成するデータベースプロジェクトの名前

directorystringデフォルト: packages

アプリケーションを格納するディレクトリ。

infraenumデフォルト: aurora

プロビジョニングするリレーショナルデータベースサービス。

auroranone
engineenumデフォルト: postgres

選択したサービスで使用するデータベースエンジン。

postgresmysql
frameworkenumデフォルト: sqlmodel

生成されるプロジェクトで使用するORMフレームワーク。

sqlmodel
iacenumデフォルト: inherit

優先するIaCプロバイダー。デフォルトでは初期選択から継承されます。

inheritcdkterraform
subDirectorystring

プロジェクトが配置されるサブディレクトリ。デフォルトではプロジェクト名になります。

databaseUserstringデフォルト: dbadmin

データベース管理者のユーザー名。デフォルトは 'dbadmin' です。

databaseNamestring

初期データベース名。デフォルトはプロジェクト名になります。

preferInstallDependenciesbooleanデフォルト: true

ジェネレーター実行後に依存関係のインストールを優先するかどうか。複数のジェネレーターをバッチ処理する際にインストールを延期する場合は false に設定します(後続のジェネレーターがNxプロジェクトグラフを計算できるよう、必要に応じてインストールは実行されます)。最後に一度だけインストールします。

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

  • Directory<name>
    • __init__.py Package exports
    • connection.py Database engine and session factory with IAM authentication
    • utils.py Runtime config and local development helpers
    • migration_handler.py Lambda handler that runs Alembic migrations during deployment
    • create_db_user_handler.py Lambda handler that creates the application database user during deployment
    • Directorymodels
      • __init__.py Model exports, imported by Alembic to discover your tables
      • example.py Example SQLModel table definition
  • Directorymigrations
    • versions Alembic-generated migration scripts
    • env.py Alembic environment (connects to the database)
    • script.py.mako Alembic migration script template
  • Directorytests
    • __init__.py Module initialisation
    • conftest.py Test configuration
    • test_noop.py Placeholder test
  • alembic.ini Alembic configuration
  • config.json Local development connection details and runtime config key
  • Dockerfile.migration Container image for the migration handler
  • Dockerfile.create-db-user Container image for the create-db-user handler
  • project.json Project configuration and build targets
  • pyproject.toml Packaging configuration file used by UV
  • README.md Project README
  • .python-version Contains the project’s Python version
  • .gitignore Files excluded from version control

ローカル開発スクリプトはすべてのデータベースプロジェクト間で共有され、packages/common/scripts/ に生成されます:

  • Directorypackages/common/scripts/src/rdb
    • pull-image.ts Pulls the database container image
    • start-container.ts Starts a local database container
    • wait-for-postgres-db.ts Waits for the local database to be ready (PostgreSQL)
    • wait-for-mysql-db.ts Waits for the local database to be ready (MySQL)

このジェネレーターは、選択した iac に基づいてインフラストラクチャをコードとして提供するため、関連する CDK コンストラクトまたは Terraform モジュールを含む packages/common にプロジェクトを作成します。

共通のインフラストラクチャコードプロジェクトは、次のように構成されています:

  • 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 エンジンのフレーバーのみです。

Loading the diagram…

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

モデルの例:

packages/my_db/my_db/models/example.py
from sqlalchemy import Column, String
from sqlmodel import Field, SQLModel
class ExampleModel(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str = Field(sa_column=Column(String(255), nullable=False))
description: str | None = Field(default=None, sa_column=Column(String(255), nullable=True))

Alembic が自動生成中にモデルを検出できるように、<name>/models/__init__.py でモデルをインポートしてください。

モデルを追加または更新した後、Alembic を使用してマイグレーションスクリプトを生成および適用します。生成された alembic ターゲットは、実行前に自動的にローカルデータベースコンテナを起動します:

Terminal window
pnpm nx run <project>:alembic revision --autogenerate -m "describe your change"

これにより、migrations/versions/ 配下に新しいマイグレーションスクリプトが生成されます。適用する前に生成されたスクリプトを確認してください。

ローカルデータベースにマイグレーションを適用します:

Terminal window
pnpm nx run <project>:migrate

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

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

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

他の開発者が作成したマイグレーションファイルをプルした場合、ローカルデータベースに適用します:

Terminal window
pnpm nx run <project>:migrate

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

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

dev を停止すると(例:Ctrl+C で)、ローカルデータベースコンテナは自動的に削除されますが、名前付きボリュームは保持されるため、再起動してもデータは保持されます。

データベースパッケージから session_context をインポートし、非同期コンテキストマネージャーとして使用して AsyncSession を取得します:

from sqlmodel import select
from my_scope_my_db import session_context
from my_scope_my_db.models.example import ExampleModel
async def example():
async with session_context() as session:
results = (await session.execute(select(ExampleModel))).scalars().all()

データベースクライアントは自動的に:

  • 実行時に AWS AppConfig からデータベース設定を取得します
  • IAM 認証用に boto3 RDS Signer を介して一時的な認証トークンを生成します
  • ssl.create_default_context() を使用して TLS 接続を確立します

リレーショナルデータベースジェネレーターは、選択した iac に基づいて 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 認証が有効化され、アプリケーションデータベースに対する DML 権限(SELECT、INSERT、UPDATE、DELETE)が付与されます

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

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

VPC 設定の例については、こちらをクリックしてください。

connection ジェネレーターを使用して、プロジェクトをこのデータベースに接続します。データベースに到達するために必要なインフラストラクチャの配線については、関連するコンピュートタイプ(FastAPI、MCP サーバー、エージェントなど)の接続ガイドを参照してください。

このプロジェクト用にビルドされた Docker イメージは、ECR ホスト版 Trivy イメージから実行される Trivy を使用して脆弱性をスキャンできます。

プロジェクトに trivy ターゲットが追加され、ビルドされたイメージをスキャンし、HIGH または CRITICAL の深刻度の脆弱性が見つかった場合は非ゼロで終了します。生成された Dockerfile は、生成時点でこれらの深刻度の既知の修正可能な脆弱性がないベースイメージを使用し、バンドルされたツール(npm など)をアップグレードしてその状態を維持します。

スキャンはイメージビルドと同じコンテナエンジン(docker または finch)を使用するため、追加のツールは必要ありません。スキャンはキャッシュされません。これは、読み取るイメージがディスク上ではなくコンテナエンジン内に存在するためです — そのため、常に実際のイメージをスキャンし、もはや存在しないイメージに対してキャッシュされた合格を報告するのではなく、明確に失敗します。したがって、各実行はイメージごとに数十秒かかり、Trivy の脆弱性データベースを更新するため、ネットワークアクセスが必要です。提供される trivy ルートスクリプトは、ワークスペース内のすべてのイメージをスキャンします:

Terminal window
pnpm trivy

特定の脆弱性を抑制したい場合があります。たとえば、まだ修正が利用できず、リスクを許容可能と評価した場合などです。

脆弱性 ID(1 行に 1 つ)をプロジェクトのルート(つまり project.json の隣)にある .trivyignore ファイルに追加します:

.trivyignore
# node-tar arbitrary file write - not exploitable in our usage
CVE-2024-XXXXX

検出結果のフィルタリングの詳細については、Trivy フィルタリングドキュメントを参照してください。

生成されたインフラストラクチャには、デフォルトで RDS Proxy が含まれており、アプリケーションと Aurora クラスターの間に配置されます。RDS Proxy にはいくつかの利点があります:

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

次のように RDS プロキシを無効にできます:

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 クラスターエンドポイントに直接接続します。

RDS Proxy を使用せずに接続する場合の SSL 要件

Section titled “RDS Proxy を使用せずに接続する場合の SSL 要件”

Amazon RDS CA バンドルは、ランタイムのシステムトラストストアに含まれている必要があります。

ADD https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem /etc/pki/ca-trust/source/anchors/global-bundle.pem
RUN update-ca-trust

zip デプロイされた Lambda 関数(py#api FastAPI など)の場合、Amazon Linux 2023 Lambda 実行環境の組み込み CA トラストストアには、RDS で使用される Amazon ルート CA が含まれています。

RDS Proxy を使用する場合、データベースに接続するランタイムで 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 のスケーリング制限を制御します。両方のプロバイダーは、デフォルトで最小 0.5 ACU、最大 4 ACU に設定されています。

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 エンジンバージョンを固定します。

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

ローカルデータベースイメージは、データベースプロジェクトルートにある生成された config.json ファイルの localDev.image フィールドで設定されます。エンジンバージョンを変更する際は、その値を更新してください。

engine = postgres
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,
});

Auroraクラスターは2つの独立したガードによって保護されているため、どちらか一方をオフにしただけではデータを削除できません:

  • deletionProtection、RDSによって強制されます。
  • RemovalPolicy.RETAIN、CloudFormationによって強制され、スタックから削除されてもクラスターをそのまま残します。

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

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,
});

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,
});
engine = postgres

postgresql ログは Aurora PostgreSQL 用にエクスポートされ、ログは DDL ステートメントのみにスコープされています(log_statement=ddl)。そのため、各ステートメントが個別に送信される限り、ステートメントのパラメータ値はログに記録されません。log_statement=ddl は、複数ステートメントのバッチ(例:単一の psql -c "a;b;c" 呼び出し)の生のテキスト全体を、そのバッチ内のいずれかのステートメントが DDL である場合、同じバッチ内の DML 値を含めてそのまま記録します。

engine = mysql

audit および error ログは Aurora MySQL 用にエクスポートされます — general および slowquery は、DML 値を含む完全なステートメントテキストをログに記録するため、意図的に除外されています。Advanced Auditing は接続と DDL にスコープされており(server_audit_events=CONNECT,QUERY_DDL)、ステートメントパラメータ値はログに記録されません。

Performance Insights は、デフォルトで Aurora ライターインスタンスで有効になっています(クラスターの KMS キーで暗号化されます)。Aurora エンジンログもデフォルトで CloudWatch Logs にエクスポートされ、行データを漏洩させることなくスキーマレベルのアクティビティを表示するように設定されています。

エクスポートされるログ量、つまり CloudWatch Logs の取り込みコスト は、クエリトラフィックではなくスキーマ変更と接続数に応じてスケールします。これは、完全なステートメントテキストを含むログタイプが除外されているためです。Aurora MySQL では、CONNECT 監査イベントが接続ごとに発行されるため、リクエストごとに接続を開くワークロードは、プールを使用するワークロードよりも多くのログを生成します。

必要ない場合は、データベースごとにログエクスポートを無効にします:

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

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

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

Auroraの管理者(マスター)ユーザーのパスワードは、RDS管理のマスターユーザーパスワードを使用して、Aurora自身がAWS Secrets Managerで生成およびローテーションします。インフラストラクチャコードはパスワードを受け取らないため、CloudFormationテンプレートやTerraformステートファイルに漏洩することはありません。Auroraは、デプロイや保守が必要なローテーション関数なしで、7日ごとにシークレットをローテーションします。

シークレットは、クラスターと同じカスタマー管理のKMSキーで暗号化されます。

アプリケーションはこれらの認証情報を使用しません。IAM認証を使用して最小権限のデータベースユーザーとして接続します。管理者シークレットを読み取るのは、マイグレーションハンドラーとcreate-db-userハンドラーのみであり、それぞれはそのシークレットとそのKMSキーへのアクセスのみが許可されます。

管理者シークレットは、基盤となるクラスターのsecret.secretArnとして公開され、grantSecretReadはコンシューマーにそれへの読み取りアクセスを許可します:

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

connection ジェネレーターを使用して、このプロジェクトをワークスペース内の他のプロジェクトと統合します。このプロジェクトに関連する接続は以下の通りです:

Strands AgentsPythonAmazon AuroraPython
Python Agent to Relational DatabasePython Agent を Aurora リレーショナルデータベースに接続する
FastAPIAmazon AuroraPython
FastAPI to Relational DatabaseFastAPI を Aurora リレーショナルデータベースに接続する
Model Context ProtocolPythonAmazon AuroraPython
Python MCP Server to Relational DatabasePython MCP Server を Aurora リレーショナルデータベースに接続する