0
0

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

はじめに

CDKでスタックを作成するとき、インフラ系のサービス(VPC、S3、CloudWatch、・・・)と、アプリケーションやサーバと直接結びつくサービス(Lambda、EC2、・・・)とで、スタックを分けたいと思うことがありました。スタックのデプロイは時間がかかるので、スタックを分けることであまり変更のないスタックはそのままにしつつ、よく変更するアプリケーションやサーバのスタックだけ更新するといったことができるメリットがあります。

他にも無償の範囲で利用できるサービスと、プロビジョニングするだけで費用が発生するサービス(VPCエンドポイントやALBなど)で分けておくと、不必要なときはまとめてスタックを消しておくことでコスト削減につなげるといったことも可能になります。

すでに作成されているサービスを参照するときは、各サービスのfrom_lookup関数を使えば検索できます。しかし、自分のアカウントIDやリージョンを予め指定する必要があるほか、CDKで作成したスタックのテンプレートを他アカウントで使用できないなどのデメリットがあります。できることならfrom_lookup関数の使用を避ける設計をしたほうが保守性の高いシステムになるのではないかと、個人的には感じています。

ここでVPCのfrom_lookupのリファレンスを読むと、次の記載があります。

This function only needs to be used to use VPCs not defined in your CDK application. If you are looking to share a VPC between stacks, you can pass the Vpc object between stacks and use it as normal.

この関数は、CDK アプリケーションで定義されていない VPC を使用する場合にのみ使用する必要があります。スタック間でVPCを共有したい場合は、スタック間でVpcオブジェクトを渡し、通常通り使用することができます。(DeepL翻訳)

公式的にも、CDKで作成したサービスを参照するときはfrom_lookupを使用せず、スタック間でオブジェクトを渡せばいいとあります。

が、じゃあどうすればできるんだよ?というのを探すのに苦労したので、備忘録として残します。

結論

スタックごとに作成したサービスのオブジェクトをインスタンス変数として保持しておき、コンストラクタでスタックのオブジェクトごと渡すだけで参照できます。

この方法に限らず、作ったサービスのオブジェクトを何らかの方法で渡せばいいです。

実際の書き方

通常通り、Cloud9などのサーバでCDKの開発環境を初期化します。

mkdir sample_app
cd sample_app
cdk init app --language python
source .venv/bin/activate
python -m pip install -r requirements.txt
cdk synth
# リージョンで初めてCDKを使うときのみ以下を実行
cdk bootstrap

ここでは冒頭の例のようにインフラとサーバでスタックを分割し、インフラスタックでVPCを作成し、サーバスタックでEC2を配置してみます。まずはインフラスタックを作成します。

sample_app/infra_stack.py
from aws_cdk import (
    Stack,
    aws_ec2,
)
from constructs import Construct

class InfraStack(Stack):

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

        self.vpc = aws_ec2.Vpc(self, "infra-stack-vpc",
            cidr="10.0.0.0/16",
            enable_dns_support=True,
            enable_dns_hostnames=True,
            max_azs=3,
            nat_gateways=0,
            subnet_configuration=[
                aws_ec2.SubnetConfiguration(
                    name="infra-subnet",
                    cidr_mask=24,
                    subnet_type=aws_ec2.SubnetType.PRIVATE_ISOLATED,
                ),
            ],
        )

ここでのポイントは、aws_ec2.Vpcのオブジェクトをスタックのインスタンス変数として保持している点です。これにより実際にこのスタッククラスを初期化するapp.pyaws_ec2.Vpcオブジェクトを参照できるようになります。あとは後続のスタックにInfraStackのインスタンスをコンストラクタで渡すだけです。

sample_app/server_stack.py
from aws_cdk import (
    Stack,
    aws_ec2,
)
from constructs import Construct
from sample_app.infra_stack import InfraStack

class ServerStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, infra: InfraStack, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        
        self.ec2 = aws_ec2.Instance(self, "test-instance",
            vpc=infra.vpc,
            instance_type=aws_ec2.InstanceType.of(
                aws_ec2.InstanceClass.T2,
                aws_ec2.InstanceSize.MICRO
            ),
            machine_image=aws_ec2.MachineImage.latest_amazon_linux(
                generation=aws_ec2.AmazonLinuxGeneration.AMAZON_LINUX_2,
            ),
        )
app.py
#!/usr/bin/env python3
import os

import aws_cdk as cdk

from sample_app.infra_stack import InfraStack
from sample_app.server_stack import ServerStack

app = cdk.App()

env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION'))
infra = InfraStack(app, "InfraStack",
    env=env,
)
server = ServerStack(app, "ServerStack",
    env=env,
    infra=infra,
)

app.synth()

最後に、作ったスタックをデプロイします。デプロイに限らず、複数スタックの操作をするときは、コマンドの最後に--allをつける必要があります。

cdk synth --all
cdk deploy --all

なお、--allの代わりにスタック名を指定すると、個別のスタックごとに操作することもできます。

cdk destroy ServerStack

おわりに

CDKは個別関数レベルのリファレンスは結構整理されていて見やすいですが、使い方のサンプルが少ないのが難点です。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?