Aller au contenu

Base de données relationnelle Python

Ce générateur crée un nouveau projet de base de données relationnelle Python soutenu par Amazon Aurora (PostgreSQL ou MySQL), SQLModel pour la modélisation des données, et Alembic pour les migrations de schéma. Il génère le code d’application et l’infrastructure nécessaires pour provisionner et gérer une base de données en utilisant AWS CDK ou Terraform, avec une définition de schéma déclarative, un déploiement automatique des migrations et un client de base de données.

Exécuter ce générateur@aws/nx-plugin:py#rdb

pnpm nx g @aws/nx-plugin:py#rdb
Composez votre commande10

Requis

Options du générateur10 options
nameRequisstring

Nom du projet de base de données à générer

directorystringPar défaut: packages

Le répertoire dans lequel stocker l'application.

infraenumPar défaut: aurora

Service de base de données relationnelle à provisionner.

auroranone
engineenumPar défaut: postgres

Moteur de base de données à utiliser avec le service sélectionné.

postgresmysql
frameworkenumPar défaut: sqlmodel

Framework ORM à utiliser pour le projet généré.

sqlmodel
iacenumPar défaut: inherit

Le fournisseur IaC préféré. Par défaut, il est hérité de votre sélection initiale.

inheritcdkterraform
subDirectorystring

Le sous-répertoire dans lequel le projet est placé. Par défaut, il s'agit du nom du projet.

databaseUserstringPar défaut: dbadmin

Nom d'utilisateur administrateur de la base de données. Par défaut 'dbadmin'.

databaseNamestring

Nom initial de la base de données. Par défaut, le nom du projet.

preferInstallDependenciesbooleanPar défaut: true

Indique s'il faut privilégier l'installation des dépendances après l'exécution du générateur. Définir sur false pour différer l'installation lors du traitement par lots de plusieurs générateurs (une installation s'exécute toujours si nécessaire pour que les générateurs suivants puissent calculer le graphe de projet Nx) ; installer une seule fois à la fin.

Le générateur crée la structure de projet suivante dans le répertoire <directory>/<name> :

  • Répertoire<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
    • Répertoiremodels
      • __init__.py Model exports, imported by Alembic to discover your tables
      • example.py Example SQLModel table definition
  • Répertoiremigrations
    • versions Alembic-generated migration scripts
    • env.py Alembic environment (connects to the database)
    • script.py.mako Alembic migration script template
  • Répertoiretests
    • __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

Les scripts de développement local sont partagés entre tous les projets de base de données et générés dans packages/common/scripts/ :

  • Répertoirepackages/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)

Étant donné que ce générateur fournit de l’infrastructure en tant que code basée sur votre iac choisi, il créera un projet dans packages/common qui inclut les constructs CDK ou modules Terraform pertinents.

Le projet d’infrastructure en tant que code commun est structuré comme suit :

  • Répertoirepackages/common/constructs
    • Répertoiresrc
      • Répertoireapp/ Constructs pour l’infrastructure spécifique à un projet/générateur
      • Répertoirecore/ Constructs génériques qui sont réutilisés par les constructs dans app
      • index.ts Entry point exporting constructs from app
    • project.json Project build targets and configuration
  • Répertoirepackages/common/constructs/src
    • Répertoireapp
      • Répertoiredbs
        • <name>.ts Infrastructure spécifique à votre base de données
    • Répertoirecore
      • Répertoirerdb
        • aurora.ts Construct Aurora générique pour base de données

La base de données déployée a l’architecture suivante. Par défaut, un Amazon RDS Proxy se trouve devant le cluster Aurora pour mettre en commun les connexions et pour activer l’authentification IAM — voir Désactiver RDS Proxy pour l’alternative. L’architecture est la même que vous sélectionniez le moteur PostgreSQL ou MySQL ; seule la variante du moteur Aurora diffère.

Loading the diagram…

Le projet généré utilise SQLModel pour définir votre schéma de base de données. Le flux de travail est axé sur le modèle : ajoutez ou mettez à jour les classes de table SQLModel dans le répertoire <name>/models/ de votre projet de base de données, puis générez une migration à partir de ces modifications de modèle.

Exemple de modèle :

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))

Importez vos modèles dans <name>/models/__init__.py afin qu’Alembic puisse les découvrir lors de la génération automatique.

Après avoir ajouté ou mis à jour des modèles, utilisez Alembic pour générer et appliquer des scripts de migration. La cible alembic générée démarre automatiquement un conteneur de base de données local avant l’exécution :

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

Cela génère un nouveau script de migration dans migrations/versions/. Examinez le script généré avant de l’appliquer.

Appliquez la migration à votre base de données locale :

Terminal window
pnpm nx run <project>:migrate

Lorsque vous déployez la pile AWS, l’infrastructure générée applique automatiquement les migrations générées à la base de données déployée.

Lorsque vous récupérez des fichiers de migration créés par d’autres développeurs, appliquez-les à votre base de données locale :

Terminal window
pnpm nx run <project>:migrate

La cible alembic générée expose l’interface CLI d’Alembic, vous pouvez donc exécuter n’importe quelle commande Alembic sur la base de données locale. Consultez la référence des commandes Alembic pour les commandes disponibles.

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

L’arrêt de dev (par exemple avec Ctrl+C) supprime automatiquement le conteneur de base de données local, mais préserve le volume nommé afin que vos données persistent entre les redémarrages.

Importez session_context depuis votre package de base de données et utilisez-le comme gestionnaire de contexte asynchrone pour obtenir une 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()

Le client de base de données automatiquement :

  • Récupère la configuration de la base de données depuis AWS AppConfig à l’exécution
  • Génère des jetons d’authentification temporaires via boto3 RDS Signer pour l’authentification IAM
  • Établit des connexions TLS en utilisant ssl.create_default_context()

Le générateur de base de données relationnelle crée une infrastructure CDK ou Terraform en fonction de votre iac sélectionné.

Le construct CDK est créé dans common/constructs. Exemple d’utilisation :

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

Cela provisionne un cluster Aurora avec RDS Proxy, des identifiants administrateur, un utilisateur de base de données d’application, l’enregistrement de configuration d’exécution et un gestionnaire de migration.

L’infrastructure générée crée deux utilisateurs de base de données :

  • Utilisateur administrateur - Créé lors du provisionnement du cluster avec des identifiants stockés dans AWS Secrets Manager
  • Utilisateur d’application - Créé via une ressource personnalisée Lambda avec authentification IAM activée et privilèges DML (SELECT, INSERT, UPDATE, DELETE) sur la base de données d’application

L’utilisateur d’application est automatiquement créé avec un nom aléatoire et une authentification IAM. Le client de base de données généré est déjà configuré pour s’authentifier en tant que cet utilisateur en utilisant des jetons RDS de courte durée, de sorte que votre code d’application ne gère jamais les mots de passe de base de données.

Votre VPC doit inclure des sous-réseaux publics, des sous-réseaux privés avec sortie et des sous-réseaux privés isolés. La base de données peut s’exécuter dans des sous-réseaux privés isolés, tandis que les fonctions Lambda d’application doivent s’exécuter dans des sous-réseaux privés avec sortie afin qu’elles puissent atteindre les services AWS tels que AppConfig.

Cliquez ici pour un exemple de configuration VPC.

Utilisez le générateur connection pour connecter un projet à cette base de données — consultez le guide de connexion pour le type de calcul pertinent (par exemple FastAPI, serveur MCP, agent) pour le câblage d’infrastructure requis pour l’atteindre.

L’image Docker construite pour ce projet peut être analysée pour détecter les vulnérabilités à l’aide de Trivy, exécuté depuis l’image Trivy hébergée sur ECR.

Une cible trivy est ajoutée à votre projet qui analyse l’image construite et se termine avec un code non nul si une vulnérabilité de gravité HIGH ou CRITICAL est trouvée. Le Dockerfile généré utilise une image de base sans vulnérabilité corrigeable connue de ces gravités au moment de la génération, et met à niveau les outils fournis (tels que npm) pour maintenir cet état.

L’analyse utilise le même moteur de conteneur que votre construction d’image (docker ou finch), donc aucun outillage supplémentaire n’est requis. L’analyse n’est pas mise en cache, car l’image qu’elle lit se trouve dans le moteur de conteneur plutôt que sur le disque — elle analyse donc toujours l’image réelle et échoue bruyamment plutôt que de signaler un succès mis en cache pour une image qui n’est plus là. Chaque exécution prend donc des dizaines de secondes par image et actualise la base de données de vulnérabilités de Trivy, elle nécessite donc un accès réseau. Le script racine trivy fourni analyse chaque image dans l’espace de travail :

Terminal window
pnpm trivy

Il peut y avoir des cas où vous souhaitez supprimer une vulnérabilité spécifique, par exemple lorsqu’aucun correctif n’est encore disponible et que vous avez évalué le risque comme acceptable.

Ajoutez l’ID de vulnérabilité (un par ligne) au fichier .trivyignore à la racine de votre projet (c’est-à-dire à côté de votre project.json) :

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

Pour plus de détails sur le filtrage des résultats, consultez la documentation de filtrage Trivy.

L’infrastructure générée inclut un RDS Proxy par défaut, qui se situe entre votre application et le cluster Aurora. RDS Proxy offre plusieurs avantages :

  • Pooling de connexions - Maintient un pool de connexions à la base de données qui peuvent être partagées entre les instances d’application, réduisant ainsi la surcharge liée à l’établissement de nouvelles connexions
  • Résilience des connexions - Gère automatiquement les basculements et les reconnexions lors des remplacements d’instances Aurora ou de la maintenance
  • Authentification IAM - Prend en charge l’authentification de base de données basée sur IAM, éliminant le besoin de gérer les identifiants de base de données dans le code de votre application
  • Sécurité améliorée - Applique le chiffrement TLS pour toutes les connexions

Vous pouvez désactiver le proxy RDS comme suit :

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

Lorsque RDS Proxy est désactivé, votre application se connecte directement au point de terminaison du cluster Aurora.

Le bundle CA Amazon RDS doit être dans le magasin de confiance système du runtime.

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

Pour les fonctions Lambda déployées en zip (telles qu’une py#api FastAPI), le magasin de confiance CA intégré de l’environnement d’exécution Lambda Amazon Linux 2023 inclut les CA racine Amazon utilisés par RDS.

Lors de l’utilisation de RDS Proxy, vous n’avez pas besoin de configurer le bundle CA RDS dans le runtime qui se connecte à la base de données.

Configurez les instances d’écriture et de lecture pour votre cluster 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')],
});

Contrôlez les limites de mise à l’échelle d’Aurora Serverless v2 pour correspondre à votre charge de travail. Les deux fournisseurs utilisent par défaut un minimum de 0,5 ACU et un maximum de 4.

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

Épinglez une version spécifique du moteur Aurora.

Par défaut, l’image de conteneur de base de données locale générée correspond à la version par défaut du moteur Aurora. Si vous modifiez la version du moteur Aurora, il est recommandé d’utiliser également une version d’image de conteneur locale correspondante pour une compatibilité maximale. Consultez les notes de version AWS pour les versions Aurora PostgreSQL et les versions Aurora MySQL pour identifier la version de base de données communautaire correspondante.

L’image de base de données locale est configurée dans le champ localDev.image du fichier config.json généré à la racine de votre projet de base de données. Mettez à jour cette valeur lorsque vous changez de version de moteur.

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

Le cluster Aurora est protégé par deux garde-fous indépendants, de sorte que la désactivation de l’un seul ne peut pas supprimer vos données :

  • deletionProtection, appliqué par RDS.
  • RemovalPolicy.RETAIN, appliqué par CloudFormation, qui laisse le cluster en place lorsqu’il est retiré de la stack.

Vous pouvez désactiver la protection pour les environnements où la suppression de la base de données est attendue, comme les stacks de développement ou de prévisualisation éphémères.

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

Le construct CDK conserve le cluster Aurora par défaut (removalPolicy: RemovalPolicy.RETAIN). Modifiez ceci lorsque vous souhaitez que la suppression de la stack CDK crée un snapshot ou détruise le cluster à la place.

Lors de l’utilisation de RemovalPolicy.DESTROY, la protection contre la suppression doit également être désactivée avant que le cluster puisse être supprimé.

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

Pour un environnement éphémère où la base de données doit être supprimée avec la stack :

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

Le journal postgresql est exporté pour Aurora PostgreSQL, avec une journalisation limitée aux instructions DDL uniquement (log_statement=ddl) afin que les valeurs des paramètres des instructions ne soient jamais enregistrées — tant que chaque instruction est envoyée séparément. log_statement=ddl enregistre l’intégralité du texte brut d’un lot multi-instructions (par exemple, un seul appel psql -c "a;b;c") tel quel si une instruction du lot est DDL, y compris toutes les valeurs DML dans ce même lot.

engine = mysql

Les journaux audit et error sont exportés pour Aurora MySQLgeneral et slowquery sont délibérément exclus car ils enregistrent le texte complet des instructions, y compris les valeurs DML. Advanced Auditing est limité aux connexions et au DDL (server_audit_events=CONNECT,QUERY_DDL), de sorte que les valeurs des paramètres d’instruction ne sont jamais enregistrées.

Performance Insights est activé par défaut sur l’instance writer Aurora (chiffré avec la clé KMS du cluster). Les journaux du moteur Aurora sont également exportés vers CloudWatch Logs par défaut, configurés pour exposer l’activité au niveau du schéma sans divulguer les données de ligne.

Le volume de journaux exportés — et donc le coût d’ingestion CloudWatch Logs — évolue en fonction des modifications de schéma et des connexions plutôt que du trafic de requêtes, car les types de journaux qui contiennent le texte complet des instructions sont exclus. Sur Aurora MySQL, l’événement d’audit CONNECT est émis par connexion, de sorte que les charges de travail qui ouvrent une connexion par requête en produisent plus que celles qui utilisent un pool.

Désactivez l’export des journaux par base de données si ce n’est pas nécessaire :

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

La clé KMS utilisée pour chiffrer le cluster Aurora et son secret d’identifiants a la rotation automatique des clés activée par défaut. Désactivez-la si votre politique de sécurité gère la rotation en externe.

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

Le mot de passe de l’utilisateur administrateur (master) Aurora est généré et pivoté par Aurora lui-même dans AWS Secrets Manager, en utilisant les mots de passe d’utilisateur master gérés par RDS. Votre code d’infrastructure ne reçoit jamais le mot de passe, il ne peut donc pas fuir dans un modèle CloudFormation ou un fichier d’état Terraform. Aurora pivote le secret tous les 7 jours sans aucune fonction de rotation à déployer ou maintenir.

Le secret est chiffré avec la même clé KMS gérée par le client que le cluster.

Votre application n’utilise jamais ces identifiants. Elle se connecte en tant qu’utilisateur de base de données à privilèges minimaux en utilisant l’authentification IAM — seuls les gestionnaires de migration et de création d’utilisateur de base de données lisent le secret administrateur, et chacun se voit accorder l’accès uniquement à ce secret et à sa clé KMS.

Le secret administrateur est exposé en tant que secret.secretArn sur le cluster sous-jacent, et grantSecretRead accorde à un consommateur un accès en lecture à celui-ci :

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

Utilisez le générateur connection pour intégrer ce projet avec d’autres dans votre espace de travail. Les connexions suivantes impliquent ce projet :

Strands AgentsPythonAmazon AuroraPython
Python Agent to Relational DatabaseConnect a Python Agent to an Aurora relational database
FastAPIAmazon AuroraPython
FastAPI to Relational DatabaseConnect a FastAPI to an Aurora relational database
Model Context ProtocolPythonAmazon AuroraPython
Python MCP Server to Relational DatabaseConnect a Python MCP Server to an Aurora relational database