AWS CDKでクロススタック参照をしてみた

2021.11.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 IoT事業部の若槻です。

AWS CDKは、書き慣れた言語でAWSリソースのIaCを構成できるAWSサービスです。

このAWS CDKでアプリケーションを構築する際に、目的単位やリソース種別単位でCDKスタックを複数使用することがよくあるのですが、その際にスタック間でリソースのパラメーター(リソース名やArnなど)を参照させたい(クロススタック参照)場合があります。

そこで今回は、AWS CDKでクロススタック参照をする方法を確認してみました。

方法

スタックAwsCdkStateMachineStackで作成したステートマシンのArnを、もう一方のスタックAwsCdkAppStackで参照したい場合の実装で確認してみます。

参照される側のスタック

クロススタック参照される側のスタックでは、CfnOutputを使用して参照させたいパラメーターをエクスポートします。

lib/aws-cdk-state-machine-stack.ts

import * as cdk from '@aws-cdk/core';
import * as sfn from '@aws-cdk/aws-stepfunctions';

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

    //ステートマシン
    const stateMachine = new sfn.StateMachine(this, 'sampleStateMachine', {
      stateMachineName: 'sampleStateMachine',
      definition: new sfn.Pass(this, 'pass', {}),
    });

    //ステートマシンArnのエクスポート
    new cdk.CfnOutput(this, 'stateMachineArnOutPut', {
      value: stateMachine.stateMachineArn,
      exportName: 'stateMachineArn',
    });
  }
}

参照する側のスタック

クロススタック参照する側のスタックでは、Fn.importValueを使用して参照したいパラメーターをインポートします。

lib/aws-cdk-app-stack.ts

import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';
import * as lambdaNodejs from '@aws-cdk/aws-lambda-nodejs';
import * as iam from '@aws-cdk/aws-iam';

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

    //ステートマシンArnのインポート
    const stateMachineArn = cdk.Fn.importValue('stateMachineArn');

    //Lambda関数
    const startStateMachineFunc = new lambdaNodejs.NodejsFunction(
      this,
      'startStateMachineFunc',
      {
        functionName: 'startStateMachineFunc',
        entry: 'src/lambda/startStateMachineHandler.ts',
        handler: 'handler',
        runtime: lambda.Runtime.NODEJS_14_X,
        environment: {
          STATE_MACHINE_ARN: stateMachineArn,
        },
      }
    );

    //ステートマシン起動権限付与
    startStateMachineFunc.addToRolePolicy(
      new iam.PolicyStatement({
        actions: ['states:StartExecution'],
        resources: [stateMachineArn],
      })
    );
  }
}

CDKアプリ

CDKアプリでは、addDependencyを使用してクロススタック参照する/される両スタックの依存関係を明示的に定義します。

bin/aws-cdk-app.ts

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { AwsCdkAppStack } from '../lib/aws-cdk-app-stack';
import { AwsCdkStateMachineStack } from '../lib/aws-cdk-state-machine-stack';

const app = new cdk.App();

//参照される側のスタック
const awsCdkStateMachineStack = new AwsCdkStateMachineStack(
  app,
  'AwsCdkStateMachineStack',
  {}
);

//参照する側のスタック
const awsCdkAppStack = new AwsCdkAppStack(app, 'AwsCdkAppStack', {});

//両スタックの依存関係を明示的に定義
awsCdkAppStack.addDependency(awsCdkStateMachineStack);

動作確認

両スタックをCDKデプロイします。

$ cdk deploy --all

CloudFormationのマネジメントコンソールで参照される側のスタックの出力を確認すると、ちゃんと値がエクスポートされています。

インポートしたステートマシンのArnがLambdaの環境変数にちゃんとセットできています。

addDependencyによる依存関係の指定の必要性について

addDependencyを使用せずスタック間の依存を明示的に指定しない場合でも、適切な順でスタックをスタックを作成すればエラーを回避できます。

例えば、下記のようにcdk deployコマンドで参照される側(依存される側)のAwsCdkStateMachineStackを手前で指定すれば、デプロイは問題なく行われます。

$ cdk deploy AwsCdkStateMachineStack AwsCdkAppStack

しかし下記のように参照する側(依存する側)のAwsCdkAppStackを手前で指定すると、AwsCdkStateMachineStackが未作成であればNo export named stateMachineArn found.というエラーとなります。

$ cdk deploy AwsCdkAppStack AwsCdkStateMachineStack

12:22:56 AM | ROLLBACK_IN_PROGRESS | AWS::CloudFormation::Stack | AwsCdkAppStack
No export named stateMachineArn found. Rollback requested by user.
12:22:56 AM | ROLLBACK_IN_PROGRESS | AWS::CloudFormation::Stack | AwsCdkAppStack
No export named stateMachineArn found. Rollback requested by user.

またcdk deploy --allでデプロイした場合でも同様のエラーになる場合があります。よってaddDependencycdk deployコマンドの組み立て方によっては必須ではないのですが、明示的に指定しておいた方が安全です。

クロスリージョンの場合

クロスリージョンでのクロススタック参照を行いたい場合は下記を参考にしてください。

参考

以上