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

2021.11.09

こんにちは、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コマンドの組み立て方によっては必須ではないのですが、明示的に指定しておいた方が安全です。

参考

以上