Créer ou étendre des constructions - AWS Conseils prescriptifs

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Créer ou étendre des constructions

Qu'est-ce qu'une construction ?

Une construction est l'élément de base d'une AWS CDK application. Une construction peut représenter une AWS ressource unique, telle qu'un bucket Amazon Simple Storage Service (Amazon S3), ou il peut s'agir d'une abstraction de niveau supérieur composée de plusieurs ressources connexes. AWS Les composants d'une construction peuvent inclure une file d'attente de travail avec sa capacité de calcul associée, ou une tâche planifiée avec des ressources de surveillance et un tableau de bord. AWS CDK Il inclut une collection de constructions appelée AWS Construct Library. La bibliothèque contient des constructions pour chaque Service AWS. Vous pouvez utiliser le Construct Hub pour découvrir des constructions supplémentaires provenant de AWS tiers et de la communauté open source AWS CDK .

Quels sont les différents types de construction ?

Il existe trois types de constructions différents pour : AWS CDK

  • Constructions L1 — Les constructions de couche 1, ou L1, sont exactement les ressources définies par CloudFormation —ni plus, ni moins. Vous devez fournir vous-même les ressources nécessaires à la configuration. Ces constructions L1 sont très basiques et doivent être configurées manuellement. Les constructions L1 ont un Cfn préfixe et correspondent directement aux spécifications. CloudFormation Services AWS Les nouveaux sont pris en charge AWS CDK dès que ces services sont CloudFormation pris en charge. CfnBucketest un bon exemple de construction L1. Cette classe représente un compartiment S3 dans lequel vous devez configurer explicitement toutes les propriétés. Nous vous recommandons de n'utiliser une construction L1 que si vous ne trouvez pas la construction L2 ou L3 correspondante.

  • Constructions L2 : les constructions Layer 2, ou L2, ont un code réutilisable et une logique de collage communs. Ces constructions comportent des valeurs par défaut pratiques et réduisent la quantité de connaissances que vous devez connaître à leur sujet. Les constructions L2 utilisent des API basées sur l'intention pour créer vos ressources et encapsulent généralement les modules L1 correspondants. Un bon exemple de construction L2 est Compartiment. Cette classe crée un compartiment S3 avec des propriétés et des méthodes par défaut, telles que le bucket. addLifeCycleRule (), qui ajoute une règle de cycle de vie au compartiment.

  • Constructions L3 : une construction Layer 3, ou L3, est appelée un modèle. Les constructions L3 sont conçues pour vous aider à effectuer des tâches courantes AWS, impliquant souvent plusieurs types de ressources. Elles sont encore plus spécifiques et mieux définies que les constructions L2 et répondent à un cas d'utilisation spécifique. Par exemple, le aws-ecs-patterns. ApplicationLoadBalancedFargateServiceconstruct représente une architecture qui inclut un cluster de AWS Fargate conteneurs utilisant un Application Load Balancer. Un autre exemple est le aws-apigateway. LambdaRestApiconstruire. Cette construction représente une API Amazon API Gateway qui est soutenue par une fonction Lambda.

À mesure que les niveaux de construction augmentent, de plus en plus d'hypothèses sont formulées quant à la manière dont ces constructions seront utilisées. Cela vous permet de fournir des interfaces avec des valeurs par défaut plus efficaces pour des cas d'utilisation très spécifiques.

Comment créer votre propre construction

Pour définir votre propre construction, vous devez suivre une approche spécifique. Cela est dû au fait que toutes les constructions étendent la classe Construct. La classe Construct est la composante de base de l'arbre de construction. Les constructions sont implémentées dans des classes qui étendent la classe de base Construct. Toutes les constructions prennent trois paramètres lorsqu'elles sont initialisées :

  • Portée — Le parent ou le propriétaire d'une construction, qu'il s'agisse d'une pile ou d'une autre construction, détermine sa place dans l'arbre des constructions. Vous devez généralement transmettre this (ou self en Python), qui représente l'objet actuel, pour la portée.

  • ID : identifiant qui doit être unique dans cette portée. L'identifiant sert d'espace de noms pour tout ce qui est défini dans la construction actuelle et est utilisé pour attribuer des identités uniques, telles que les noms de ressources et les identifiants CloudFormation logiques.

  • Accessoires — Ensemble de propriétés qui définissent la configuration initiale de la construction.

L'exemple suivant montre comment définir une construction.

import { Construct } from 'constructs'; export interface CustomProps { // List all the properties Name: string; } export class MyConstruct extends Construct { constructor(scope: Construct, id: string, props: CustomProps) { super(scope, id); // TODO } }

Création ou extension d'une construction L2

Une construction L2 représente un « composant cloud » et encapsule tout ce qui CloudFormation doit être nécessaire pour créer le composant. Une construction L2 peut contenir une ou plusieurs AWS ressources, et vous êtes libre de la personnaliser vous-même. L'avantage de créer ou d'étendre une construction L2 est que vous pouvez réutiliser les composants dans des CloudFormation piles sans redéfinir le code. Vous pouvez simplement importer la construction en tant que classe.

Lorsqu'il existe une relation « existe » avec une construction existante, vous pouvez étendre une construction existante pour ajouter des fonctionnalités par défaut supplémentaires. Il est recommandé de réutiliser les propriétés de la construction L2 existante. Vous pouvez remplacer les propriétés en les modifiant directement dans le constructeur.

L'exemple suivant montre comment s'aligner sur les bonnes pratiques et étendre une construction L2 existante appelée s3.Bucket. L'extension définit les propriétés par défaut, telles que versioned, publicReadAccess, blockPublicAccess, pour s'assurer que tous les objets (dans cet exemple, les compartiments S3) créés à partir de cette nouvelle construction auront toujours ces valeurs par défaut définies.

import * as s3 from 'aws-cdk-lib/aws-s3'; import { Construct } from 'constructs'; export class MySecureBucket extends s3.Bucket { constructor(scope: Construct, id: string, props?: s3.BucketProps) { super(scope, id, { ...props, versioned: true, publicReadAccess: false, blockPublicAccess: BlockPublicAccess.BLOCK_ALL }); } }

Création d'une construction L3

La composition est le meilleur choix lorsqu'il existe une relation « a » avec une composition de construction existante. La composition signifie que vous générez votre propre construction par-dessus d'autres constructions existantes. Vous pouvez créer votre propre modèle pour encapsuler toutes les ressources et leurs valeurs par défaut dans une seule construction L3 de niveau supérieur pouvant être partagée. L'avantage de créer vos propres constructions L3 (modèles) est que vous pouvez réutiliser les composants dans des piles sans redéfinir le code. Vous pouvez simplement importer la construction en tant que classe. Ces modèles sont conçus pour aider les consommateurs à fournir de manière concise plusieurs ressources basées sur des modèles communs avec une quantité limitée de connaissances.

L'exemple de code suivant crée une AWS CDK construction appeléeExampleConstruct. Vous pouvez utiliser cette construction comme modèle pour définir vos composants cloud.

import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; export interface ExampleConstructProps { //insert properties you wish to expose } export class ExampleConstruct extends Construct { constructor(scope: Construct, id: string, props: ExampleConstructProps) { super(scope, id); //Insert the AWS components you wish to integrate } }

L'exemple suivant montre comment importer la nouvelle construction dans votre AWS CDK application ou votre pile.

import { ExampleConstruct } from './lib/construct-name';

L'exemple suivant montre comment instancier une instance de la construction que vous avez étendue à partir de la classe de base.

import { ExampleConstruct } from './lib/construct-name'; new ExampleConstruct(this, 'newConstruct', { //insert props which you exposed in the interface `ExampleConstructProps` });

Pour plus d'informations, consultez AWS CDK Workshop dans la documentation de l' AWS CDK atelier.

Trappe de secours

Vous pouvez utiliser une trappe d'échappement dans le AWS CDK pour monter d'un niveau d'abstraction afin d'accéder au niveau inférieur des constructions. Les trappes d'évacuation sont utilisées pour étendre la construction aux fonctionnalités qui ne sont pas exposées dans la version actuelle de AWS mais disponibles dans CloudFormation.

Nous vous recommandons d'utiliser une trappe de secours dans les situations suivantes :

  • Une Service AWS fonctionnalité est disponible via CloudFormation, mais il n'existe aucune Construct construction pour elle.

  • Une Service AWS fonctionnalité est disponible CloudFormation et il existe Construct des constructions pour le service, mais celles-ci n'exposent pas encore la fonctionnalité. Comme Construct les concepts sont développés « à la main », ils peuvent parfois être en retard par rapport aux concepts liés aux CloudFormation ressources.

L'exemple de code suivant montre un cas d'utilisation courant d'une trappe de secours. Dans cet exemple, la fonctionnalité qui n'est pas encore implémentée dans la construction de niveau supérieur permet d'ajouter httpPutResponseHopLimit pour la mise à l'échelle automatique de LaunchConfiguration.

const launchConfig = autoscaling.onDemandASG.node.findChild("LaunchConfig") as CfnLaunchConfiguration; launchConfig.metadataOptions = { httpPutResponseHopLimit: autoscalingConfig.httpPutResponseHopLimit|| 2 }

L'exemple de code précédent montre le flux de travail suivant :

  1. Vous définissez votre AutoScalingGroup à l'aide d'une construction L2. La construction L2 ne prend pas en charge la mise à jour duhttpPutResponseHopLimit, vous devez donc utiliser une trappe d'évacuation.

  2. Vous accédez à la propriété node.defaultChild sur la construction AutoScalingGroup L2 et l'ajoutez comme ressource CfnLaunchConfiguration.

  3. Vous pouvez à présent définir la propriété launchConfig.metadataOptions sur la CfnLaunchConfiguration L1.

Ressources personnalisées

Vous pouvez utiliser des ressources personnalisées pour écrire une logique de provisionnement personnalisée dans des modèles qui CloudFormation s'exécutent chaque fois que vous créez, mettez à jour (si vous avez modifié la ressource personnalisée) ou supprimez des piles. Par exemple, vous pouvez utiliser une ressource personnalisée si vous souhaitez inclure des ressources qui ne sont pas disponibles dans le AWS CDK. De cette façon, vous pouvez continuer à gérer toutes les ressources connexes dans une seule pile.

La génération d'une ressource personnalisée implique l'écriture d'une fonction Lambda qui répond aux événements du cycle de vie CREATE, UPDATE et DELETE d'une ressource. Si votre ressource personnalisée ne doit effectuer qu'un seul appel d'API, envisagez d'utiliser la AwsCustomResourceconstruction. Cela permet d'effectuer des appels au SDK arbitraires lors d'un CloudFormation déploiement. Sinon, nous vous suggérons d'écrire votre propre fonction Lambda pour effectuer le travail que vous devez exécuter.

Pour plus d'informations sur les ressources personnalisées, consultez la section Ressources personnalisées dans la CloudFormation documentation. Pour un exemple d'utilisation d'une ressource personnalisée, consultez le référentiel de ressources personnalisées sur GitHub.

L'exemple suivant montre comment créer une classe de ressources personnalisée pour lancer une fonction Lambda et envoyer CloudFormation un signal de réussite ou d'échec.

import cdk = require('aws-cdk-lib'); import customResources = require('aws-cdk-lib/custom-resources'); import lambda = require('aws-cdk-lib/aws-lambda'); import { Construct } from 'constructs'; import fs = require('fs'); export interface MyCustomResourceProps { /** * Message to echo */ message: string; } export class MyCustomResource extends Construct { public readonly response: string; constructor(scope: Construct, id: string, props: MyCustomResourceProps) { super(scope, id); const fn = new lambda.SingletonFunction(this, 'Singleton', { uuid: 'f7d4f730-4ee1-11e8-9c2d-fa7ae01bbebc', code: new lambda.InlineCode(fs.readFileSync('custom-resource-handler.py', { encoding: 'utf-8' })), handler: 'index.main', timeout: cdk.Duration.seconds(300), runtime: lambda.Runtime.PYTHON_3_6, }); const provider = new customResources.Provider(this, 'Provider', { onEventHandler: fn, }); const resource = new cdk.CustomResource(this, 'Resource', { serviceToken: provider.serviceToken, properties: props, }); this.response = resource.getAtt('Response').toString(); } }

L'exemple suivant montre la logique principale de la ressource personnalisée.

def main(event, context): import logging as log import cfnresponse log.getLogger().setLevel(log.INFO) # This needs to change if there are to be multiple resources in the same stack physical_id = 'TheOnlyCustomResource' try: log.info('Input event: %s', event) # Check if this is a Create and we're failing Creates if event['RequestType'] == 'Create' and event['ResourceProperties'].get('FailCreate', False): raise RuntimeError('Create failure requested') # Do the thing message = event['ResourceProperties']['Message'] attributes = { 'Response': 'You said "%s"' % message } cfnresponse.send(event, context, cfnresponse.SUCCESS, attributes, physical_id) except Exception as e: log.exception(e) # cfnresponse's error message is always "see CloudWatch" cfnresponse.send(event, context, cfnresponse.FAILED, {}, physical_id)

L'exemple suivant montre comment la AWS CDK pile appelle la ressource personnalisée.

import cdk = require('aws-cdk-lib'); import { MyCustomResource } from './my-custom-resource'; /** * A stack that sets up MyCustomResource and shows how to get an attribute from it */ class MyStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); const resource = new MyCustomResource(this, 'DemoResource', { message: 'CustomResource says hello', }); // Publish the custom resource output new cdk.CfnOutput(this, 'ResponseMessage', { description: 'The message that came back from the Custom Resource', value: resource.response }); } } const app = new cdk.App(); new MyStack(app, 'CustomResourceDemoStack'); app.synth();