

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# コンストラクトの作成または拡張
<a name="constructs-best-practices"></a>

## コンストラクトとは
<a name="construct-definition"></a>

コンストラクトは、 AWS CDK アプリケーションの基本的な構成要素です。コンストラクトは、Amazon Simple Storage Service (Amazon S3) バケットなどの単一の AWS リソースを表すことも、複数の AWS 関連リソースで構成される高レベルの抽象化にすることもできます。コンストラクトのコンポーネントには、関連するコンピューティング能力を持つワーカーキュー、またはモニタリングリソースとダッシュボードを持つスケジュールされたジョブが含まれることがあります。には、コンストラクトライブラリと呼ばれる AWS コンストラクトのコレクション AWS CDK が含まれています。ライブラリには、すべての のコンストラクトが含まれています AWS のサービス。[Construct Hub](https://constructs.dev/search?q=&cdk=aws-cdk&cdkver=2&sort=downloadsDesc&offset=0) を使用して、、サードパーティー AWS、オープンソース AWS CDK コミュニティから追加のコンストラクトを検出できます。

## コンストラクトのさまざまなタイプ
<a name="construct-types"></a>

には 3 つの異なるタイプのコンストラクトがあります AWS CDK。
+ **L1 コンストラクト** — レイヤー 1 (L1) のコンストラクトは、まさに CloudFormation によって定義されたリソースであり、それ以上でもそれ以下でもありません。設定に必要なリソースは自分で用意しなければなりません。これらの L1 コンストラクトは非常に基本的なため、手動で設定する必要があります。 L1 コンストラクトには`Cfn`プレフィックスがあり、CloudFormation 仕様に直接対応しています。新しい AWS のサービス は、CloudFormation がこれらのサービスをサポートする AWS CDK とすぐに でサポートされます。[CfnBucket](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.CfnBucket.html) は L1 コンストラクトの良い例です。このクラスは S3 バケットを表し、すべてのプロパティを明示的に設定する必要があります。L1 コンストラクトは、L2 または L3 コンストラクトが見つからない場合にのみ使用することをお勧めします。
+ **L2 コンストラクト**— レイヤー 2 (L2) のコンストラクトには、共通の定型コードとグルーロジックがあります。これらのコンストラクトには便利なデフォルトがあり、それらについて知っておく必要がある知識の量を減らします。L2 コンストラクトは、インテントベースの APIs を使用してリソースを構築し、通常は対応する L1 モジュールをカプセル化します。L2 コンストラクトの良い例が[バケット](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3.Bucket.html)です。このクラスは、[bucket.addLifeCycleRule()](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html#add-wbr-lifecycle-wbr-rulerule) のようなデフォルトのプロパティとメソッドを使用して S3 バケットを作成し、ライフサイクルルールをバケットに追加します。
+ **L3 コンストラクト** — レイヤー 3 (L3) のコンストラクトはパターンと呼ばれます。L3 コンストラクトは、 で一般的なタスクを完了するのに役立つように設計されており AWS、多くの場合、複数の種類のリソースが含まれます。これらは L2 コンストラクトよりもさらに限定された特定用途向けとなっていて、ある決まったユースケースに使用されます。たとえば、 [aws-ecs-patterns.ApplicationLoadBalancedFargateService](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecs_patterns.ApplicationLoadBalancedFargateService.html) コンストラクトは、Application Load Balancer を使用するコンテナクラスターを含む AWS Fargate アーキテクチャを表します。もう 1 つの例として、[aws-apigateway.LambdaRestApi](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApi.html) コンストラクトがあります。このコンストラクトは Lambda 関数によってサポートされている Amazon API Gateway API を表しています。

コンストラクトレベルが高くなるにつれて、これらのコンストラクトがどのように使用されるかについて、より多くの仮定がなされます。これにより、極めて特殊なユースケースに対して、より効果的なデフォルトをインターフェイスに提供できるようになります。

## 独自のコンストラクトを作成する方法
<a name="create-construct"></a>

独自のコンストラクトを定義するには、特定の方法に従う必要があります。これは、すべてのコンストラクトが `Construct` クラスを拡張するためです。`Construct` クラスはコンストラクトツリーの構成要素です。コンストラクトは、`Construct` 基本クラスを拡張するクラスで実装されます。すべてのコンストラクトは、初期化時に次の 3 つのパラメータを取ります。
+ **スコープ** – コンストラクトの親または所有者、スタック、またはコンストラクトツリー内の場所を決定する別のコンストラクト。通常は `this` (または Python の `self`) にパスしなければならず、それがスコープの現在のオブジェクトを表します。
+ **id** — このスコープ内で一意でなければならない識別子です。識別子は、現在のコンストラクト内で定義されているすべての名前空間として機能し、リソース名や CloudFormation 論理 IDs などの一意の ID を割り当てるために使用されます。
+ **Props** – コンストラクトの初期設定を定義する一連のプロパティ。

次の例は、コンストラクトを定義する方法を示しています。

```
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
  }
}
```

## L2 コンストラクトの作成または拡張
<a name="create-l2-construct"></a>

L2 コンストラクトは「クラウドコンポーネント」を表し、CloudFormation がコンポーネントを作成するために必要なすべてのものをカプセル化します。L2 コンストラクトには 1 つ以上の AWS リソースを含めることができ、自分でコンストラクトをカスタマイズできます。L2 コンストラクトを作成または拡張することの利点は、コードを再定義しなくても CloudFormation スタックのコンポーネントを再利用できることです。コンストラクトをクラスとしてインポートするだけで済みます。

既存のコンストラクトとの「is a」関係がある場合は、既存のコンストラクトを拡張してデフォルトの機能を追加できます。既存の L2 コンストラクトのプロパティを再利用するのがベストプラクティスです。コンストラクターでプロパティを直接変更することで、プロパティを上書きできます。

次の例は、ベストプラクティスに沿って、`s3.Bucket` という既存の L2 コンストラクトを拡張する方法を示しています。この拡張は、`versioned`、`publicReadAccess`、`blockPublicAccess` のようなデフォルトプロパティを設定し、この新しいコンストラクトから作成されたすべてのオブジェクト (この例では S3 バケット) に、これらのデフォルト値が常に設定されるようにします。

```
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: s3.BlockPublicAccess.BLOCK_ALL
    });
  }
}
```

## L3 コンストラクトの作成
<a name="create-l3-construct"></a>

コンポジションは、既存のコンストラクトコンポジションと「関係がある」場合に適しています。コンポジションとは、他の既存のコンストラクトに独自のコンストラクトを構築することです。独自のパターンを作成して、すべてのリソースとそのデフォルト値を、共有可能な単一上位レベルの L3 コンストラクトにカプセル化できます。独自の L3 コンストラクト (パターン) を作成する利点は、コードを再定義しなくてもコンポーネントをスタックで再利用できることです。コンストラクトをクラスとしてインポートするだけで済みます。これらのパターンは、消費者が共通のパターンに基づいて、限られた知識で複数のリソースを簡潔にプロビジョニングできるように設計されています。

次のコード例では、 という AWS CDK コンストラクトを作成します`ExampleConstruct`。このコンストラクトをテンプレートとして使用して、クラウドコンポーネントを定義できます。

```
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
  }
}
```

次の例は、新しく作成されたコンストラクトを AWS CDK アプリケーションまたはスタックにインポートする方法を示しています。

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

次の例は、基本クラスから拡張したコンストラクトのインスタンスをインスタンス化する方法を示しています。

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

new ExampleConstruct(this, 'newConstruct', {
  //insert props which you exposed in the interface `ExampleConstructProps`
});
```

詳細については、[AWS CDK ワークショップ](https://cdkworkshop.com/)ドキュメントの AWS CDK 「ワークショップ」を参照してください。

## エスケープハッチ
<a name="escape-hatch"></a>

でエスケープハッチを使用して抽象化レベル AWS CDK を上げると、より低いレベルのコンストラクトにアクセスできます。エスケープハッチは、 の最新バージョンでは公開されていない AWS が CloudFormation で利用可能な機能のコンストラクトを拡張するために使用されます。

次のようなシナリオでは、エスケープハッチの使用を推奨します。
+  AWS のサービス 機能は CloudFormation を通じて使用できますが、`Construct`コンストラクトはありません。
+  AWS のサービス 機能は CloudFormation を通じて利用でき、サービスの`Construct`コンストラクトがありますが、まだこの機能を公開していません。と言うのも、`Construct` コンストラクトの開発は「手作業で」行われるため、CloudFormation リソースコンストラクトよりも遅れる場合があるからです。

次のコード例は、エスケープハッチを使用する一般的なユースケースを示しています。この例では、上位レベルのコンストラクトにはまだ実装されていない機能を、オートスケーリング `LaunchConfiguration` 用の `httpPutResponseHopLimit` に追加するためのものです。

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

前述のコード例は、次のワークフローを示しています。

1. L2 コンストラクトを使用して `AutoScalingGroup` を定義します。L2 コンストラクトは の更新をサポートしていないため`httpPutResponseHopLimit`、エスケープハッチを使用する必要があります。

1. `node.findChild()` メソッドを使用して L2 `AutoScalingGroup`コンストラクトの特定の`LaunchConfig`子を見つけ、`CfnLaunchConfiguration`リソースとしてキャストします。

1. これで、L1 `CfnLaunchConfiguration` の `launchConfig.metadataOptions` のプロパティを設定できるようになりました。

## カスタムリソース
<a name="custom-resource"></a>

カスタムリソースを使用すると、テンプレートにカスタムのプロビジョニングロジックを書き込むことができ、スタックを作成、更新 (カスタムリソースを変更した場合)、削除するたびに CloudFormation がそれを実行します。たとえば、 で利用できないリソースを含める場合は、カスタムリソースを使用できます AWS CDK。この方法により、すべての関連リソースを 1 つのスタックで管理できます。

カスタムリソースを構築するには、リソースの CREATE、UPDATE、DELETE ライフサイクルイベントに応答する Lambda 関数を書き込む必要があります。カスタムリソースが API を呼び出せるのが 1 回だけである場合には、[AwsCustomResource](https://github.com/awslabs/aws-cdk/tree/master/packages/%40aws-cdk/custom-resources) コンストラクトの使用を検討してください。これにより、CloudFormation のデプロイ中に任意の SDK 呼び出しを実行することが可能となります。それ以外の場合は、必要な作業を実行するための独自の Lambda 関数を作成することを推奨します。

カスタムリソースの詳細については、CloudFormation ドキュメントの「[カスタムリソース](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html)」を参照してください。カスタムリソースの使用例については、GitHub の「[Custom Resource](https://github.com/aws-samples/aws-cdk-examples/tree/master/typescript/custom-resource/)」リポジトリを参照してください。

次の例は、Lambda 関数を開始して CloudFormation に成功または失敗シグナルを送信する、カスタムリソースクラスの作成方法を示しています。

```
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();
    }
}
```

次の例は、カスタムリソースの主なロジックです。

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

次の例は、 AWS CDK スタックがカスタムリソースを呼び出す方法を示しています。

```
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();
```