2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【AWS CDK (Python)】 クロススタック参照の方法

Posted at

はじめに

本記事は、私自身の備忘録を兼ねてAWS CDKをこれから始める方の一助になればと思い、AWS CDKの使い方等をまとめたものです。
今回は、AWS CDKでスタック間参照する方法を確認しています。
なお、本記事は私自身の経験を基に記載していますが、間違いがあったらすみません。

スタック分割とクロススタック参照

あるスタックで作成したリソースの情報(ARNなど)を別のスタックから参照することをクロススタック参照やスタック間参照と言います。
スタックは、ライフサイクルや管理主体により分割する方がよいとされています。しかし、分割した際にスタック間でリソース情報を参照する必要が出てきます。例えば、VPCとEC2のスタックを分けた場合、EC2のスタックでVPCスタックにあるsubnetの情報を参照する必要が出てきます。
こうした場合に、参照されるスタックではexport、参照するスタックではimportすることで必要な情報をスタック間で参照することが可能です。

環境

本記事は以下の環境を使用して記載しています。

  • AWS Cloud9
  • AWS CDK:2.80.0
  • Python: 3.10.11
  • Node.js: 16.20.0

また、以下の記事に基づいてAWS CDKの環境を作成しています。

クロススタック参照の方法

今回は、あるスタックで作成したS3バケットのバケット名とARNを別のスタックから参照してみます。
参照の方法がいくつかあるので、方法ごとに見ていきましょう。

aws_cdk.CfnOutput/aws_cdk.Fn.import_valueを使う方法

まず、aws_cdk.CfnOutputとaws_cdk.Fn.import_valueを使用する方法です。
以下のように参照される側のスタックでS3の作成とaws_cdk.CfnOutputを使用してバケット名とARNをexportします。

cdk_app/cdk_export_stack.py
from aws_cdk import (
    Stack,
    aws_s3 as s3,
    RemovalPolicy,
    CfnOutput
)
from constructs import Construct

class CdkExportStack(Stack):

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

        s3bucket = s3.Bucket(
            self,
            "MyS3Bucket",
            bucket_name = "cdk-test-bucket-yyyymmdd",
            versioned=True,
            removal_policy=RemovalPolicy.DESTROY
        )

        # ARNをexport.        
        CfnOutput(
            self,
            "exportvalue_CfnOutput_arn",
            value=s3bucket.bucket_arn,
            description="S3Bucket ARN",
            export_name="s3bucket-arn-CfnOutput"
        )

        # バケット名をexport.        
        CfnOutput(
            self,
            "exportvalue_CfnOutput_name",
            value=s3bucket.bucket_name,
            description="S3Bucket Name",
            export_name="s3bucket-name-CfnOutput"
        )

参照する側では、aws_cdk.Fn.import_valueを使用してバケット名とARNをimportします。(確認のため、importしたバケット名とARNをパラメータストアに格納します。)

cdk_app/cdk_import_stack.py
from aws_cdk import (
    Stack,
    aws_ssm as ssm,
    Fn
)
from constructs import Construct
import json

class CdkImportStack(Stack):

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

        # ARN、バケット名のimport.
        value={
            "ARN": Fn.import_value("s3bucket-arn-CfnOutput"),
            "NAME": Fn.import_value("s3bucket-name-CfnOutput")
        }

        # 確認用:パラメータストアへの格納.
        cfn_parameter = ssm.CfnParameter(
            self,
            "put_parameter_CfnOutput",
            type="String",
            value=json.dumps(value, indent=4),
            description="test export/import value.",
            name="/test/parameter1",
        )

なお、app.pyでは、依存元スタックオブジェクト.add_dependency(依存先スタックオブジェクト)のようにスタック間に依存関係を追加し、スタック作成順序を制御しています。

app.py
#!/usr/bin/env python3
import os
import aws_cdk as cdk
from cdk_app.cdk_export_stack import CdkExportStack
from cdk_app.cdk_import_stack import CdkImportStack

app = cdk.App()

CdkExportStack = CdkExportStack(app, "CdkExportStack",
    )
CdkImportStack = CdkImportStack(app, "CdkImportStack",
    )
# CdkExportStackが先に作成されるよう依存関係を追加
CdkImportStack.add_dependency(CdkExportStack)

app.synth()

ではデプロイしてみます。

(.venv) user_name:~/environment/cdk-app (master) $ cdk deploy --all

マネージメントコンソールからCloudFormationのスタックの出力を確認してみます。ARN、バケット名がexportされていることが分かります。
image.png

パラメータストアでも確認してみます。ARN、バケット名共に格納されてますね。
image.png

aws_cdk.Stack.export_value/aws_cdk.Fn.import_valueを使う方法

次に、aws_cdk.Stack.export_valueとaws_cdk.Fn.import_valueを使用する方法です。
以下のように参照される側のスタックでaws_cdk.Stack.export_valueを使用してバケット名とARNをexportします。ほぼCfnOutputと同じですね。

cdk_app/cdk_export_stack.py
from aws_cdk import (
    Stack,
    aws_s3 as s3,
    RemovalPolicy,
)
from constructs import Construct

class CdkExportStack(Stack):

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

        s3bucket = s3.Bucket(
            self,
            "MyS3Bucket",
            bucket_name = "cdk-test-bucket-yyyymmdd",
            versioned=True,
            removal_policy=RemovalPolicy.DESTROY
        )

        # ARNをexport.        
        Stack.export_value(
            self,
            exported_value=s3bucket.bucket_arn,
            name="s3bucket-arn-export-value"
        )

        # バケット名をexport.        
        Stack.export_value(
            self,
            exported_value=s3bucket.bucket_name,
            name="s3bucket-name-export-value"
        )

参照する側も先ほどと同じです。

cdk_app/cdk_import_stack.py
from aws_cdk import (
    Stack,
    aws_ssm as ssm,
    Fn
)
from constructs import Construct
import json

class CdkImportStack(Stack):

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

        # ARN、バケット名のimport.
        value={
            "ARN": Fn.import_value("s3bucket-arn-export-value"),
            "NAME": Fn.import_value("s3bucket-name-export-value")
        }

        # 確認用:パラメータストアへの格納.
        cfn_parameter = ssm.CfnParameter(
            self,
            "put_parameter_export_value",
            type="String",
            value=json.dumps(value, indent=4),
            description="test export/import value.",
            name="/test/parameter2",
        )

デプロイしてマネージメントコンソールでCloudFormationのスタックの出力とパラメータストアを確認してみます。先ほどと同様に確認できます。先ほどと違いがあるとするとaws_cdk.Fn.import_valueを使用する場合は説明(description)の設定ができないことでしょうか。
image.png

image.png

Stackのアトリビュートに追加する方法

最後に、Stackのアトリビュートに追加する方法です。
以下のように参照される側のスタックでStackのアトリビュートにバケット名とARNを追加します。一番シンプルですね。

cdk_app/cdk_export_stack.py
from aws_cdk import (
    Stack,
    aws_s3 as s3,
    RemovalPolicy,
)
from constructs import Construct

class CdkExportStack(Stack):

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

        s3bucket = s3.Bucket(
            self,
            "MyS3Bucket",
            bucket_name = "cdk-test-bucket-yyyymmdd",
            versioned=True,
            removal_policy=RemovalPolicy.DESTROY
        )
        
        # ARNをexport.        
        Stack.s3bucket_arn = s3bucket.bucket_arn
        # バケット名をexport.        
        Stack.s3bucket_name = s3bucket.bucket_name

参照する側でもStackのアトリビュートを参照します。

cdk_app/cdk_import_stack.py
from aws_cdk import (
    Stack,
    aws_ssm as ssm,
)
from constructs import Construct
import json

class CdkImportStack(Stack):

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

        # ARN、バケット名のimport.
        value={
            "ARN": Stack.s3bucket_arn,
            "NAME": Stack.s3bucket_name
        }

        # 確認用:パラメータストアへの格納.
        cfn_parameter = ssm.CfnParameter(
            self,
            "put_parameter_s3bucket_arn",
            type="String",
            value=json.dumps(value, indent=4),
            description="test export/import value.",
            name="/test/parameter3",
        )

デプロイしてマネージメントコンソールでCloudFormationのスタックの出力とパラメータストアを確認してみます。先ほどと同様に確認できます。ただ、この方法だとexport名の指定も説明の設定もできないので、パッと見た目が分かりづらい状態になってしまいます。CloudFormation Templateでもこのexport名になっているので、見た目で分かりづらいのが難点でしょうか。
image.png

image.png

image.png

まとめ

AWS CDKでのクロススタック参照の方法を確認しました。3つの方法は、どれもあまり変わらないので好みで使用してもらえればと思います。(説明を付けたいならCfnOutput、見た目気にせずとにかくシンプルが好みならStackのアトリビュートに追加ですかね。)
最後まで読んでいただいてありがとうございます。
少しでも参考になれば幸いです。

参考文献

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?