CDK Migrateで生成したコードを外部パラメータに対応させる

記事タイトルとURLをコピーする

こんにちは。ディベロップメントサービス3課の千本松です。

以前の記事で、CDK Migrateを使用してAWS CloudFormation(以下、CloudFormation)からAWS CDK(以下、CDK)への基本的な移行を行いました。

今回は、実際の運用で重要となる外部パラメータの管理について解説します。

前回と同じAmazon EC2(以下、EC2)スタックを題材に、実際の検証結果を交えながら解説します。

前回の記事はこちら:AWS CloudFormationスタックをAWS CDKで管理!CDK Migrateを使ってみた - サーバーワークスエンジニアブログ

CDK Migrateとは

CDK Migrateは、CloudFormationのスタックやテンプレートをCDKコードに変換するための機能であり、CDK内のコマンドとして提供されています

ただし、現状実験的な機能として提供されており、将来的に破壊的な変更が加わる可能性がある点に注意が必要です。(2025年7月時点)

The cdk migrate command is experimental and may have breaking changes in the future.

docs.aws.amazon.com

現在のコードの課題点

CDK Migrateで変換されたコードを確認して、課題点を確認していきます。

変換前のCloudFormationテンプレートのポイント

元のCloudFormationテンプレートでは、環境ごとに異なる設定を行うために、パラメータを使用していました。

Parameters:
  EnvironmentName:
    Type: String
    Default: Dev

※ 元になるCloudFormationテンプレート全文は、前回の記事で紹介しています。

変換後のCDKコードの確認

CDK Migrateコマンドで生成されたコードを確認してみましょう。

app.py(メインアプリケーション)

#!/usr/bin/env python3
import os
import aws_cdk as cdk
from dev_ec2_stack.dev_ec2_stack_stack import DevEc2StackStack

app = cdk.App()
DevEc2StackStack(app, "Dev-EC2-Stack")
app.synth()

dev_ec2_stack_stack.py(スタック定義)

from aws_cdk import Stack
import aws_cdk as cdk
import aws_cdk.aws_ec2 as ec2
from constructs import Construct

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

    # パラメータの定義
    props = {
      'environmentName': kwargs.get('environmentName', 'Dev'),
    }

    # セキュリティグループの定義
    securityGroup = ec2.CfnSecurityGroup(self, 'SecurityGroup',
          group_description = 'Security group for EC2 instance',
          vpc_id = cdk.Fn.import_value(f"""{props['environmentName']}-VPC-ID"""),
          tags = [
            {
              'key': 'Name',
              'value': f"""{props['environmentName']}-EC2-SecurityGroup""",
            },
          ],
        )

    # EC2インスタンスの定義
    ec2Instance = ec2.CfnInstance(self, 'EC2Instance',
          image_id = 'ami-xxxxxxxxxxxxxxxxx',
          instance_type = 't3.micro',
          subnet_id = cdk.Fn.import_value(f"""{props['environmentName']}-PublicSubnet1-ID"""),
          security_group_ids = [
            securityGroup.ref,
          ],
          tags = [
            {
              'key': 'Name',
              'value': f"""{props['environmentName']}-EC2-Instance""",
            },
            {
              'key': 'Environment',
              'value': props['environmentName'],
            },
          ],
        )

    # 出力値の定義
    self.instance_id = ec2Instance.ref
    cdk.CfnOutput(self, 'CfnOutputInstanceId', 
      key = 'InstanceId',
      description = 'EC2 Instance ID',
      export_name = f"""{props['environmentName']}-EC2-Instance-ID""",
      value = str(self.instance_id),
    )

課題点

以下の行で環境名をパラメータとして受け取っていますが、現状ではデフォルト値が設定されているだけで、実際の環境ごとに異なる設定を適用することができません。

また、異なる環境を設定するためには、コードを直接編集する必要があります。

# パラメータの定義
props = {
  'environmentName': kwargs.get('environmentName', 'Dev'),
}

コンテキスト値を使用した解決策

CDKでは、アプリが外部からパラメータを受け取るために、コンテキスト値を使用することができます。

このコンテキスト値を使用して、環境ごとに異なるパラメータを指定できるように変更していきます。

参考:コンテキスト値と AWS CDK

app.pyの修正

コンテキスト値を使用して外部からパラメータを受け取れるようにapp.py(メインアプリケーション)を修正します:

#!/usr/bin/env python3
import os
import aws_cdk as cdk
from dev_ec2_stack.dev_ec2_stack_stack import DevEc2StackStack

app = cdk.App()

##########################################
# コンテキスト値から環境名を取得するように変更
environment_name = app.node.try_get_context("environmentName")
if not environment_name:
    raise ValueError("environmentName context value is required. Use: cdk deploy -c environmentName=Dev")
##########################################

##########################################
# スタック名を環境名に基づいて設定
# 取得した環境名をスタックに渡すように変更
DevEc2StackStack(app, f"{environment_name}-EC2-Stack", environment_name=environment_name)
##########################################

app.synth()

dev_ec2_stack_stack.py の修正

スタックがパラメータを引数として受け取れるように修正します:

from aws_cdk import Stack
import aws_cdk as cdk
import aws_cdk.aws_ec2 as ec2
from constructs import Construct

class DevEc2StackStack(Stack):
    # ===========================================
    # コンストラクタの引数に environment_name を追加
    def __init__(self, scope: Construct, construct_id: str, environment_name: str, **kwargs):
    # ===========================================

        super().__init__(scope, construct_id, **kwargs)

        # VPCの参照を取得
        vpc_id = cdk.Fn.import_value(f"{environment_name}-VPC-ID")
        subnet_id = cdk.Fn.import_value(f"{environment_name}-PublicSubnet1-ID")

        # セキュリティグループの作成
        security_group = ec2.CfnSecurityGroup(
            self, 'SecurityGroup',
            group_description='Security group for EC2 instance',
            vpc_id=vpc_id,
            tags=[{
                'key': 'Name',
                'value': f"{environment_name}-EC2-SecurityGroup",
            }]
        )

        # EC2インスタンスの作成
        ec2_instance = ec2.CfnInstance(
            self, 'EC2Instance',
            image_id='ami-xxxxxxxxxxxxxxxxx',
            instance_type='t3.micro',
            subnet_id=subnet_id,
            security_group_ids=[security_group.ref],
            tags=[
                {
                    'key': 'Name',
                    'value': f"{environment_name}-EC2-Instance",
                },
                {
                    'key': 'Environment',
                    'value': environment_name,
                }
            ]
        )

        # 出力値の定義
        cdk.CfnOutput(
            self, 'CfnOutputInstanceId',
            key='InstanceId',
            description='EC2 Instance ID',
            export_name=f"{environment_name}-EC2-Instance-ID",
            value=ec2_instance.ref
        )

contextの使い方

以下のようにコマンドラインからコンテキスト値を指定してデプロイできます。

# 開発環境へのデプロイ(変更セット確認)
cdk deploy -c environmentName=Dev --no-execute

# 開発環境へのデプロイ
cdk deploy -c environmentName=Dev

# 本番環境へのデプロイ
cdk deploy -c environmentName=Prod

もしくは、cdk.jsonファイルにデフォルトの環境名を設定することもできます。

{
  "app": "python app.py",
  "context": {
    "environmentName": "Dev"
  }
}

まとめ

CDK Migrateを使用して生成されたコードを、環境ごとに異なるパラメータに対応させる方法を解説しました。

コンテキスト値を利用することで、パラメータのハードコーディングを解消し、環境ごとに異なる設定を簡単に適用できるようになりました。

最後までお読みいただきありがとうございました!

本ブログが誰かの参考になれば幸いです。

千本松 輝(記事一覧)

アプリケーションサービス部ディベロップメントサービス3課

CloudFormation・CDKなどIaCが好きです。AWS SAP資格勉強中。好物は生ガキと焼酎。