🛠

IaCサービス【AWS CDK】について基本を実践

2025/02/23に公開

はじめに

前回の「AWS CloudFormation」に引き続き、今回もAWSのIaCサービスである「AWS CDK」について概要と実践方法をご紹介します。
お時間あれば前回記事をご参照の後に、本記事をご覧いただければと思います。

https://zenn.dev/gj77a/articles/920440ae3f7ec6

また今回ご紹介する操作は、基本的に以下リンクの公式チュートリアルに沿った内容としていますので、不明点がありましたらそちらも併せてご確認ください。

https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/hello_world.html

私自身が学習中の身ではありますが、同じような初学者の方にとって、この記事が少しでもお力になれれば幸いです。

AWS CDKとは・・・?

今回取り上げる「AWS CDK(Cloud Development Kit)」とはCloudFormationをより便利に使用できるように開発されたフレームワークのことです。(以降「CDK」と略記します)

CloudFormationテンプレートはYAML/JSONといった一般的にコーディングで使用されない言語で記述する必要がありましたが、CDKを使用すると「TypeScript, Python, Java, C#, Go」といった、フロント側でも広く使用される言語で各種リソースの記述が可能となります。
それにより、多くのアプリ側開発者にとって新たな言語を学習するコストが低くなる点、変数や各種関数を利用した柔軟なリソース定義を行える点が、CDKを利用する大きな利点と言えます。

CDKは内部的にCloudFormationと連携しており、CDKで記述したコードは最終的に CloudFormation テンプレートに変換され、スタックが作成されます。

CDKインストールの前に

公式デベロッパーガイドにも記載の通り、CDKの実行には「Node.js 14.15.0 以降」のインストールが必要です。
後の手順に進まれる前に、予めご利用のOSに沿った手順でインストールをお願いします。
また、CDKスタックの記述に使用する言語によっても前提条件が規定されている場合がありますので、必ず上記リンクをご確認ください。

https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/prerequisites.html

本稿ではPythonを使用するため「pip および virtualenv を含む Python 3.7 以降」をインストールします。

今回は「インストールが楽、後片付けが楽」という点からAmazon Linux 2023のEC2(c5a.xlarge)上に実行環境を構築します。
前提パッケージのインストールが行えれば、ローカルでもクラウドでもどのような環境でも問題ありませんが、必要以上にスペックをケチることは推奨しません。(t2.microのEC2でデプロイ実行したらCPU100%で張り付きました...)

実行環境の準備につきましては記載を省略させていただきます。

CDKインストール

早速CDKのインストールを実施しましょう。

CDKインストール
$ sudo npm install -g aws-cdk

added 1 package in 1s

正常にインストールできたことを確認するため、CDKのバージョンを取得します。

CDKバージョン確認
$ cdk --version
2.179.0 (build b867f19)

CDKプロジェクトの作成

適当なディレクトリを作成し、そのディレクトリに移動します。

プロジェクトルートの作成
$ mkdir cdktest
$ cd cdktest

そのディレクトリ内で cdk init コマンドを実行し、CDKプロジェクトの初期化を行います。
--language オプションでCDKスタックの記述に使用する言語を指定します。
※今回の場合は --language python

プロジェクトの初期化
$ cdk init app --language python

またpythonの場合は、続けて仮想環境の起動とCDK関連モジュールのインストールを実行します。

Python仮想環境起動 & 関連モジュールインストール
$ source .venv/bin/activate
$ python -m pip install -r requirements.txt

ここまでで一旦、現状のディレクトリ構成について確認してみましょう。
cdk init コマンドによっていろいろ作成されています。

プロジェクトディレクトリ構成確認
$ pwd 
/home/ssm-user/cdktest

$ ls -l
total 28
-rw-r--r--. 1 ssm-user ssm-user 1658 Feb 18 06:51 README.md
-rw-r--r--. 1 ssm-user ssm-user  928 Feb 18 06:51 app.py
-rw-r--r--. 1 ssm-user ssm-user 4500 Feb 18 06:51 cdk.json
drwxr-xr-x. 2 ssm-user ssm-user   49 Feb 18 06:51 cdktest
-rw-r--r--. 1 ssm-user ssm-user   14 Feb 18 06:51 requirements-dev.txt
-rw-r--r--. 1 ssm-user ssm-user   48 Feb 18 06:51 requirements.txt
-rw-r--r--. 1 ssm-user ssm-user  437 Feb 18 06:51 source.bat
drwxr-xr-x. 3 ssm-user ssm-user   37 Feb 18 06:51 tests

特に重要なファイルにについて簡単に解説を記載します。

  1. app.py
    CDK アプリケーションのエントリーポイント(メインスクリプト)。
    CDK スタック(CloudFormation のリソース定義)を作成し、デプロイ可能な形に変換してくれます。
app.py(初期状態)
#!/usr/bin/env python3

import aws_cdk as cdk
from cdktest.cdktest_stack import CdktestStack

app = cdk.App() # CDK アプリのルートを作成
CdktestStack(app, "cdktest") # スタック(CloudFormation のリソース定義)を作成

app.synth() # CDK を CloudFormation に変換(テンプレートを生成)
  1. cdk.json
    CDK コマンドの設定を管理する JSON ファイル。
    cdk deploycdk synth 実行時の設定が記載されています。
cdk.json(初期状態)(省略)
{
  "app": "python3 app.py", # CDKが実行するアプリケーションのエントリーポイント
  "watch": { # cdk watch コマンド実行時に、どのファイルを監視するか、または監視から除外するかを設定
    "include": [
      "**"
    ],
    "exclude": [
      "README.md",
      "cdk*.json",
      "requirements*.txt",
      "source.bat",
      "**/__init__.py",
      "**/__pycache__",
      "tests"
    ]
  },
  "context": { # CDKの動作に影響を与える追加の設定などを指定するためのセクション
    "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
    "@aws-cdk/core:checkSecretUsage": true,
    "@aws-cdk/core:target-partitions": [
      "aws",
      "aws-cn"
    ],
    "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
    "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
    "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
    "@aws-cdk/aws-iam:minimizePolicies": true,

    ### 省略 ###

  }
}
  1. cdktest/(ディレクトリ)
    CDKスタック(CloudFormation のリソース定義)が格納されるディレクトリです。
    ディレクトリ名はプロジェクトルートのディレクトリ名が設定されます。
    内部にある「 (プロジェクトルート名)_stack.py 」がCDKの核とも言えるファイルであり、このファイルに作成するリソースなどを記述していきます。
(プロジェクトルート名)_stack.py(初期状態)
from aws_cdk import (
    # Duration,
    Stack,
    # aws_sqs as sqs,
)
from constructs import Construct

class CdktestStack(Stack):

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

        # The code that defines your stack goes here

        # example resource
        # queue = sqs.Queue(
        #     self, "CdktestQueue",
        #     visibility_timeout=Duration.seconds(300),
        # )

AWS環境の設定

このステップでは、作成するCDKスタックのデプロイ先となるAWS環境情報を設定します。
具体的にはアカウントIDとリージョンを「app.py」に明示的に指定します。
指定しなかった場合は、AWS CLIのデフォルトの認証情報やリージョン設定(~/.aws/config や ~/.aws/credentialsなど)を参照して、自動的にデプロイ先のアカウントやリージョンが判断されます。

  • アカウントIDの確認
アカウントID確認
$ aws sts get-caller-identity --query "Account" --output text
1234567890
  • リージョン確認
リージョン確認
$ aws configure get region
ap-northeast-1
  • 「app.py」に確認した情報を追記
app.py
#!/usr/bin/env python3
import os

import aws_cdk as cdk

from cdktest.cdktest_stack import CdktestStack


app = cdk.App()
CdktestStack(app, "CdktestStack",
   # If you don't specify 'env', this stack will be environment-agnostic.
   # Account/Region-dependent features and context lookups will not work,
   # but a single synthesized template can be deployed anywhere.

   # Uncomment the next line to specialize this stack for the AWS Account
   # and Region that are implied by the current CLI configuration.

   #env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')),

   # Uncomment the next line if you know exactly what Account and Region you
   # want to deploy the stack to. */

   # ↓ コメントアウトを外してアカウントIDとリージョンを設定する
   env=cdk.Environment(account='1234567890', region='ap-northeast-1'),

   # For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html
   )

app.synth()

ブートストラップの実行

説明

CDKを初めて特定のAWSアカウントやリージョンで使用する際には cdk bootstrap コマンドを実行する必要があります。
このコマンドを実行することで、その環境に必要な前提リソースがCloudFormationにより自動的に作成されます。
作成されるリソースの内、代表的なものを以下表に記載します。

リソース名 目的
S3バケット CDKのアセット(Lambda コード、静的ファイルなど)の一時保存用
ECRリポジトリ CDKが管理するコンテナイメージの保存用
IAMロール CDKによるデプロイ時に必要な権限を付与
IAMポリシー CDKによるデプロイ時に必要な権限を付与(IAMロールにアタッチ)
SSMパラメータ ブートストラップのメタデータ管理用

ブートストラップ実行時に使用されるCloudFormationテンプレートは以下コマンドで取得可能です。
より詳細が気になる方は取得したyamlファイルより内容をご確認ください。

ブートストラップテンプレート取得
$ cdk bootstrap --show-template > bootstrap-template.yaml

実行

実際にブートストラップを実行します。(平常、数分程度で完了)
✅ Environment aws://アカウントID/リージョン bootstrapped. が表示されればブートストラップ完了です。

$ cdk bootstrap
 ⏳  Bootstrapping environment aws://1234567890/ap-northeast-1...
Trusted accounts for deployment: (none)
Trusted accounts for lookup: (none)
Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize.
CDKToolkit: creating CloudFormation changeset...
CDKToolkit |  0/12 | 1:55:10 PM | REVIEW_IN_PROGRESS   | AWS::CloudFormation::Stack | CDKToolkit User Initiated
CDKToolkit |  0/12 | 1:55:16 PM | CREATE_IN_PROGRESS   | AWS::CloudFormation::Stack | CDKToolkit User Initiated

( 中略 )

CDKToolkit | 11/12 | 1:56:01 PM | CREATE_COMPLETE      | AWS::IAM::Role          | DeploymentActionRole
CDKToolkit | 12/12 | 1:56:02 PM | CREATE_COMPLETE      | AWS::CloudFormation::Stack | CDKToolkit
 ✅  Environment aws://1234567890/ap-northeast-1 bootstrapped.

CDKスタックの作成

ブートストラップの正常終了を確認後、核となるCDKスタックの作成に着手します。
作成するスタックの内容ですが、今回は(も)私の他記事でご紹介したWeb/APサーバ環境を転用します。
Web/APサーバ環境の詳細につきまして、ご興味ある方は下記リンクをご参照ください。
https://zenn.dev/gj77a/articles/3f3b1be845289b

cdktest/cdktest_stack.py の中身を以下の通り編集します。

cdktest_stack.py
import aws_cdk as cdk
from aws_cdk import (
    aws_ec2 as ec2
)
from constructs import Construct

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

        # 既存のVPCを使用
        vpc = ec2.Vpc.from_lookup(self, 'VPC', vpc_id='vpc-xxxxxxxxxxxxxxxx')

        # 既存のサブネットを使用
        subnet = ec2.Subnet.from_subnet_attributes(self, 'Subnet',
            subnet_id='subnet-xxxxxxxxxxxxxxxx',
            availability_zone='ap-northeast-1a',
            route_table_id='rtb-xxxxxxxxxxxxxxxx7'
        )

        # セキュリティグループの作成
        security_group = ec2.SecurityGroup(
            self, 'SecurityGroup',
            vpc=vpc,
            security_group_name='cdk-test-sg',
            description='test',
            allow_all_outbound=True
        )

        # HTTPトラフィックを許可
        security_group.add_ingress_rule(
            ec2.Peer.any_ipv4(),
            ec2.Port.tcp(80),
            'Allow HTTP traffic'
        )

        # EC2インスタンスの作成
        instance = ec2.Instance(
            self, 'EC2Instance',
            vpc=vpc,
            vpc_subnets=ec2.SubnetSelection(
                # 既存のサブネットIDを指定
                subnets=[subnet]
            ),
            instance_type=ec2.InstanceType('t2.micro'),
            machine_image=ec2.MachineImage.generic_linux({
                # Amazon Linux 2023 AMIのID
                'ap-northeast-1': 'ami-06c6f3fa7959e5fdd'
            }),
            security_group=security_group,
            block_devices=[
                ec2.BlockDevice(
                    device_name='/dev/xvda',
                    volume=ec2.BlockDeviceVolume.ebs(8, volume_type=ec2.EbsDeviceVolumeType.GP3)
                )
            ],

            # サーバ起動後に実行するコマンドを記述
            user_data=ec2.UserData.custom(
                """#!/bin/bash
                sudo dnf update -y
                sudo dnf -y install java-21-amazon-corretto-devel
                sudo dnf -y install tomcat10-webapps.noarch
                sudo dnf -y install httpd-2.4.62-1.amzn2023
                sudo systemctl start httpd tomcat10
                sudo systemctl enable httpd tomcat10
                """
            )
        )

        # インスタンスにタグを追加
        cdk.Tags.of(instance).add('Name', 'cdk-test-instance')

デプロイ前チェック

スタックファイルの編集完了後、そのままデプロイ・・・する前に確認作業を挟みます。

  1. cdk synth

まずは以下コマンドを実行しましょう。

cdk synth

上記コマンドは、記述したスタックファイルからCloudFormationテンプレートを出力するコマンドですが、その際に構文エラーやリソースの指定ミスなどがチェックされます。
コマンド実行後に表示される結果を確認し、エラーが発生しているようであれば修正し再実行しましょう。

正常に終了した場合、YAML形式のCloudFormationテンプレートが標準出力に表示され、JSON形式のテンプレートが「cdk.out/」ディレクトリ内に保存されます。

cdk synth コマンドはプロジェクトルート直下で実行してください。

  1. cdk diff

続けて以下コマンドを実行します。

cdk diff

上記コマンドを実行すると、既にAWS上にデプロイされているCloudFormationスタックと、ローカル上で記述したCDKスタックファイルの差分を比較し、追加・変更・削除されるリソースを一覧表示することができます。

今回のように全く新規のデプロイの場合でも、デプロイにより作成されるリソースの確認を行うことができるため、とりあえず実行することをおすすめします。

※ 前述の cdk synth でも確認可能ですが、こちらのコマンドの方が可読性が高いです。

デプロイ

確認作業が終わりましたら、後はデプロイするだけです。
以下コマンドを実行しましょう。

cdk deploy

数分待機し、以下表示が出力されればデプロイ完了です!

 ✅  CdktestStack

✨  Deployment time: 41.65s

続けてマネジメントコンソールから作成されたリソースを確認しましょう。

作成リソース確認

最後に、スタックファイルに記述したリソースが問題なく作成されたか確認しましょう。

  1. 各種リソース
  • インスタンス名(ネームタグ):cdk-test-instance
  • インスタンスタイプ:t2.micro
  • IAMロール:CdktestStack-EC2InstanceInstanceRole(CDKにより自動作成)

※IAMロールに付与された信頼ポリシー↓

{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Effect": "Allow",
           "Principal": {
               "Service": "ec2.amazonaws.com"
           },
           "Action": "sts:AssumeRole"
       }
   ]
}
  • セキュリティグループ:cdk-test-sg
    ・インバウンド:ポート80:0.0.0.0/0
    ・アウトバウンド:すべて:0.0.0.0/0

  1. 接続確認

ブラウザで「http://パブリックIP:80」に接続。

スタックファイルに記載漏れていましたが、セキュリティグループのインバウンドルールに「ポート:8080」を追加することでTomcatのデフォルトページに接続できます。
ブラウザで「http://パブリックIP:8080」に接続。

ApacheとTomcatに接続できたため、スタックファイルに記載した「user_data」内の処理が正常に完了していると判断し、サーバ内での確認は割愛いたします。

後片付け

リソースが正常に作成されたことを確認できましたら、忘れる前に後片付け(削除)を行いましょう。
後片付けは非常に簡単で、以下コマンドを実行するだけです。

$ cdk destroy

以下表示が出ればリソース削除完了です。

✅  CdktestStack: destroyed

念のため、マネジメントコンソール画面からでも削除されたことを確認しておきましょう。

おわりに

前回のCloudFormationに続きIaCツールのご紹介でした。

ツールの実行環境さえ用意できれば、スタックファイルを記述し何度かコマンドを叩くだけでインフラ環境の構築が完了する点はかなり楽ですし、スタックファイルを保存しておけば何度でも同一環境が作成できる点も有用性の高さを感じました。

ただやはり、このツールの真価は各種プログラミング言語を利用した柔軟なスタックファイルの記述が可能なところにあると思いますので、引き続き言語の学習も兼ねて積極的に利用していこうと思います。
(現状、私のスキルではCloudFormationの方が使用ハードルが低いです・・・)

今後もAWS CDKを活用した内容の記事を書いていこうと思いますので、またご覧いただければ幸いです。

以上、ここまでお付き合いいただきありがとうございました。

Discussion