【初心者向け】ECS on EC2 の構築チュートリアル

# 1. はじめに
AWS の ECS on EC2 は、コンテナ化されたアプリケーションを実行する方法の一つです。この記事では、ECS on EC2 の基本的な構築方法を紹介し、よくあるトラブルとその解決方法について説明します。

## 1-1. この記事でわかること
- ECS on EC2 の構築方法
- よくあるトラブルとその解決方法

## 1-2. この記事の対象者
- ECS on EC2 を初めて構築する人
- ECS on EC2 のトラブルに直面している人
- AWS の基礎知識を有している人
- Amazon ECS の基礎知識を有している人

※　ECS の基礎知識については[こちら](https://o2mamiblog.com/aws-ecs-beginner/)の記事で確認できます

## 1-3. この記事の大まかな流れ
1. ECS on EC2 の選択理由
2. ECS on EC2 の構築方法
3. よくあるトラブルとその解決方法

# 2. なぜ「ECS on EC2」を選ぶのか
本章では、「ECS on EC2」を選択するメリットについて説明します。
ECS（Elastic Container Service）は、AWS が提供するコンテナオーケストレーションサービスであり、コンテナの実行環境として **EC2** と **Fargate** の2つの選択肢があります。実行環境として **EC2** を選択するメリットには、以下のような点が挙げられます。

- **高いカスタマイズ性**
EC2 インスタンスのタイプや数を自由に選択できるため、システムに最適なリソースを構築できます。
- **コスト効率の向上**
長期的または大規模な利用においては、Fargate に比べてコスト効率が高くなる傾向にあります。特に、リザーブドインスタンスやスポットインスタンスを利用することでコストを抑えることが可能です。

これらのメリットから、コンテナの実行環境として EC2 を使用するケースがあります。

※　EC2 と Fargate のより詳細な比較やメリット・デメリットについては[こちら](https://envader.plus/article/441)の記事で確認できます

# 3. ECS on EC2 の構築
本章では、ECS on EC2 環境をゼロから構築する手順を紹介します。構築の概要から説明を始め、事前準備、ECS クラスターの作成、タスク定義の作成、サービスの作成、最後に動作確認まで順を追って解説します。

## 3-1. 構築の概要
この記事では、以下の構成図のような ECS on EC2 を構築します。

![Qiita構成図.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/c383abff-d487-36ca-484c-db3e4c012994.png)

ECS on EC2 をパブリックサブネットに構築し、コンテナは HTTP の 80 番ポートで接続できるように設定します。コンテナには、Docker の公式イメージである httpd を使用し、Apache HTTP Server を構築します。

※　httpd イメージの詳細は[こちら](https://www.docker.com/ja-jp/blog/how-to-use-the-apache-httpd-docker-official-image/)の記事で確認できます

## 3-2. 事前準備
ECS on EC2 を構築する前に、以下の事前準備を完了してください。

### 3-2-1. ユーザに必要な IAM 権限を付与する
コンソールが必要な IAM ロールを作成できるようにするためには、ユーザーがサービスロールを作成するための IAM 権限を持っている必要があります。詳細については[こちら](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_create_for-service.html)を確認してください。

**例：AdministratorAccess ポリシー**
AdministratorAccess ポリシーは、IAM ロールを作成するための権限を含む管理者権限を提供します。詳細については[こちら](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/get-set-up-for-amazon-ecs.html)を確認してください。

### 3-2-2. リージョンを設定する
東京（ap-notheast-1）を使用します。

### 3-2-3. VPC および関連するネットワーク設定を行う
「3-1. 構築の概要」で示した構成図を満たすように、VPC、パブリックサブネット、ルートテーブル、インターネットゲートウェイを作成してください。

※　VPC 関連の作成方法は[こちら](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/create-vpc.html)の記事で確認できます

### 3-2-5. キーペアを作成する
EC2 インスタンスを使用する場合にのみキーペアが必要です。キーペアにより、EC2 インスタンスに SSH でログインできます。

※　キーペアの作成方法は[こちら](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/create-key-pairs.html)の記事で確認できます

## 3-3. クラスターの作成
Amazon Elastic Container Service > クラスター > クラスターの作成 を開きます。

### 3-3-1. クラスターの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/328e7846-352d-7b3e-b213-57ade7fffd75.png)
任意のクラスター名を入力します。

### 3-3-2. インフラストラクチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/9b7b56e6-d00d-ad09-e4b1-afd422bc86aa.png)
ここでは、Auto Scaling グループの設定を行います。Auto Scaling グループに基づいて自動的に起動されたインスタンスは、コンテナが実行される環境を提供するコンテナインスタンスとして、ECS クラスターへ自動的に登録されます。このプロセスにより、インスタンスがクラスターの一部として自動的に認識され、コンテナの実行が可能となります。

**【設定項目】**
- **コンテナインスタンス**
「Amazon EC2 インスタンス」を選択します。
- **Auto Scaling グループ**
「新しい ASG の作成」を選択します。
ECS on EC2 では、インスタンスのスケーリング管理に Auto Scaling グループの設定が必要です。Fargate では自動的にスケーリングされますが、EC2 では手動で設定する必要があります。
- **コンテナインスタンス Amazon マシンイメージ（AMI）**
「Amazon Linux 2」を選択します。
- **EC2インスタンスタイプ**
「t2.micro」を選択します。
- **EC2 インスタンスロール**
「新しいロールの作成」を選択します。
EC2 インスタンスロールとは、EC2 インスタンスが ECS と通信するための権限を持つロールです。実行環境が Fargate の場合はインフラ管理が自動で行われ、ロールも自動的に割り当てられますが、EC2 の場合は手動で設定する必要があります。
- **必要な容量**
「最小値：1、最大値：1」に設定します。ここでは、Auto Scaling グループで起動するインスタンスの数が指定できます。今回は自動でスケーリングさせないためにこのような設定値とします。
:::note warn
最小値を 0 にすると、コンテナインスタンスが自動で登録されない可能性があります。詳しくは「4-1-3. エラー①：コンテナインスタンスが見つからない」で解説します。
:::
- **SSH キーペア**
事前に作成したキーペアを選択し、コンテナインスタンスへのログインを可能にします。

### 3-3-3. Amazon EC2 インスタンスのネットワーク設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/a30d02bd-6f7f-eb4d-e01e-5609187bf880.png)
ここでは、VPC、サブネット、セキュリティグループなどのネットワーク設定を行います。

**【設定項目】**
- **VPC**
事前作成した VPC を選択します。
- **サブネット**
事前に作成したパブリックサブネットを選択します。
- **セキュリティグループ**
「新しいセキュリティグループの作成」を選択します。任意のセキュリティグループ名とインバウンドルールを設定します。
:::note info
すべての IP アドレスから HTTP（ポート80番）でアクセスを許可します。
- タイプ：HTTP
- プロトコル：TCP
- ポート範囲：80
- ソース：Anywhere 0.0.0.0/0, ::/0
:::
- **パブリック IP の自動割り当て**
「サブネットの設定を使用」を選択します。これにより、パブリックサブネットの場合のみパブリック IP が自動的に割り当てられ、インターネットからコンテナインスタンスにアクセス可能となります。

以降はデフォルト設定のままです。作成ボタンをクリックするとクラスターが作成されます。

## 3-4. タスク定義の作成
Amazon Elastic Container Service > タスク定義 > 新しいタスク定義の作成 > 新しいタスク定義の作成 を開きます。

### 3-4-1. タスク定義の設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/a0737dcb-1c62-edf0-0913-56dd635c51ee.png)
任意のタスク定義名を入力します。

### 3-4-2. インフラストラクチャの要件
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/eeb4108e-e25a-0220-3d61-9741e8da8440.png)
ここでは、タスクのインフラストラクチャ要件の設定を行います。

**【設定項目】**
- **起動タイプ**
「Amazon EC2 インスタンス」を選択します。
- **オペレーティングシステム/アーキテクチャ**
「Linux/x86_64」を選択します。クラスター作成で設定した「コンテナインスタンス Amazon マシンイメージ（AMI）」に適したオペレーティングシステムやアーキテクチャを選択する必要があります。
:::note info
使用している EC2 の AMI 情報から適切なオペレーティングシステムやアーキテクチャを確認できます。コンソール上から EC2 > インスタンス > [使用しているインスタンス] > AMI ID で確認できます。
:::
- **ネットワークモード**
「bridge」を選択します。ネットワークモードは、コンテナがどのようにネットワーク接続を行うかを決定する設定です。bridge モードでは、コンテナが EC2 インスタンスの仮想ネットワークインターフェースを利用し、独自の IP アドレスを持たずに、ホストや他のコンテナと通信します。
:::note warn
ネットワークモードが誤って設定されていると、コンテナ同士の通信や外部接続に失敗することがあります。詳しくは「4-2. コンテナにアクセスできない問題」で解説します。
:::

※　ネットワークモードの詳細は[こちら](https://zenn.dev/fdnsy/articles/43b7f4d745ed1f)の記事で確認できます
- **タスクサイズ**
「CPU：1vCPU, メモリ：0.9GB」に設定します。ここでは、タスクに割り当てる CPU とメモリの量を設定できます。
:::note warn
コンテナが正常に起動する範囲で、EC2インスタンスのリソースを超えないように設定する必要があります。詳しくは「4-1-4. エラー②：コンテナインスタンスのリソース不足」で解説します。
:::
- **タスク実行ロール**
「新しいロールの作成」を選択します。これは、タスクが AWS リソースへアクセスするために必要な権限を定義する IAM ロールです。

### 3-4-3. コンテナ - 1
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/e80b5de1-7ca8-608d-b193-29afcbf040cf.png)
ここでは、立ち上げるコンテナの設定を行います。

**【設定項目】**
- **コンテナの詳細**
イメージ URI は「httpd」と入力します。今回は Docker の公式イメージである httpd を使用します。
- **ポートマッピング**
ホストポートに「80」を入力します。通信に必要なポートを設定できます。
- **リソース割り当て制限**
今回は未設定ですが、コンテナに割り当てられるリソース量を設定できます。

※　リソース割り当て制限の詳細は[こちら](https://blog.serverworks.co.jp/2023/10/24/104221#%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E5%89%B2%E3%82%8A%E5%BD%93%E3%81%A6%E5%88%B6%E9%99%90)の記事で確認できます
- **ログ収集**
今回はログ収集を行わないためチェックボックスを外します。ここでは、CloudWatch Logs を使用してコンテナログを収集するかの設定を行います。

以降はデフォルト設定のままです。作成ボタンをクリックするとタスク定義が作成されます。

## 3-5. サービスの作成
Amazon Elastic Container Service > クラスター > [作成したクラスター名] > サービス > 作成 を開きます。

### 3-5-1. 環境
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/6c46be80-1a49-f464-ec3b-2e78b4fb135b.png)
ここでは、サービスを配置する環境の設定を行います。

**【設定項目】**
- **コンピューティングオプション**
「起動タイプ」として「EC2」を選択します。これにより、クラスターに登録された EC2 インスタンス上でタスクが実行されます。また、キャパシティプロバイダー戦略を選択すると、EC2 や Fargate など複数のキャパシティプロバイダーに対して、タスクをどのように分散させるかを設定できます。

### 3-5-2. デプロイ設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/af682c81-9050-61d5-0cc1-1e58db99d818.png)
ここでは、サービスをデプロイ（実行環境へ配置すること）する方法を設定します。

**【設定項目】**
- **アプリケーションタイプ**
デフォルトの「サービス」を設定します。ここでは、タスクの実行方法を決定します。サービスでは、指定した数のタスクを常に実行し、必要な数が維持されるようにします。タスクでは、実行が終了したら自動的に停止する一時的なタスクを起動します。
- **ファミリー**
作成したタスク定義を選択します。
- **リビジョン**
「最新」と記載されているものを選択します。リビジョンとはタスク定義のバージョンを指します。
- **サービス名**
サービス名を入力します。
- **サービスタイプ**
デフォルトの「レプリカ」を設定します。サービスタイプは、タスクの実行と監視の戦略を決定します。レプリカでは、クラスター内で指定されたタスク数を維持します。デーモンでは、コンテナインスタンス毎に1つのタスクを配置します。
- **必要なタスク**
デフォルトの「1」を設定します。起動するタスク数を指定できます。

以降はデフォルト設定のままです。作成ボタンをクリックするとサービスがデプロイされます。

## 3-6. 動作確認
Amazon Elastic Container Service > クラスター > [作成したクラスター名] > サービス > [作成したサービス名] > タスク > [起動したタスク名] > 設定 を開きます。パブリック IP のオープンアドレスをクリックするとコンテナにアクセスできます。以下のような画面が表示されたら成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/487ec2e1-1edf-adf3-d5dd-28cf4722c58a.png)

:::note alert
使用したリソースには料金が発生するため、構築後はリソースを停止または削除して、無駄なコストが発生しないようにしましょう。

※　関連リソースの削除方法は[こちら](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/getting-started-ecs-ec2-v2.html#getting-started-ec2-cleanup-v2)の記事で確認できます
:::

# 4. よくあるトラブル
ECS on EC2 構築時に発生しやすいトラブルとその解決方法を紹介します。よくあるトラブルに対して、どのように対処するかを具体例とともに説明します。

## 4-1. サービスが作成できない問題
サービスをデプロイしようとしたときに、以下のようなエラーメッセージが表示されて失敗することがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/64afae40-e818-01b0-aab6-c73da321d462.png)

エラーメッセージに**ECS Deployment Circuit Breaker がトリガーされた**と記載されています。

### 4-1-1. デプロイサーキットブレイカーとは
デプロイサーキットブレイカーは、サービスのデプロイが失敗した場合に自動でロールバックを行い、リソースの無駄な消費を防ぐ機能です。これにより、デプロイが無限に続く事態を防げますが、一方で失敗の詳細な情報を確認できなくなる場合があります。

### 4-1-2. デプロイサーキットブレイカーを無効化する方法
デプロイサーキットブレイカーを無効化することで、エラーメッセージを確認することができます。サービス作成時に「デプロイ不具合の検出」のチェックボックスを外してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/78673fa2-ed16-9a7a-e918-fdf71f4f1d22.png)

無効化することで、デプロイに失敗した場合でも、エラーの詳細なイベントメッセージを確認できます。 Amazon Elastic Container Service > クラスター > [作成したクラスター名] > サービス > [作成したサービス名] > イベント で確認することができます。

### 4-1-3. エラー①：コンテナインスタンスが見つからない
**【エラーメッセージ】**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/312a956d-fa56-da8c-e2ed-c46d106bc475.png)
**クラスター内に必要な条件を満たすコンテナインスタンスが見つからない**という内容になっています。

**【原因】**
原因は、**クラスターにコンテナインスタンスが登録されていない**ことです。
本来は、クラスター作成時に Auto Scaling グループが作成され、インスタンスが自動で起動してコンテナインスタンスに登録されます。しかし、今回は Auto Scaling グループの希望するキャパシティが 0 だったため、インスタンスが起動せず、コンテナインスタンスが登録されませんでした。

:::note info
クラスターに登録されているコンテナインスタンスは、Amazon Elastic Container Service > クラスター > [作成したクラスター名] > インフラストラクチャ で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/7d586bb8-e94c-0574-e758-55b023a50d8d.png)
:::

:::note info
Auto Scaling グループの希望するキャパシティは、EC2 > Auto Scaling グループ > [グループ名] で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/974c9aab-27fd-1330-1b9c-5da13810ae48.png)
:::

**【解決策】**
- Auto Scaling グループの希望するキャパシティを 1 以上に変更する
- クラスター作成時に必要な容量の項目の最小値を 1 以上に設定する

### 4-1-4. エラー②：コンテナインスタンスのリソース不足
**【エラーメッセージ】**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/a8d12cd1-50d4-9edb-7a94-ff2ba7cca383.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/82ca8778-7d0b-01ac-cf06-d6c6c82ff454.png)

1つ目は**CPU が不足している**、2つ目は**メモリが不足している**という内容になっています。

**【原因】**
原因は、**作成しようとしたタスクのサイズがコンテナインスタンスのリソースを超えていた**ことです。
今回使用したコンテナインスタンス（インスタンスタイプ：t2.micro, CPU：1vCPU, メモリ：1GiB）に対し、設定したタスクサイズが CPU：2vCPU、メモリ：2GB であり、リソース不足のためタスクが作成されませんでした。

:::note info
タスクサイズは、Amazon Elastic Container Service > タスク定義 > [作成したタスク定義] > [リビジョン] > コンテナ で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/274a04a3-fcc4-ad01-40d8-5955c8edaed6.png)
:::

**【解決策】**
- タスク定義で CPU やメモリの値を下げる
- コンテナインスタンスのスケールアップ

## 4-2. コンテナにアクセスできない問題
**【エラーメッセージ】**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/3838ae1c-1643-bfb5-4b2a-127f509b9e33.png)

**パブリック IP での接続が失敗した**という内容になっています。

**【原因】**
原因は、**タスク定義のネットワークモードで awsvpc モードを使用していた**ことです。
awsvpc モードでは、コンテナごとに個別の仮想ネットワークインターフェース（ENI）が割り当てられ、EC2 インスタンスの ENI とは別にコンテナ専用の ENI が生成されます。この場合、コンテナ用の ENI にパブリック IP が割り当てられていないと、インターネットからアクセスできません。

:::note info
ネットワークモードは、コンテナがどのようにネットワーク接続を行うかを決定する設定です。作成された ENI は、EC2 > インスタンス > [インスタンス名] > ネットワーキング で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3933262/7827f839-8ba4-c53b-ec0a-fb472ecfe6f2.png)

※　ネットワークモードの詳細は[こちら](https://zenn.dev/fdnsy/articles/43b7f4d745ed1f)の記事で確認できます
:::

**【解決策】**
- bridge モードを使用する

bridge モードでは、コンテナは EC2 インスタンス用の ENI を共有し、EC2 インスタンスの IP アドレスを使って通信できるようになります。これにより、EC2 インスタンスのパブリック IP でコンテナへアクセスできるようになります。

# 5. おわりに
この記事では、ECS on EC2 の構築方法とよくあるトラブル、そしてその解決方法について解説しました。ECS on EC2 の構築の手助けになれば幸いです。次の学習ステップとしては、「ECS on EC2 に ALB を追加する」や「ECS on Fargate の構築」などを試してみることをおすすめします。

# 6. 参考資料
- [【AWS初学者向け・図解】Amazon ECSとは？現役エンジニアがわかりやすく解説](https://o2mamiblog.com/aws-ecs-beginner/)
- [どっちを選ぶ？AWS ECS on EC2とFargateの違い](https://envader.plus/article/441)
- [Apache httpd Docker Official Image の使い方](https://www.docker.com/ja-jp/blog/how-to-use-the-apache-httpd-docker-official-image/)
- [Amazon ECS を使用するようにセットアップする](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/get-set-up-for-amazon-ecs.html)
- [AWS サービスにアクセス許可を委任するロールを作成する](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_create_for-service.html)
- [「VPC を作成する」](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/create-vpc.html)
- [Amazon EC2 インスタンスのキーペアを作成する](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/create-key-pairs.html)
- [ECSのネットワークモードを調べてみた](https://zenn.dev/fdnsy/articles/43b7f4d745ed1f)
- [【初心者向け】Amazon ECSのパラメータ一覧](https://blog.serverworks.co.jp/2023/10/24/104221#%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E5%89%B2%E3%82%8A%E5%BD%93%E3%81%A6%E5%88%B6%E9%99%90)
- [Amazon ECS deployment circuit breaker のご紹介](https://aws.amazon.com/jp/blogs/news/announcing-amazon-ecs-deployment-circuit-breaker-jp/)
- [デプロイサーキットブレーカーを無効な状態で ECS サービスを新規作成する方法を教えてください](https://dev.classmethod.jp/articles/tsnote-ecs-deployment-circuit-breaker-created-in-disabled-state/)
- [AWS初心者がECSをEC2起動タイプでデプロイするときに苦労した話](https://techblog.ap-com.co.jp/entry/2024/07/23/113344)
- [パブリックサブネットで起動したECS(EC2 + awsvpc)でコンテナがインターネット接続出来ない点について](https://dev.classmethod.jp/articles/publicsubnet_ecs_ec2_awsvpc_internet_connection/)