

これは AWS CDK v2 デベロッパーガイドです。旧版の CDK v1 は 2022 年 6 月 1 日にメンテナンスを開始し、2023 年 6 月 1 日にサポートを終了しました。

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

# CDK Pipelines を使用した継続的インテグレーションと継続的デリバリー (CI/CD)
<a name="cdk-pipeline"></a>

AWS コンストラクトライブラリの [CDK Pipelines](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines-readme.html) モジュールを使用して、AWS CDK アプリケーションの継続的デリバリーを設定します。CDK アプリのソースコードを AWS CodeCommit、GitHub、または AWS CodeStar にコミットすると、CDK Pipelines が自動的に新しいバージョンのビルド、テスト、デプロイを行います。

CDK Pipelines は自動更新です。アプリケーションステージまたはスタックを追加すると、パイプラインは自動的に再設定され、それらの新しいステージまたはスタックがデプロイされます。

**注記**  
CDK Pipelines は 2 つの API をサポートしています。1 つは、CDK Pipelines 開発者プレビューで利用可能になった元の API です。もう 1 つは、プレビューフェーズで受け取った CDK 顧客からのフィードバックが組み込まれた、最新の API です。このトピックの例では、最新の API を使用しています。2 つのサポートされている API の違いの詳細については、「*aws-cdk GitHub リポジトリ*」の「[CDK Pipelines オリジナル API](https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/pipelines/ORIGINAL_API.md)」を参照してください。

## AWS 環境のブートストラップ
<a name="cdk-pipeline-bootstrap"></a>

CDK Pipelines を使用する前に、スタックをデプロイする AWS [環境](environments.md)をブートストラップする必要があります。

CDK パイプラインには、少なくとも 2 つの環境が含まれます。1 つめの環境は、パイプラインがプロビジョニングされる場所です。2 つめの環境は、アプリケーションのスタックまたはステージをデプロイする場所です (ステージは関連するスタックのグループです)。これらの環境は同じにすることができますが、ベストプラクティスとしては、異なる環境でステージを分離することをおすすめします。

**注記**  
ブートストラップによって作成されるリソースの種類と、ブートストラップスタックをカスタマイズする方法については、「[AWS ブートストラップ](bootstrapping.md)」を参照してください。

CDK Pipelines での継続的なデプロイでは、CDK Toolkit スタックに以下を含める必要があります。
+ 1 つの Amazon Simple Storage Service (Amazon S3) バケット
+ Amazon ECR リポジトリ
+ パイプラインのさまざまな部分に必要なアクセス許可を付与する IAM ロール

CDK Toolkit は、既存のブートストラップスタックをアップグレードするか、必要に応じて新しいブートストラップスタックを作成します。

AWS CDK パイプラインをプロビジョニングできる環境をブートストラップするには、以下の例に示すように `cdk bootstrap` を呼び出します。`npx` コマンドを使用して AWS CDK Toolkit を呼び出すと、必要に応じて一時的にインストールされます。また、現在のプロジェクトにインストールされている Toolkit が存在する場合は、そのバージョンも使用します。

 `--cloudformation-execution-policies` は、将来の CDK Pipelines デプロイを実行するポリシーの ARN を指定します。デフォルトの `AdministratorAccess` ポリシーにより、あらゆるタイプの AWS リソースをデプロイできるパイプラインが確実に作成されます。このポリシーを使用する場合は、AWS CDK アプリを構成するすべてのコードと依存関係を信頼するようにしてください。

ほとんどの組織は、自動化によってデプロイできるリソースの種類をより厳しく制御することを義務付けています。組織内の適切な部門に問い合わせて、パイプラインが使用するポリシーを決定します。

デフォルトの AWS プロファイルに必要な認証設定と AWS リージョンが含まれている場合は、`--profile` オプションを省略できます。

**Example**  

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER>/<REGION> --profile <ADMIN-PROFILE> \
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
```

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER></REGION> --profile< ADMIN-PROFILE> ^
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess
```

パイプラインによって AWS CDK アプリケーションがデプロイされる追加の環境をブートストラップするには、代わりに以下のコマンドを使用します。`--trust` オプションは、AWS CDK アプリケーションをこの環境にデプロイするアクセス許可を、他のどのアカウントに付与するかを指定します。このオプションでは、パイプラインの AWS アカウント ID を指定します。

ここでも、デフォルトの AWS プロファイルに必要な認証設定と AWS リージョンが含まれている場合は、`--profile` オプションを省略できます。

**Example**  

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER>/<REGION> --profile <ADMIN-PROFILE> \
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess \
    --trust <PIPELINE-ACCOUNT-NUMBER>
```

```
npx cdk bootstrap aws://<ACCOUNT-NUMBER>/<REGION> --profile <ADMIN-PROFILE> ^
    --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess ^
    --trust <PIPELINE-ACCOUNT-NUMBER>
```

**ヒント**  
管理認証情報は、ブートストラップと初期パイプラインのプロビジョニングにのみ使用します。その後、ローカルマシンではなくパイプライン自体を使用して変更をデプロイします。

レガシーブートストラップ環境をアップグレードする場合、新しいバケットが作成されると、以前の Amazon S3 バケットは孤立します。これは、Amazon S3 コンソールを使用して手動で削除してください。

### ブートストラップスタックの削除からの保護
<a name="cdk-pipeline-protect"></a>

ブートストラップスタックが削除されると、CDK デプロイをサポートするために環境で最初にプロビジョニングされた AWS リソースも削除されます。これにより、パイプラインの動作が停止します。これが起きると、復旧のための一般的なソリューションはありません。

環境がブートストラップされた後は、環境のブートストラップスタックの削除と再作成は行わないでください。代わりに、`cdk bootstrap` コマンドを再度実行して、ブートストラップスタックを新しいバージョンに更新してみてください。

ブートストラップスタックが誤って削除されないように保護するには、終了保護を有効にする `--termination-protection` オプションに `cdk bootstrap` コマンドを指定することをおすすめします。新規または既存のブートストラップスタックで終了保護を有効にすることができます。このオプションの詳細については、「` --termination-protection `」を参照してください。

終了保護を有効にした後、AWS CLI または CloudFormation コンソールを使用して検証できます。

1. 次のコマンドを実行して、新規または既存のブートストラップスタックで終了保護を有効にします。

   ```
   $ cdk bootstrap --termination-protection
   ```

1. AWS CLI または CloudFormation コンソールを使用して確認します。以下に示しているのは、AWS CLI を使用した例です。ブートストラップスタック名を変更した場合は、`CDKToolkit` をスタック名に置き換えます。

   ```
   $ aws cloudformation describe-stacks --stack-name <CDKToolkit> --query "Stacks[0].EnableTerminationProtection"
   true
   ```

## プロジェクトの初期化
<a name="cdk-pipeline-init"></a>

新しい空の GitHub プロジェクトを作成し、`my-pipeline` ディレクトリ内のワークステーションにクローンします。(このトピックのコード例では、GitHub を使用します。AWS CodeStar または AWS CodeCommit を使用することもできます。)

```
git clone <GITHUB-CLONE-URL> my-pipeline
cd my-pipeline
```

**注記**  
アプリのメインディレクトリには、`my-pipeline` 以外の名前を使用できます。ただし、その場合は、このトピックの後半でファイルとクラス名を調整する必要があります。これは、AWS CDK ツールキットの一部のファイル名とクラス名がメインディレクトリの名前に基づいているためです。

クローンを作成したら、通常どおりにプロジェクトを初期化します。

**Example**  

```
$ cdk init app --language typescript
```

```
$ cdk init app --language javascript
```

```
$ cdk init app --language python
```
アプリを作成したら、以下の 2 つのコマンドも入力します。これにより、アプリの Python 仮想環境がアクティブ化され、AWS CDK コア依存関係がインストールされます。  

```
$ source .venv/bin/activate # On Windows, run `.\venv\Scripts\activate` instead
$ python -m pip install -r requirements.txt
```

```
$ cdk init app --language java
```
IDE を使用している場合は、これでプロジェクトを開くかインポートできるようになります。たとえば Eclipse では、**[ファイル]**、**[インポート]**、**[Maven]**、**[既存の Maven プロジェクト]** を選択します。プロジェクト設定が Java 8 (1.8) を使用するように設定されていることを確認してください。

```
$ cdk init app --language csharp
```
Visual Studio を使用している場合は、`src` ディレクトリでソリューションファイルを開きます。

```
$ cdk init app --language go
```
アプリを作成したら、以下のコマンドを入力して、アプリに必要な AWS コンストラクトライブラリモジュールをインストールします。  

```
$ go get
```

**重要**  
`cdk.json` および `cdk.context.json` ファイルは必ずソースコントロールにコミットしてください。コンテキスト情報 (AWS アカウントから取得した特徴量フラグやキャッシュされた値など) は、プロジェクトの状態の一部です。値は環境ごとに異なる場合があり、結果として予期せぬ変更が生じる可能性があります。詳細については、「[コンテキスト値と AWS CDK](context.md)」を参照してください。

## パイプラインを定義する
<a name="cdk-pipeline-define"></a>

CDK Pipelines アプリケーションには、少なくとも 2 つのスタックが含まれます。1 つはパイプライン自体を表すスタックで、もう 1 つかそれ以上は、それを通してデプロイされたアプリケーションを表すスタックです。スタックは*ステージ*にグループ化することもできます。ステージを使用して、インフラストラクチャスタックのコピーをさまざまな環境にデプロイできます。ひとまずはパイプラインを検討し、後ほどにはデプロイするアプリケーションについて掘り下げていきます。

コンストラクト ` [CodePipeline](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.CodePipeline.html) ` は、AWS をデプロイエンジンとして使用する CDK Pipelines を表すコンストラクトです。`CodePipeline` をスタックでインスタンス化する場合は、パイプラインのソースの場所 (GitHub リポジトリなど) を定義します。また、アプリケーションを構築するためのコマンドも定義します。

たとえば、ソースが GitHub リポジトリに保存されているパイプラインを以下に示します。これには、TypeScript CDK アプリケーションのビルドステップも含まれています。GitHub リポジトリに関する情報を、指定された場所に入力します。

**注記**  
デフォルトでは、パイプラインは、Secrets Manager に `github-token` という名前で保存されている個人用アクセストークンを使用して GitHub を認証します。

また、パイプラインスタックのインスタンス化を更新して、AWS アカウントとリージョンを指定する必要があります。

**Example**  
`lib/my-pipeline-stack.ts` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';

export class MyPipelineStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });
  }
}
```
`bin/my-pipeline.ts` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { MyPipelineStack } from '../lib/my-pipeline-stack';

const app = new cdk.App();
new MyPipelineStack(app, 'MyPipelineStack', {
  env: {
    account: '111111111111',
    region: 'eu-west-1',
  }
});

app.synth();
```
`lib/my-pipeline-stack.js` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
const cdk = require('aws-cdk-lib');
const { CodePipeline, CodePipelineSource, ShellStep } = require('aws-cdk-lib/pipelines');

 class MyPipelineStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });
  }
}

module.exports = { MyPipelineStack }
```
`bin/my-pipeline.js` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
#!/usr/bin/env node

const cdk = require('aws-cdk-lib');
const { MyPipelineStack } = require('../lib/my-pipeline-stack');

const app = new cdk.App();
new MyPipelineStack(app, 'MyPipelineStack', {
  env: {
    account: '111111111111',
    region: 'eu-west-1',
  }
});

app.synth();
```
`my-pipeline/my-pipeline-stack.py` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
import aws_cdk as cdk
from constructs import Construct
from aws_cdk.pipelines import CodePipeline, CodePipelineSource, ShellStep

class MyPipelineStack(cdk.Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        pipeline =  CodePipeline(self, "Pipeline",
                        pipeline_name="MyPipeline",
                        synth=ShellStep("Synth",
                            input=CodePipelineSource.git_hub("OWNER/REPO", "main"),
                            commands=["npm install -g aws-cdk",
                                "python -m pip install -r requirements.txt",
                                "cdk synth"]
                        )
                    )
```
`app.py` に作成  

```
#!/usr/bin/env python3
import aws_cdk as cdk
from my_pipeline.my_pipeline_stack import MyPipelineStack

app = cdk.App()
MyPipelineStack(app, "MyPipelineStack",
    env=cdk.Environment(account="111111111111", region="eu-west-1")
)

app.synth()
```
`src/main/java/com/myorg/MyPipelineStack.java` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
package com.myorg;

import java.util.Arrays;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.pipelines.CodePipeline;
import software.amazon.awscdk.pipelines.CodePipelineSource;
import software.amazon.awscdk.pipelines.ShellStep;

public class MyPipelineStack extends Stack {
    public MyPipelineStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
             .pipelineName("MyPipeline")
             .synth(ShellStep.Builder.create("Synth")
                .input(CodePipelineSource.gitHub("OWNER/REPO", "main"))
                .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                .build())
             .build();
    }
}
```
`src/main/java/com/myorg/MyPipelineApp.java` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
package com.myorg;

import software.amazon.awscdk.App;
import software.amazon.awscdk.Environment;
import software.amazon.awscdk.StackProps;

public class MyPipelineApp {
    public static void main(final String[] args) {
        App app = new App();

        new MyPipelineStack(app, "PipelineStack", StackProps.builder()
            .env(Environment.builder()
                .account("111111111111")
                .region("eu-west-1")
                .build())
            .build());

        app.synth();
    }
}
```
`src/MyPipeline/MyPipelineStack.cs` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
using Amazon.CDK;
using Amazon.CDK.Pipelines;

namespace MyPipeline
{
    public class MyPipelineStack : Stack
    {
        internal MyPipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
            {
                PipelineName = "MyPipeline",
                Synth = new ShellStep("Synth", new ShellStepProps
                {
                    Input = CodePipelineSource.GitHub("OWNER/REPO", "main"),
                    Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
                })
            });
        }
    }
}
```
`src/MyPipeline/Program.cs` に作成 (プロジェクトフォルダの名前が `my-pipeline` ではない場合は、異なる場合があります)  

```
using Amazon.CDK;

namespace MyPipeline
{
    sealed class Program
    {
        public static void Main(string[] args)
        {
            var app = new App();
            new MyPipelineStack(app, "MyPipelineStack", new StackProps
            {
                Env = new Amazon.CDK.Environment {
                    Account = "111111111111", Region = "eu-west-1" }
            });

            app.Synth();
        }
    }
}
```

```
package main

import (
	"github.com/aws/aws-cdk-go/awscdk/v2"
	codebuild "github.com/aws/aws-cdk-go/awscdk/v2/awscodebuild"
	ssm "github.com/aws/aws-cdk-go/awscdk/v2/awsssm"
	pipeline "github.com/aws/aws-cdk-go/awscdk/v2/pipelines"
	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
	"os"
)

// my CDK Stack with resources
func NewCdkStack(scope constructs.Construct, id *string, props *awscdk.StackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, id, props)

	// create an example ssm parameter
	_ = ssm.NewStringParameter(stack, jsii.String("ssm-test-param"), &ssm.StringParameterProps{
		ParameterName: jsii.String("/testparam"),
		Description:   jsii.String("ssm parameter for demo"),
		StringValue:   jsii.String("my test param"),
	})

	return stack
}

// my CDK Application
func NewCdkApplication(scope constructs.Construct, id *string, props *awscdk.StageProps) awscdk.Stage {
	stage := awscdk.NewStage(scope, id, props)

	_ = NewCdkStack(stage, jsii.String("cdk-stack"), &awscdk.StackProps{Env: props.Env})

	return stage
}

// my CDK Pipeline
func NewCdkPipeline(scope constructs.Construct, id *string, props *awscdk.StackProps) awscdk.Stack {
	stack := awscdk.NewStack(scope, id, props)

	// GitHub repo with owner and repository name
	githubRepo := pipeline.CodePipelineSource_GitHub(jsii.String("owner/repo"), jsii.String("main"), &pipeline.GitHubSourceOptions{
		Authentication: awscdk.SecretValue_SecretsManager(jsii.String("my-github-token"), nil),
	})

	// self mutating pipeline
	myPipeline := pipeline.NewCodePipeline(stack, jsii.String("cdkPipeline"), &pipeline.CodePipelineProps{
		PipelineName: jsii.String("CdkPipeline"),
		// self mutation true - pipeline changes itself before application deployment
		SelfMutation: jsii.Bool(true),
		CodeBuildDefaults: &pipeline.CodeBuildOptions{
			BuildEnvironment: &codebuild.BuildEnvironment{
				// image version 6.0 recommended for newer go version
				BuildImage: codebuild.LinuxBuildImage_FromCodeBuildImageId(jsii.String("aws/codebuild/standard:6.0")),
			},
		},
		Synth: pipeline.NewCodeBuildStep(jsii.String("Synth"), &pipeline.CodeBuildStepProps{
			Input: githubRepo,
			Commands: &[]*string{
				jsii.String("npm install -g aws-cdk"),
				jsii.String("cdk synth"),
			},
		}),
	})

	// deployment of actual CDK application
	myPipeline.AddStage(NewCdkApplication(stack, jsii.String("MyApplication"), &awscdk.StageProps{
		Env: targetAccountEnv(),
	}), &pipeline.AddStageOpts{
		Post: &[]pipeline.Step{
			pipeline.NewCodeBuildStep(jsii.String("Manual Steps"), &pipeline.CodeBuildStepProps{
				Commands: &[]*string{
					jsii.String("echo \"My CDK App deployed, manual steps go here ... \""),
				},
			}),
		},
	})

	return stack
}

// main app
func main() {
	defer jsii.Close()

	app := awscdk.NewApp(nil)

	// call CDK Pipeline
	NewCdkPipeline(app, jsii.String("CdkPipelineStack"), &awscdk.StackProps{
		Env: pipelineEnv(),
	})

	app.Synth(nil)
}

// env determines the AWS environment (account+region) in which our stack is to
// be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html
func pipelineEnv() *awscdk.Environment {
	return &awscdk.Environment{
		Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
		Region:  jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
	}
}

func targetAccountEnv() *awscdk.Environment {
	return &awscdk.Environment{
		Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")),
		Region:  jsii.String(os.Getenv("CDK_DEFAULT_REGION")),
	}
}
```

パイプラインは 1 度手動でデプロイする必要があります。その後、パイプラインはソースコードリポジトリから自身を最新の状態に保ち続けます。したがって、リポジトリ内のコードが、デプロイしたいコードであることを必ず確認してください。変更を確認して GitHub にプッシュし、デプロイします。

```
git add --all
git commit -m "initial commit"
git push
cdk deploy
```

**ヒント**  
最初のデプロイが完了したら、ローカル AWS アカウントには管理アクセスが不要になります。これは、アプリケーションへのすべての変更はパイプラインを介してデプロイされるためです。必要なのは GitHub にプッシュすることだけです。

## アプリケーションステージ
<a name="cdk-pipeline-stages"></a>

パイプラインに一度に追加できるマルチスタック AWS アプリケーションを定義するには、` [Stage](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stage.html) ` のサブクラスを定義します。(これは CDK Pipelines モジュールの `CdkStage` とは異なります。)

ステージには、アプリケーションを構成するスタックが含まれています。スタック間に依存関係がある場合、スタックはパイプラインに自動的に正しい順序で追加されます。相互に依存しないスタックは、並列にデプロイされます。`stack1.addDependency(stack2)` を呼び出すことで、スタック間に依存関係を追加できます。

ステージはデフォルトの `env` 引数を受け入れます。これは、その中のスタックのデフォルトの環境になります。(スタックには独自の環境を指定することもできます)。

アプリケーションをパイプラインに追加するには、[ステージ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.Stage.html)のインスタンスで ` [addStage()](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.CodePipeline.html#addwbrstagestage-optionss) ` を呼び出します。ステージをインスタンス化してパイプラインに複数回追加することで、DTAP またはマルチリージョンアプリケーションパイプラインのさまざまなステージを定義できます。

シンプルな Lambda 関数を含むスタックを作成し、そのスタックをステージに配置します。次に、ステージをパイプラインに追加してデプロイできるようにします。

**Example**  
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `lib/my-pipeline-lambda-stack.ts` を作成します。  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Function, InlineCode, Runtime } from 'aws-cdk-lib/aws-lambda';

export class MyLambdaStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
      super(scope, id, props);

      new Function(this, 'LambdaFunction', {
        runtime: Runtime.NODEJS_18_X,
        handler: 'index.handler',
        code: new InlineCode('exports.handler = _ => "Hello, CDK";')
      });
    }
}
```
ステージを保持する新しいファイル `lib/my-pipeline-app-stage.ts` を作成します。  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from "constructs";
import { MyLambdaStack } from './my-pipeline-lambda-stack';

export class MyPipelineAppStage extends cdk.Stage {

    constructor(scope: Construct, id: string, props?: cdk.StageProps) {
      super(scope, id, props);

      const lambdaStack = new MyLambdaStack(this, 'LambdaStack');
    }
}
```
`lib/my-pipeline-stack.ts` を編集して、ステージをパイプラインに追加します。  

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import { MyPipelineAppStage } from './my-pipeline-app-stage';

export class MyPipelineStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });

    pipeline.addStage(new MyPipelineAppStage(this, "test", {
      env: { account: "111111111111", region: "eu-west-1" }
    }));
  }
}
```
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `lib/my-pipeline-lambda-stack.js` を作成します。  

```
const cdk = require('aws-cdk-lib');
const { Function, InlineCode, Runtime } = require('aws-cdk-lib/aws-lambda');

class MyLambdaStack extends cdk.Stack {
    constructor(scope, id, props) {
      super(scope, id, props);

      new Function(this, 'LambdaFunction', {
        runtime: Runtime.NODEJS_18_X,
        handler: 'index.handler',
        code: new InlineCode('exports.handler = _ => "Hello, CDK";')
      });
    }
}

module.exports = { MyLambdaStack }
```
ステージを保持する新しいファイル `lib/my-pipeline-app-stage.js` を作成します。  

```
const cdk = require('aws-cdk-lib');
const { MyLambdaStack } = require('./my-pipeline-lambda-stack');

class MyPipelineAppStage extends cdk.Stage {

    constructor(scope, id, props) {
      super(scope, id, props);

      const lambdaStack = new MyLambdaStack(this, 'LambdaStack');
    }
}

module.exports = { MyPipelineAppStage };
```
`lib/my-pipeline-stack.ts` を編集して、ステージをパイプラインに追加します。  

```
const cdk = require('aws-cdk-lib');
const { CodePipeline, CodePipelineSource, ShellStep } = require('aws-cdk-lib/pipelines');
const { MyPipelineAppStage } = require('./my-pipeline-app-stage');

 class MyPipelineStack extends cdk.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: 'MyPipeline',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });

    pipeline.addStage(new MyPipelineAppStage(this, "test", {
      env: { account: "111111111111", region: "eu-west-1" }
    }));

  }
}

module.exports = { MyPipelineStack }
```
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `my_pipeline/my_pipeline_lambda_stack.py` を作成します。  

```
import aws_cdk as cdk
from constructs import Construct
from aws_cdk.aws_lambda import Function, InlineCode, Runtime

class MyLambdaStack(cdk.Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        Function(self, "LambdaFunction",
            runtime=Runtime.NODEJS_18_X,
            handler="index.handler",
            code=InlineCode("exports.handler = _ => 'Hello, CDK';")
        )
```
ステージを保持する新しいファイル `my_pipeline/my_pipeline_app_stage.py` を作成します。  

```
import aws_cdk as cdk
from constructs import Construct
from my_pipeline.my_pipeline_lambda_stack import MyLambdaStack

class MyPipelineAppStage(cdk.Stage):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        lambdaStack = MyLambdaStack(self, "LambdaStack")
```
`my_pipeline/my-pipeline-stack.py` を編集して、ステージをパイプラインに追加します。  

```
import aws_cdk as cdk
from constructs import Construct
from aws_cdk.pipelines import CodePipeline, CodePipelineSource, ShellStep
from my_pipeline.my_pipeline_app_stage import MyPipelineAppStage

class MyPipelineStack(cdk.Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        pipeline =  CodePipeline(self, "Pipeline",
                        pipeline_name="MyPipeline",
                        synth=ShellStep("Synth",
                            input=CodePipelineSource.git_hub("OWNER/REPO", "main"),
                            commands=["npm install -g aws-cdk",
                                "python -m pip install -r requirements.txt",
                                "cdk synth"]))

        pipeline.add_stage(MyPipelineAppStage(self, "test",
            env=cdk.Environment(account="111111111111", region="eu-west-1")))
```
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `src/main/java/com.myorg/MyPipelineLambdaStack.java` を作成します。  

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;

import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.lambda.InlineCode;

public class MyPipelineLambdaStack extends Stack {
    public MyPipelineLambdaStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineLambdaStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        Function.Builder.create(this, "LambdaFunction")
          .runtime(Runtime.NODEJS_18_X)
          .handler("index.handler")
          .code(new InlineCode("exports.handler = _ => 'Hello, CDK';"))
          .build();

    }

}
```
ステージを保持する新しいファイル `src/main/java/com.myorg/MyPipelineAppStage.java` を作成します。  

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.Stage;
import software.amazon.awscdk.StageProps;

public class MyPipelineAppStage extends Stage {
    public MyPipelineAppStage(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineAppStage(final Construct scope, final String id, final StageProps props) {
        super(scope, id, props);

        Stack lambdaStack = new MyPipelineLambdaStack(this, "LambdaStack");
    }

}
```
`src/main/java/com.myorg/MyPipelineStack.java` を編集して、ステージをパイプラインに追加します。  

```
package com.myorg;

import java.util.Arrays;
import software.constructs.Construct;
import software.amazon.awscdk.Environment;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.StageProps;
import software.amazon.awscdk.pipelines.CodePipeline;
import software.amazon.awscdk.pipelines.CodePipelineSource;
import software.amazon.awscdk.pipelines.ShellStep;

public class MyPipelineStack extends Stack {
    public MyPipelineStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public MyPipelineStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
            .pipelineName("MyPipeline")
            .synth(ShellStep.Builder.create("Synth")
                .input(CodePipelineSource.gitHub("OWNER/REPO", "main"))
                .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                .build())
            .build();

        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
            .env(Environment.builder()
                .account("111111111111")
                .region("eu-west-1")
                .build())
            .build()));
    }
}
```
Lambda 関数を含むアプリケーションスタックを保持する新しいファイル `src/MyPipeline/MyPipelineLambdaStack.cs` を作成します。  

```
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.Lambda;

namespace MyPipeline
{
    class MyPipelineLambdaStack : Stack
    {
        public MyPipelineLambdaStack(Construct scope, string id, StackProps props=null) : base(scope, id, props)
        {
            new Function(this, "LambdaFunction", new FunctionProps
            {
                Runtime = Runtime.NODEJS_18_X,
                Handler = "index.handler",
                Code = new InlineCode("exports.handler = _ => 'Hello, CDK';")
            });
        }
    }
}
```
ステージを保持する新しいファイル `src/MyPipeline/MyPipelineAppStage.cs` を作成します。  

```
using Amazon.CDK;
using Constructs;

namespace MyPipeline
{
    class MyPipelineAppStage : Stage
    {
        public MyPipelineAppStage(Construct scope, string id, StageProps props=null) : base(scope, id, props)
        {
            Stack lambdaStack = new MyPipelineLambdaStack(this, "LambdaStack");
        }
    }
}
```
`src/MyPipeline/MyPipelineStack.cs` を編集して、ステージをパイプラインに追加します。  

```
using Amazon.CDK;
using Constructs;
using Amazon.CDK.Pipelines;

namespace MyPipeline
{
    public class MyPipelineStack : Stack
    {
        internal MyPipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
            {
                PipelineName = "MyPipeline",
                Synth = new ShellStep("Synth", new ShellStepProps
                {
                    Input = CodePipelineSource.GitHub("OWNER/REPO", "main"),
                    Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
                })
            });

            pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
            {
                Env = new Environment
                {
                    Account = "111111111111", Region = "eu-west-1"
                }
            }));
        }
    }
}
```

`addStage()` で追加されたすべてのアプリケーションステージは、`addStage()` コールで返された ` [StageDeployment](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.StageDeployment.html) ` インスタンスで表される、対応するパイプラインステージを追加します。デプロイ前アクションまたはデプロイ後アクションは、`addPre()` または `addPost()` のメソッドを呼び出すことでステージに追加できます。

**Example**  

```
// import { ManualApprovalStep } from 'aws-cdk-lib/pipelines';

const testingStage = pipeline.addStage(new MyPipelineAppStage(this, 'testing', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

    testingStage.addPost(new ManualApprovalStep('approval'));
```

```
// const { ManualApprovalStep } = require('aws-cdk-lib/pipelines');

const testingStage = pipeline.addStage(new MyPipelineAppStage(this, 'testing', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

testingStage.addPost(new ManualApprovalStep('approval'));
```

```
# from aws_cdk.pipelines import ManualApprovalStep

testing_stage = pipeline.add_stage(MyPipelineAppStage(self, "testing",
    env=cdk.Environment(account="111111111111", region="eu-west-1")))

testing_stage.add_post(ManualApprovalStep('approval'))
```

```
// import software.amazon.awscdk.pipelines.StageDeployment;
// import software.amazon.awscdk.pipelines.ManualApprovalStep;

StageDeployment testingStage =
        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
                .env(Environment.builder()
                        .account("111111111111")
                        .region("eu-west-1")
                        .build())
                .build()));

testingStage.addPost(new ManualApprovalStep("approval"));
```

```
var testingStage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));

testingStage.AddPost(new ManualApprovalStep("approval"));
```

例えば複数のアカウントやリージョンにステージをデプロイする場合などは、` [Wave](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.Wave.html) ` にステージを追加して並列にデプロイできます。

**Example**  

```
const wave = pipeline.addWave('wave');
wave.addStage(new MyApplicationStage(this, 'MyAppEU', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));
wave.addStage(new MyApplicationStage(this, 'MyAppUS', {
  env: { account: '111111111111', region: 'us-west-1' }
}));
```

```
const wave = pipeline.addWave('wave');
wave.addStage(new MyApplicationStage(this, 'MyAppEU', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));
wave.addStage(new MyApplicationStage(this, 'MyAppUS', {
  env: { account: '111111111111', region: 'us-west-1' }
}));
```

```
wave = pipeline.add_wave("wave")
wave.add_stage(MyApplicationStage(self, "MyAppEU",
    env=cdk.Environment(account="111111111111", region="eu-west-1")))
wave.add_stage(MyApplicationStage(self, "MyAppUS",
    env=cdk.Environment(account="111111111111", region="us-west-1")))
```

```
// import software.amazon.awscdk.pipelines.Wave;
final Wave wave = pipeline.addWave("wave");
wave.addStage(new MyPipelineAppStage(this, "MyAppEU", StageProps.builder()
        .env(Environment.builder()
                .account("111111111111")
                .region("eu-west-1")
                .build())
        .build()));
wave.addStage(new MyPipelineAppStage(this, "MyAppUS", StageProps.builder()
        .env(Environment.builder()
                .account("111111111111")
                .region("us-west-1")
                .build())
        .build()));
```

```
var wave = pipeline.AddWave("wave");
wave.AddStage(new MyPipelineAppStage(this, "MyAppEU", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));
wave.AddStage(new MyPipelineAppStage(this, "MyAppUS", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "us-west-1"
    }
}));
```

## デプロイのテスト
<a name="cdk-pipeline-validation"></a>

CDK Pipeline にステップを追加して、実行しているデプロイを検証できます。例えば、CDK Pipeline ライブラリの ` [ShellStep](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.ShellStep.html) ` を使用して、以下のようなタスクを実行できます。
+ Lambda 関数にバックアップされた新しくデプロイされた Amazon API Gateway へのアクセスを試みる
+ AWS CLI コマンドを実行してデプロイされたリソースの設定を確認する

最もシンプルな形式では、検証アクションの追加は以下のようになります。

**Example**  

```
// stage was returned by pipeline.addStage

stage.addPost(new ShellStep("validate", {
  commands: ['../tests/validate.sh'],
}));
```

```
// stage was returned by pipeline.addStage

stage.addPost(new ShellStep("validate", {
  commands: ['../tests/validate.sh'],
}));
```

```
# stage was returned by pipeline.add_stage

stage.add_post(ShellStep("validate",
  commands=[''../tests/validate.sh'']
))
```

```
// stage was returned by pipeline.addStage

stage.addPost(ShellStep.Builder.create("validate")
        .commands(Arrays.asList("'../tests/validate.sh'"))
        .build());
```

```
// stage was returned by pipeline.addStage

stage.AddPost(new ShellStep("validate", new ShellStepProps
{
    Commands = new string[] { "'../tests/validate.sh'" }
}));
```

多くの AWS CloudFormation デプロイでは、予測不可能な名前のリソースが生成されます。このため、CDK Pipelines はデプロイ後に AWS CloudFormation 出力を読み取る方法を提供します。これにより、生成されたロードバランサーの URL を (たとえば) テストアクションに渡すことができます。

出力を使用するには、関心のある `CfnOutput` オブジェクトを公開します。次に、ステップの `envFromCfnOutputs` プロパティに渡して、そのステップ内の環境変数として使用可能にします。

**Example**  

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
this.loadBalancerAddress = new cdk.CfnOutput(lbStack, 'LbAddress', {
  value: `https://${lbStack.loadBalancer.loadBalancerDnsName}/`
});

// pass the load balancer address to a shell step
stage.addPost(new ShellStep("lbaddr", {
  envFromCfnOutputs: {lb_addr: lbStack.loadBalancerAddress},
  commands: ['echo $lb_addr']
}));
```

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
this.loadBalancerAddress = new cdk.CfnOutput(lbStack, 'LbAddress', {
  value: `https://${lbStack.loadBalancer.loadBalancerDnsName}/`
});

// pass the load balancer address to a shell step
stage.addPost(new ShellStep("lbaddr", {
  envFromCfnOutputs: {lb_addr: lbStack.loadBalancerAddress},
  commands: ['echo $lb_addr']
}));
```

```
# given a stack lb_stack that exposes a load balancer construct as load_balancer
self.load_balancer_address = cdk.CfnOutput(lb_stack, "LbAddress",
    value=f"https://{lb_stack.load_balancer.load_balancer_dns_name}/")

# pass the load balancer address to a shell step
stage.add_post(ShellStep("lbaddr",
    env_from_cfn_outputs={"lb_addr": lb_stack.load_balancer_address}
    commands=["echo $lb_addr"]))
```

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
loadBalancerAddress = CfnOutput.Builder.create(lbStack, "LbAddress")
                            .value(String.format("https://%s/",
                                    lbStack.loadBalancer.loadBalancerDnsName))
                            .build();

stage.addPost(ShellStep.Builder.create("lbaddr")
    .envFromCfnOutputs(     // Map.of requires Java 9 or later
        java.util.Map.of("lbAddr", loadBalancerAddress))
    .commands(Arrays.asList("echo $lbAddr"))
    .build());
```

```
// given a stack lbStack that exposes a load balancer construct as loadBalancer
loadBalancerAddress = new CfnOutput(lbStack, "LbAddress", new CfnOutputProps
{
    Value = string.Format("https://{0}/", lbStack.loadBalancer.LoadBalancerDnsName)
});

stage.AddPost(new ShellStep("lbaddr", new ShellStepProps
{
    EnvFromCfnOutputs = new Dictionary<string, CfnOutput>
    {
        {  "lbAddr", loadBalancerAddress }
    },
    Commands = new string[] { "echo $lbAddr" }
}));
```

`ShellStep` で簡単な検証テストを記述することはできますが、テストが数行を超えると、このアプローチは扱いにくくなります。より複雑なテストでは、`inputs` プロパティを介して追加のファイル (完全なシェルスクリプト、他の言語のプログラムなど) を `ShellStep` に持ち込むことができます。入力は、ソース (GitHub リポジトリなど) や別の `ShellStep` など、出力を持つ任意のステップにすることができます。

ソースリポジトリからファイルを取り込むのは、ファイルがテストで直接使用できる場合 (たとえば、ファイル自体が実行可能である場合) に適しています。この例では、GitHub リポジトリを (`CodePipeline` の一部としてインラインでインスタンス化するのではなく) `source` として宣言します。次に、このファイルセットをパイプラインと検証テストの両方に渡します。

**Example**  

```
const source = CodePipelineSource.gitHub('OWNER/REPO', 'main');

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: new ShellStep('Synth', {
    input: source,
    commands: ['npm ci', 'npm run build', 'npx cdk synth']
  })
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

stage.addPost(new ShellStep('validate', {
  input: source,
  commands: ['sh ../tests/validate.sh']
}));
```

```
const source = CodePipelineSource.gitHub('OWNER/REPO', 'main');

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: new ShellStep('Synth', {
    input: source,
    commands: ['npm ci', 'npm run build', 'npx cdk synth']
  })
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

stage.addPost(new ShellStep('validate', {
  input: source,
  commands: ['sh ../tests/validate.sh']
}));
```

```
source   = CodePipelineSource.git_hub("OWNER/REPO", "main")

pipeline =  CodePipeline(self, "Pipeline",
                pipeline_name="MyPipeline",
                synth=ShellStep("Synth",
                    input=source,
                    commands=["npm install -g aws-cdk",
                        "python -m pip install -r requirements.txt",
                        "cdk synth"]))

stage = pipeline.add_stage(MyApplicationStage(self, "test",
            env=cdk.Environment(account="111111111111", region="eu-west-1")))

stage.add_post(ShellStep("validate", input=source,
    commands=["sh ../tests/validate.sh"],
))
```

```
final CodePipelineSource source = CodePipelineSource.gitHub("OWNER/REPO", "main");

final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
        .pipelineName("MyPipeline")
        .synth(ShellStep.Builder.create("Synth")
                .input(source)
                .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                .build())
        .build();

final StageDeployment stage =
        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
                .env(Environment.builder()
                        .account("111111111111")
                        .region("eu-west-1")
                        .build())
                .build()));

stage.addPost(ShellStep.Builder.create("validate")
        .input(source)
        .commands(Arrays.asList("sh ../tests/validate.sh"))
        .build());
```

```
var source = CodePipelineSource.GitHub("OWNER/REPO", "main");

var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
{
    PipelineName = "MyPipeline",
    Synth = new ShellStep("Synth", new ShellStepProps
    {
        Input = source,
        Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
    })
});

var stage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));

stage.AddPost(new ShellStep("validate", new ShellStepProps
{
    Input = source,
    Commands = new string[] { "sh ../tests/validate.sh" }
}));
```

合成ステップから追加のファイルを取得することは、合成の一部として行われるテストをコンパイルする必要がある場合に適しています。

**Example**  

```
const synthStep = new ShellStep('Synth', {
  input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
  commands: ['npm ci', 'npm run build', 'npx cdk synth'],
});

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: synthStep
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, 'test', {
  env: { account: '111111111111', region: 'eu-west-1' }
}));

// run a script that was transpiled from TypeScript during synthesis
stage.addPost(new ShellStep('validate', {
  input: synthStep,
  commands: ['node tests/validate.js']
}));
```

```
const synthStep = new ShellStep('Synth', {
  input: CodePipelineSource.gitHub('OWNER/REPO', 'main'),
  commands: ['npm ci', 'npm run build', 'npx cdk synth'],
});

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: synthStep
});

const stage = pipeline.addStage(new MyPipelineAppStage(this, "test", {
  env: { account: "111111111111", region: "eu-west-1" }
}));

// run a script that was transpiled from TypeScript during synthesis
stage.addPost(new ShellStep('validate', {
  input: synthStep,
  commands: ['node tests/validate.js']
}));
```

```
synth_step = ShellStep("Synth",
                input=CodePipelineSource.git_hub("OWNER/REPO", "main"),
                commands=["npm install -g aws-cdk",
                  "python -m pip install -r requirements.txt",
                  "cdk synth"])

pipeline   = CodePipeline(self, "Pipeline",
                pipeline_name="MyPipeline",
                synth=synth_step)

stage = pipeline.add_stage(MyApplicationStage(self, "test",
            env=cdk.Environment(account="111111111111", region="eu-west-1")))

# run a script that was compiled during synthesis
stage.add_post(ShellStep("validate",
    input=synth_step,
    commands=["node test/validate.js"],
))
```

```
final ShellStep synth = ShellStep.Builder.create("Synth")
                            .input(CodePipelineSource.gitHub("OWNER/REPO", "main"))
                            .commands(Arrays.asList("npm install -g aws-cdk", "cdk synth"))
                            .build();

final CodePipeline pipeline = CodePipeline.Builder.create(this, "pipeline")
        .pipelineName("MyPipeline")
        .synth(synth)
        .build();

final StageDeployment stage =
        pipeline.addStage(new MyPipelineAppStage(this, "test", StageProps.builder()
                .env(Environment.builder()
                        .account("111111111111")
                        .region("eu-west-1")
                        .build())
                .build()));

stage.addPost(ShellStep.Builder.create("validate")
        .input(synth)
        .commands(Arrays.asList("node ./tests/validate.js"))
        .build());
```

```
var synth = new ShellStep("Synth", new ShellStepProps
{
    Input = CodePipelineSource.GitHub("OWNER/REPO", "main"),
    Commands = new string[] { "npm install -g aws-cdk", "cdk synth" }
});

var pipeline = new CodePipeline(this, "pipeline", new CodePipelineProps
{
    PipelineName = "MyPipeline",
    Synth = synth
});

var stage = pipeline.AddStage(new MyPipelineAppStage(this, "test", new StageProps
{
    Env = new Environment
    {
        Account = "111111111111", Region = "eu-west-1"
    }
}));

stage.AddPost(new ShellStep("validate", new ShellStepProps
{
    Input = synth,
    Commands = new string[] { "node ./tests/validate.js" }
}));
```

## セキュリティ上の考慮事項
<a name="cdk-pipeline-security"></a>

どのような形の継続的デリバリーにも、固有のセキュリティリスクがあります。AWS [責任共有モデル](https://aws.amazon.com/compliance/shared-responsibility-model/)では、AWS クラウド内の情報のセキュリティにはユーザーが責任を担います。CDK Pipelines ライブラリは、セキュアなデフォルト値とモデリングのベストプラクティスを組み込むことで、開発を迅速に開始できます。

ただし、その性質上、意図した目的を達成するために高レベルのアクセスを必要とするライブラリは、完全なセキュリティを保証することはできません。AWS および組織の外には多くの攻撃ベクトルが存在します。

特に、次の点に注意してください。
+ 使用するソフトウェアに注意してください。パイプラインで実行するすべてのサードパーティーソフトウェアを検証します。これは、デプロイされるインフラストラクチャが変更される可能性があるためです。
+ 依存関係ロックを使用して、予期せぬアップグレードを防止します。CDK Pipelines は、依存関係が想定どおりのものであるよう、 `package-lock.json` と `yarn.lock` を遵守します。
+ CDK Pipelines は、独自のアカウントで作成されたリソースで実行され、それらのリソースの設定は、パイプラインを介してコードを送信する開発者によって制御されます。したがって、CDK Pipelines 自体は、コンプライアンスチェックをバイパスしようとする悪意のある開発者から保護することはできません。脅威モデルに CDK コードを記述する開発者が含まれている場合は、AWS CloudFormation 実行ロールに無効化するアクセス許可がない [AWS CloudFormation Hooks](https://aws.amazon.com/blogs/mt/proactively-keep-resources-secure-and-compliant-with-aws-cloudformation-hooks/) (予防) や [AWS Config](https://aws.amazon.com/config/) (事後対応) などの外部コンプライアンスメカニズムが必要です。
+ 本番稼働環境の認証情報は、有効期間が短くなければなりません。ブートストラップと初期プロビジョニングの後、開発者がアカウント認証情報を持つ必要はありません。変更はパイプラインを通じてデプロイできます。そもそも認証情報を必要とせず、認証情報が漏洩する可能性を減らします。

## トラブルシューティング
<a name="cdk-pipeline-troubleshooting"></a>

CDK Pipelines の使用を開始する際に、一般的に発生する問題は次のとおりです。

 **パイプライン: 内部障害**   

```
CREATE_FAILED  | {aws}::CodePipeline::Pipeline | Pipeline/Pipeline
Internal Failure
```
GitHub アクセストークンを確認します。欠落しているか、リポジトリにアクセスするアクセス許可がない可能性があります。

 **キーポリシーに 1 つ以上の無効なプリンシパルを含むステートメントが含まれています**   

```
CREATE_FAILED | {aws}::KMS::Key | Pipeline/Pipeline/ArtifactsBucketEncryptionKey
Policy contains a statement with one or more invalid principals.
```
ターゲット環境の 1 つが新しいブートストラップスタックでブートストラップされていません。すべてのターゲット環境がブートストラップされていることを確認します。

 **スタックは ROLLBACK\_COMPLETE 状態であり、更新できません**   

```
Stack <STACK_NAME> is in ROLLBACK_COMPLETE state and cannot be updated. (Service:
AmazonCloudFormation; Status Code: 400; Error Code: ValidationError; Request
ID: ...)
```
スタックは以前のデプロイに失敗し、再試行不可能な状態です。AWS CloudFormation コンソールからスタックを削除し、デプロイを再試行します。