AWS-CDKを用いたAmazon ECS構築

# 前提条件：

- VPC、サブネット、セキュリティグループは作成済み
- ECS,ECRを使用する際のIAMロールは作成済み
- 言語はtypescriptを使用
- ローカル環境で実行する
- クレデンシャルキーは発行済み
- Docker Desktopはインストール済み

# ローカル環境構築：

```ローカル
#プロジェクト用にディレクトリを作成
mkdir my-ecs-project

#移動
cd my-ecs-project

#CDKプロジェクトの初期化
cdk init app --language typescript

#モジュールのインストール
npm install @aws-cdk/aws-ec2 @aws-cdk/aws-ecs @aws-cdk/aws-ecr @aws-cdk/aws-iam @aws-cdk/aws-ecr-assets

```

# コーディング：

## **CDKスタックの定義**

```lib/my-ecs-project-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Stack, StackProps } from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as ecr from 'aws-cdk-lib/aws-ecr';
import { DockerImageAsset } from 'aws-cdk-lib/aws-ecr-assets';
import { Construct } from 'constructs';

export class MyEcsProjectStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // 既存のVPCを参照
    const vpc = ec2.Vpc.fromLookup(this, 'MyExistingVpc', {
      vpcId: 'vpc-XXXXXXXXXXX',  // 既存のVPCのIDを指定
    });

    // 特定のサブネットを参照
    const subnets = [
      ec2.Subnet.fromSubnetId(this, 'Subnet1', 'subnet-XXXXXXXXXXX'),
      // ec2.Subnet.fromSubnetId(this, 'Subnet2', 'subnet-XXXXXXXXXXXXX'), // 必要に応じて他のサブネットも追加
    ];

    // ECS クラスター作成
    const cluster = new ecs.Cluster(this, 'MyCluster', {
      vpc,
      clusterName: 'poc-Cluster',  // クラスター名を指定
    });

    // ECR リポジトリ作成
    const repository = new ecr.Repository(this, 'MyRepository', {
      repositoryName: 'poc-repository', // リポジトリ名を指定
    });
    
    // CDKスタックのデプロイ完了後に実行される処理を定義
    this.node.addDependency(repository);

    // Docker イメージのビルドとプッシュ
    const dockerImageAsset = new DockerImageAsset(this, 'MyDockerImage', {
      directory: './', // Dockerfile が存在するディレクトリ
    });

    // 既存の IAM ロールを使用
    const ecsTaskExecutionRole = iam.Role.fromRoleArn(this, 'EcsTaskExecutionRole', 'arn:aws:iam::533876055951:role/ec2-ssm-ecs-full');

    // 既存のセキュリティグループを参照
    const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(this, 'ExistingSecurityGroup', 'sg-XXXXXXXXXXXX');

    // ECS タスク定義作成
    const taskDefinition = new ecs.FargateTaskDefinition(this, 'MyTaskDefinition', {
      memoryLimitMiB: 512,
      cpu: 256,
      executionRole: ecsTaskExecutionRole,
      family: 'poc-TaskDefinitionFamily' // タスク定義ファミリー名を指定
    });

    // コンテナ追加
    const container = taskDefinition.addContainer('MyContainer', {
      image: ecs.ContainerImage.fromDockerImageAsset(dockerImageAsset),
      containerName: 'poc-Container', // コンテナ名を指定
      memoryLimitMiB: 512,
      cpu: 256,
    });

    container.addPortMappings({
      containerPort: 80,
      protocol: ecs.Protocol.TCP,
    });

    // ECS サービス作成
    const service = new ecs.FargateService(this, 'MyService', {
      cluster,
      taskDefinition,
      desiredCount: 1,
      serviceName: 'poc-EcsService', // サービス名を指定
      vpcSubnets: { subnets },
      securityGroups: [securityGroup], // 既存のセキュリティグループを指定
    });
  }
}
```

## **CDKアプリのエントリーポイントの修正**



```bin/my-ecs-project.ts
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { MyEcsProjectStack } from '../lib/my-ecs-project-stack';

const app = new cdk.App();
new MyEcsProjectStack(app, 'MyEcsProjectStack', {

  env: {
    account: 'XXXXXXXXXXXX', #AWSマネジメントコンソールの右上の12桁
    region: 'ap-northeast-1',　#東京リージョン
  },
  /* 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: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },

  /* Uncomment the next line if you know exactly what Account and Region you
   * want to deploy the stack to. */
  // env: { account: '123456789012', region: 'us-east-1' },

  /* For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html */
});
```

## **dockerファイルの作成：**

Node.js をベースイメージとして使用して、Node.js アプリケーションを実行するための手順を定義

Dockerfile

```docker
# ベースイメージとしてNode.jsを使用
FROM node:14

# 作業ディレクトリを設定
WORKDIR /app

# プロジェクトの依存関係をコピー
COPY package.json package-lock.json ./

# 依存関係のインストール
RUN npm install

# ソースコードをコピー
COPY . .

# アプリケーションのビルド
RUN npm run build

# ポート番号の公開
EXPOSE 3000

# アプリケーションの実行
CMD [ "npm", "start" ]
```

# デプロイ作業：

deployコマンド

```ローカルにて
cdk deploy
```

destroyコマンド

```ローカルにて
cdk destroy
```