AWS CDK と IaCの歴史


# はじめに

- インフラコーディングの「AWS CDK」ってなんだっけ？
- 知らなかったので、他IaCと合わせて調べてみました   

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

# AWS CDK のしくみ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/f0f6d603-a48a-7a27-fa1a-8069f81a4b81.png)

引用元：https://pages.awscloud.com/rs/112-TZM-766/images/AWS-Black-Belt_2023_AWS-CDK-Basic-1-Overview_0731_v1.pdf



# IaC 記述アプローチの違い

Infrastructure as Code (IaC) の記述には主に二つのアプローチがあります。
それぞれに特徴があり、使用するツールや目的によって選ばれます。

1. **宣言型（Declarative）アプローチ:**
   - **特徴**: 望む最終的な状態を記述し、その状態をどのように達成するかは記述しない
       - つまり、「何を達成したいか」を指定し、「どのように達成するか」はツールに委ねられる
   - **例**: Terraform、AWS CloudFormationなど。
       - リソースの構成をファイルに記述し、ツールが自動的にこの状態を実現するための手順を計算し実行される

2. **手続き型（Imperative）アプローチ:**
   - **特徴**: 望む結果を達成するための具体的な手順や命令を記述する。
       - つまり、「どのようにして目的を達成するか」に焦点を当て、ステップバイステップで指示を出す
   - **例**: Chef、Puppet、Ansibleなど
       - 特定のタスクを実行するためのスクリプトやレシピを書き、それに従ってサーバーやリソースを構成する

### 比較まとめ

| 特徴               | 宣言型アプローチ                      | 手続き型アプローチ                    |
|------------------|-------------------------------------|-------------------------------------|
| **定義の方法**     | 望む最終的な状態を指定                   | どのようにその状態に達するかの手順を指定     |
| **主な利点**       | 管理が容易、一貫性と再現性が高い           | 細かい制御が可能、柔軟なカスタマイズが行える |
| **主な欠点**       | 複雑なロジックの表現が困難                 | 状態の一貫性の維持が困難                   |
| **適用例**         | AWS CloudFormation, Terraform       | Chef, Puppet, Ansible               |
| **コードの抽象度**   | 高い（抽象的な記述）                      | 低い（具体的な手順）                    |
| **目的**           | インフラの自動化と標準化                   | 特定の条件や環境に対する詳細な設定            |
| **変更管理**       | 自動的に依存関係と変更を管理               | 変更の追跡と管理が手動で必要               |
| **スケールの管理**   | 大規模な環境でも容易に扱える                 | 大規模な環境での管理が複雑になる可能性がある |

## AWS CDKとは

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

AWS CDK（AWS Cloud Development Kit）は、IaCの一形態であり、AWS リソースを構成および管理するために、開発者が慣れ親しんだプログラミング言語を使用できます。AWS CDK では、TypeScript、JavaScript、Python、Java、C#など、複数の言語をサポートしています。

例えば、AWS CDK を使用してサーバーレスアプリケーション（Lambda関数、API Gateway、DynamoDBテーブルなど）を設定し、デプロイすることが可能です。

AWS CDK（AWS Cloud Development Kit）は主に**宣言型**のアプローチを取っていますが、実際には宣言型と手続き型の要素を組み合わせたハイブリッドアプローチにをとっています。

- **宣言型の要素**: CDKを使用する際、開発者はAWSのリソースを「Construct」として表現。これは、リソースの最終的な状態を表現するオブジェクトであり、CDKがそれを基にCloudFormationテンプレートを生成する。つまり、望むリソースの構成を高レベルで指定し、具体的なプロビジョニングの詳細はCDKが処理する。

- **手続き型の要素**: 一方で、CDKでは、スクリプト内でリソース間の関連付けや特定の設定を行う際に、プログラム的な制御が可能。これにより、より具体的な操作をコードで記述することができ、複雑なデプロイメントロジックを実装する際に役立つ。


## Infrastructure as Code (IaC) の登場とその発展の歴史

| 年代         | 出来事                                                                 |
|--------------|----------------------------------------------------------------------|
| 2000年代初頭 | **Puppetの登場**: 初期のIaCツールとしてPuppetが開発され、設定管理の自動化が始まる |
| 2005年       | **Chefの登場**: Chefがリリースされ、Puppetと同様に設定管理の自動化に貢献     |
| 2009年       | **Ansibleの登場**: よりシンプルで使いやすい設定管理ツールとしてAnsibleが開発される  |
| 2010年       | **Terraformの登場**: HashiCorpによりTerraformがリリースされ、クラウドインフラのプロビジョニングに革命 |
| 2011年       | **AWS CloudFormation**: AWSがCloudFormationをリリースし、AWSリソースの宣言型管理を提供 |
| 2018年       | **AWS CDK**: AWSからプログラム可能なインフラストラクチャの設定と管理を可能にするCDKが導入される |

## AWS CDK - 登場背景と解決したい課題

AWS CDK（AWS Cloud Development Kit）の登場背景と解決したい課題について説明します。

### AWS CDKの登場背景

- AWS CDKは2018年に公開された
- その背景には、クラウドサービスの利用の拡大と共に、インフラストラクチャの設定と管理の複雑性が増していたこと
    - AWS CloudFormationのような既存のIaCツールは強力であるものの、JSONやYAMLで長大な設定ファイルを書く必要がある
        - これが多くの開発者にとっては直感的でなく、煩雑な作業だった
        - 特に、動的な環境や複雑な条件に基づくリソース管理を行う場合、これらのフォーマットでは柔軟性に欠けることが問題となっていた

### 解決したい課題

AWS CDKは以下のような主要な課題を解決することを目指しています。

1. **開発者フレンドリーなインターフェースの提供**:
   - 開発者が慣れ親しんだプログラミング言語（例：TypeScript、Python、Java..）を使って、インフラストラクチャをコードとして定義できるようにすることで、学習曲線を低減し、開発プロセスを効率化する

2. **抽象化と再利用性の向上**:
   - 高レベルの抽象化コンポーネント（Constructs）を導入することで、複雑なクラウドリソースを簡単に組み合わせて再利用することが可能になります。これにより、コードの重複を減らし、一貫性と保守性を向上させる

3. **動的な環境での柔軟性の提供**:
   - プログラミング言語を用いることで、条件分岐やループといったプログラムの構造を使って、より動的で柔軟なインフラストラクチャの設定が可能になる。これは、環境に応じて変更が頻繁に必要なアプリケーションや、複数環境にわたるデプロイメントで特に有用。

4. **自動化と統合の促進**:
   - CDKはAWS CloudFormationと統合されており、CDKで定義したインフラストラクチャがCloudFormationスタックとしてデプロイされます。これにより、既存のAWSエコシステムとシームレスに連携し、デプロイメントプロセスを自動化する。

## AWS CDK の概念 - CloudFormation との⽐較


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/9373cd3d-a129-87f2-b0dc-630ac61b4c11.png)

引用元：https://pages.awscloud.com/rs/112-TZM-766/images/AWS-Black-Belt_2023_AWS-CDK-Basic-1-Overview_0731_v1.pdf

## AWS CDKの記述例

AWS CDKを使用して以下を含むインフラストラクチャの設定例を記述してみます。
- バックエンド（Java Spring Boot）
- フロントエンド（React）
- データベース（MySQL）

バックエンドはAmazon ECSのFargateサービスで実行され、フロントエンドはS3とCloudFrontを使用して配信されます。

記述自体はpythonで行いました。

```python

from aws_cdk import (
    core,
    aws_ec2 as ec2,
    aws_ecs as ecs,
    aws_ecs_patterns as ecs_patterns,
    aws_rds as rds,
    aws_s3 as s3,
    aws_cloudfront as cloudfront,
    aws_cloudfront_origins as origins,
    aws_s3_deployment as s3_deployment,
    aws_iam as iam
)

class ExperimentalPlanAppStack(core.Stack):
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # VPCの作成
        vpc = ec2.Vpc(self, "ExperimentalPlanVpc", max_azs=3)

        # RDSデータベース用セキュリティグループ
        db_security_group = ec2.SecurityGroup(
            self, "DatabaseSecurityGroup",
            vpc=vpc,
            description="Allow mysql access",
            security_group_name="DB_Security_Group"
        )
        db_security_group.add_ingress_rule(
            ec2.Peer.ipv4(vpc.vpc_cidr_block),
            ec2.Port.tcp(3306),
            "allow mysql access from inside vpc"
        )

        # RDS MySQLデータベースの作成
        db_instance = rds.DatabaseInstance(
            self, "MySqlDatabase",
            engine=rds.DatabaseInstanceEngine.mysql(
                version=rds.MysqlEngineVersion.VER_8_0_19),
            instance_type=ec2.InstanceType.of(
                ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.MICRO),
            vpc=vpc,
            vpc_subnets={
                "subnet_type": ec2.SubnetType.PRIVATE
            },
            security_groups=[db_security_group],
            deletion_protection=False,
            database_name="experimentalplandb"
        )

        # ECSクラスターの作成
        cluster = ecs.Cluster(self, "ExperimentalPlanCluster", vpc=vpc)

        # Spring Bootアプリを実行するECSサービス
        spring_boot_service = ecs_patterns.ApplicationLoadBalancedFargateService(
            self, "SpringBootService",
            cluster=cluster,
            cpu=512,
            memory_limit_mib=1024,
            task_image_options={
                "image": ecs.ContainerImage.from_registry("yourdockerhub/springboot:latest"),
                "environment": {
                    "SPRING_DATASOURCE_URL": f"jdbc:mysql://{db_instance.db_instance_endpoint_address}/experimentalplandb"
                }
            },
            public_load_balancer=True
        )

        # Reactアプリ用のS3バケット
        site_bucket = s3.Bucket(self, "SiteBucket",
                                website_index_document="index.html",
                                public_read_access=True,
                                removal_policy=core.RemovalPolicy.DESTROY)

        # CloudFrontディストリビューション
        distribution = cloudfront.Distribution(self, "SiteDistribution",
                                                default_behavior={
                                                    "origin": origins.S3Origin(site_bucket),
                                                    "viewer_protocol_policy": cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS
                                                })

        # ReactアプリをS3にデプロイ
        s3_deployment.BucketDeployment(self, "DeployWithInvalidation",
                                       sources=[s3_deployment.Source.asset("./path/to/your/react/build/folder")],
                                       destination_bucket=site_bucket,
                                       distribution=distribution,
                                       distribution_paths=["/*"])

app = core.App()
ExperimentalPlanAppStack(app, "ExperimentalPlanAppStack")
app.synth()

```

# まとめ

インフラコーディングツールののAWS CDKについて、他IaCと比較して調べてみました。
CDKはAWS CloudFormationと統合されており、比較対象ではなく、合わせて使用するものだと理解しました。AWS CDKっていいものですね。

# Appendix CDK 用語まとめ

| 用語 | 説明 |
|------|------|
| Construct | CDKの最も基本的なビルディングブロック。1つまたは複数のAWSリソースを表現する。 |
| Stack | CloudFormation スタックに対応。デプロイ可能な最小単位。 |
| App | アプリケーション全体。複数のAWSアカウント、リージョンにまたがることが可能。 |
| Cloud Assembly | CDK Appの出力。デプロイに必要な資材一式(CloudFormation テンプレートやアセットなど)。 |
| L1 Construct | CloudFormationリソースおよびプロパティと1:1で対応する低レベルのConstruct。 |
| L2 Construct | デフォルト値や便利なメソッドを定義した、単一のAWSリソースを表すクラス。 |
| L3 Construct (Pattern) | 複数のリソースを含む一般的な構成パターンを抽象化したConstruct。 |
| CDK Toolkit (CLI) | CDKアプリケーションの操作に使用するコマンドラインツール。 |
| Synthesize | CDKアプリケーションからCloudFormationテンプレートなどを含むCloud Assemblyを生成すること。 |
| Bootstrap | CDKが使用するIAMロール、S3バケット、ECRリポジトリなどを作成すること。 |
| jsii | TypeScriptで書かれた単一のコードベースを各言語のコードにコンパイルして提供するツール。 |
| Construct Hub | 1,000以上のオープンソースのコンストラクトを公開しているリポジトリ。 |
| エスケープハッチ | L2コンストラクトでプロパティが設定できない場合などに、低レベルの構成にアクセスする手段。 |
| CDK for Terraform (CDKTF) | Terraformの構成をプログラミング言語で定義するためのCDKベースのフレームワーク。 |
| CDK for Kubernetes (CDK8s) | Kubernetesのマニフェストファイルをプログラミング言語で生成するツールキット。 |
| Aspect | Constructツリーの各Nodeへの操作を実装する手段。 |
| Provider Framework | CloudFormationで対応していない機能のためのカスタムリソースを作成するフレームワーク。 |
| AwsCustomResource | AWSのAPIを呼び出すシンプルなカスタムリソースを作成するConstruct。 |
| Hot Swap | Lambda関数などの開発時に変更を高速に反映する機能。 |
| Context | CDKアプリケーションに外部から値を渡す仕組み。 |
| Stage | 複数のStackをまとめて環境の複製を容易にする仕組み。 |
| CDK Pipelines | CDKアプリケーションのCI/CDパイプラインを自動構築する機能。 |
| Construct Tree | Appをルートとして自由にConstructを構造化したもの。 |