はじめに
以前に書いた以下の記事の反響が良く、有難いことに多くの方に見ていただきました。
ただ、最新のマネージコンソールとの差異が出てきましたので最新版に書き直しました。ECSを学びたい人の最初の取っ掛かりになればと思います。ではECSのHello Worldをやっていきたいと思います。
事前学習 (ECSとは)
マネージコンソールで操作をする前に以下を理解してから始めましょう。
★コントロールプレーン & データプレーン
まずは、ここの理解が必要です。Fargateを調べていると "ECS"やら "EKS"が出てきて混乱してしまします。その部分の整理をまずはしましょう。コンテナを運用していくにあたり、「コントロールプレーン」と「データプレーン」の2つに大きくは分けることができます。コントロールプレーンとは、コンテナな管理をするところで、サッカーで言うと監督的なポジションです。このコントロールプレーンが指示を色々出してコンテナを動かしていきます。一方、データプレーンとは、実際にコンテナを動かす部分でサッカーで言うと選手になります。この監督が「ECS・EKS」で、選手が「EC2・Fargate」なのでその組み合わせ分(4つ)、パターンがあります。
-
コントロールプレーン [ECS][EKS]
- コンテナを管理する機能
- ECS/EKSの2種類
- オーケストレーションサービスと言う点でありコンテナを動かす実行基盤ではない
-
データプレーン [EC2][Fargate]
- 実際にコンテナを実行する環境
- EC2/Fargateの2種類
- これ単体だと動かない、ECS or EKSとセットで使う
- AWSがどこまで責任を負ってくれかでEC2/Fargateは違う
- EC2だと、OSやミドルウェアはユーザーが責任を負うが、Fargateはアプリのみ責任を負えば良い
★ECS (Elastic Container Service)
今回は、「ECS on Fargate」で構成を作るので 「ECS」 の理解をもう少し進めていきましょう。
- コンテナオーケストレーター
- コンテナ管理サービス (コンテナの実行、停止、管理ができます)
- EKSが持つような機能の多くはECSはない
- 秘密情報管理、時間指定での起動、起動成功保証などなど
- ただ、ECSで持っていないがAWSが持っているサービスで補えます
★AWS Fargate
ついでに、「ECS on Fargate」の「Fargate」のメリデメも確認してみたいと思います。
-
メリット
- ホストの管理が不要
- サーバーのスケーリング、パッチ適用、保護、管理にまつわる運用上のオーバーヘッドは発生しない
-
デメリット
- 価格
- 割り当てるCPU/メモリの制限やコンテナが起動するまでの時間が少し遅い
- コンテナにSSHできなかった → 2021/03 「ECS Exec」で解決された (別の章で詳しく書きます)
- GPU未対応 → 使用したいならデータプレーンをEC2へ
その他のコンテナサービス
※ Amazon ECS Anywhere
ECSのコントロールプレーンをAWSで動作させつつ、データプレーンを自身が管理するサーバー上で動作させることができる
※ AWS App Runner
インフラ周辺の構築を全てブラックボックス化しているから楽だが、色々隠蔽されているので触りにくいかも。
★ECSの主要要素
ECSがどのようなものか少しずつわかってきたと思うので、さらに深掘りしていきたいと思います。
(blackbeltから拝借)
以下の4つの名前を覚えましょう
1.タスク(Task)
- コンテナが動作するコンポーネント
- タスクは1つ以上のコンテナから構成
2.タスク定義(Task Definition)
- タスクを定義するテンプレート定義。JSONで記載
- 設定内容
- デプロイするコンテナイメージ
- タスクとコンテナに割り当てるリソース(CPU/メモリ)
- IAMロール
- CloudWatch Logsの出力先等
3.サービス(Service)
- 指定した数だけタスクを維持するスケジューラーで、オーケストレータの「コア機能」!!!
- サービス作成の際にはALBを紐付ける
- 何らかの処理でタスクが停止したら新しいタスクを起動
- 設定内容
- タスク数
- デプロイ定義
- ALB定義
- セキュリティグループ
- オートスケール設定
4.クラスター(Cluster)
- ECSサービスとタスクを実行する論理グループ
構成
以下のような構成になっております。
- コンテナアプリの作成
- ECS構築
簡単なコンテナアプリをFlaskで作って、それをFargateで動かす流れです
実装パート
1. コンテナアプリ作成
この章では、簡単なコンテナアプリを作成し、そこからDockerイメージの作成、そしてECRにPUSHするところまで行いたいと思います。
- ディレクトリ構成は以下のようになっています
ecs_project
|_ ecs-demo-app
|_app.py #アプリケーションコード
|_requirements.txt
|_Dockerfile
|_ venv #仮想環境
(1) アプリケーションの作成
- 今回は、Flaskを使用してアプリケーションを作成します
- Flaskの解説は割愛させていただきます。5000番ポートを使用しています
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000, debug=True)
- 上記ファイルが作成できたら、とりあえず実行してみてローカルで動くか確認してみて下さい。
(venv) tatsuya:20:58:14 ecs-demo-app >>> python app.py
* Serving Flask app 'app'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.40.42:5000
Press CTRL+C to quit
* Restarting with stat
* Debugger is active!
* Debugger PIN: 944-466-397
-
WARNINGは無視していただいて問題ないです
-
ブラウザに
http://127.0.0.1:5000
を入力し、Hello world
と表示されればOKです -
MacOSで試して以下のエラーが出るようでしたらこちらの記事を参考にして下さい
Address already in use
Port 5000 is in use by another program. Either identify and stop that program, or start the server with a different port.
On macOS, try disabling the 'AirPlay Receiver' service from System Preferences -> General -> AirDrop & Handoff.
- PythonライブラリをDockerイメージの中にも渡してあげる必要があるので、
requirements.txt
に使用しているライブラリを記載する必要があります - pip を使用しているのであれば、
freeze
コマンドを利用することにより簡単に作成できます
$ pip freeze > requirements.txt
- 以下が作成されます
blinker==1.8.1
click==8.1.7
flask==3.0.3
importlib-metadata==7.1.0
itsdangerous==2.2.0
Jinja2==3.1.3
MarkupSafe==2.1.5
werkzeug==3.0.2
zipp==3.18.1
- Dockerfileを作成します
- Pythonのベースイメージを使用して、Dockerイメージを構築していきます
- 流れをざっくり言うと、Pythonのベースイメージを選択し、作業用のフォルダappを作成して、そこに
requirements.txt
をコピーし、ライブラリインストールの実施。その後、他のファイルもイメージの中に持ち込み、最後に CMDでpythonスクリプトの実行
FROM python:3.10
WORKDIR /app
COPY requirements.txt ./
RUN pip install -r requirements.txt
COPY ./ ./
CMD ["python", "app.py"]
(2) イメージの作成
Dockerfileを使用してイメージ作成します
※ -t : 名前をつけています
$ docker build -t ecs-demo-app .
作成したDockerイメージの確認
$ docker images
コンテナを起動して接続できるか確認
$ docker run -p 5000:5000 ecs-demo-app
(コンテナ内に入るとき)
$ docker run -it -p 5000:5000 ecs-demo-app /bin/bash
せっかくなのでコマンドメモ
# イメージの一覧表示
$ docker images
# イメージの削除
$ docker rmi <IMAGE ID>
# 起動中のコンテナ確認
$ docker container ps
# 停止したコンテナも確認
$ docker container ps -a
(3) ECRにイメージをPUSH
- AWSのマネージドコンソールに戻り、まずはリポジトリ作成します
- 作成されたリポジトリを選択し、「プッシュコマンドの表示」をクリックするとコマンドが表示されます
$ aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/XXXXXXXX
$ docker tag ecs-demo-app:latest public.ecr.aws/XXXXXXXX/ecs-demo-app:latest
$ docker push public.ecr.aws/XXXXXXXX/ecs-demo-app:latest
2. ECS(Fargate)構築
以下の流れで行います
- VPC作成
- サブネット作成
- インターネットゲートウェイ作成 & VPCにアタッチ
- NATゲートウェイ作成
- ルートテーブル作成&サブネットに紐付け
- ALB作成
- ECS作成
- タスク定義作成
- クラスター作成
- サービス作成
- セキュリティグループ更新/確認
1. VPC作成
- 名前タグ : fargate-demo-vpc
- IPv4 CIDR ブロック : ☑️ IPv4 CIDRの手動手入力
- IPv4 CIDR: 10.0.0.0/16
- IPv6 CIDR ブロック:IPv6 CIDR ブロックなし
→ << VPCを作成 >>
2. サブネット作成
- 今回は2AZ構成で構築するのでサブネット4つ作成します
- パブリックサブネット 2, プライベートサブネット 2
VPC
- VPC ID : 先ほど作成したVPCを選択
サブネットの設定
- サブネット名 : fargate-demo-public-subnet01
- アベイラビリティーゾーン : アジアパシフィック(東京)/ap-northeast-1a
- IPv4 VPC CIDRブロック : 10.0.0.0/16
- IPv4 サブネット CIDRブロック : 10.0.0.0/24
※同じ操作で以下の4つのサブネットを作成
「fargate-demo-public-subnet01」 : 10.0.0.0/24, 1a
「fargate-demo-public-subnet02」 : 10.0.1.0/24, 1c
「fargate-demo-private-subnet01」 : 10.0.2.0/24, 1a
「fargate-demo-private-subnet02」 : 10.0.3.0/24, 1c
4つサブネットが作成されると以下のような表示になります
3.インターネットゲートウェイ作成 & VPCにアタッチ
インターネットゲートウェイを作成したらVPCにアタッチする必要があります
-
[インターネットゲートウェイの作成] をクリック
-
[名前タグ] : fargate-demo-igw
→ <<インターネットゲートウェイの作成>> -
インターネットゲートウェイを選択して [アクション] のプルダウンから [VPCにアタッチ] を選択し、先ほどのVPCにアタッチ
4.NATゲートウェイ作成
プライベートサブネットから外部に通信するにはNat Gatewayをパブリックサブネットに配置する必要があります
- 「NATゲートウェイを作成」をクリック
NATゲートウェイの設定
- 名前 : fargate-demo-natgw01
- サブネット : fargate-demo-public-subnet01 (※パブリックサブネットを選択)
- Elastic IP割り当てID : [Elastic IPを割り当て] をクリックして割り当てる
→<<作成>>
もうひとつNATゲートウェイを作成して、もうひとつのパブリックサブネット(fargate-demo-public-subnet02)にアタッチしてください。2つNatゲートウェイが作成されると以下のような画面になります。
5.ルートテーブル作成&サブネットに紐付け
サブネットの通信制御にルートテーブルを利用します。この設定を忘れがちで通信が上手くいかないことが多いので忘れないようにしましょう
- ルートテーブルを選択し、ひとつだけあるルートテーブルをパブリックサブネット用に編集します。
- ルートを [0.0.0.0/0] → 「igw-XXXX」 を追加して保存します。
- 保存ができたら、 [アクション] → [サブネットとの関連付けを編集] でパブリックサブネット2つ紐付けしてください
これにより、パブリックサブネットの通信は外に出ることができます
後、2つルートテーブルを新規で作成していきます。これはそれぞれのプライベートサブネットがそれぞれ同じAZのNATゲートウェイへ通信を流せるようにします
- [ルートテーブル設定]
- 名前 : rt-private-to-public-01
- VPC : (今回のVPCを選択)
ルートを編集
- ルートを [0.0.0.0/0] → 「nat-XXXX」 を追加して保存します
このルートテーブルをprivate subnet01の方に紐付けします。そうすることによりprivate subnetからinternetに出る通信はpublic subnetに設定してあるnat-gatewayを経由して外に通信が走ります。01が終わったら同じように02の方も設定をしてください。
6.ALB作成
まず初めに、外からアクセスをALBが受け付けるのでそれ用のセキュリティグループを作成しておきます。つまり、どのIPからも受け付ける設定です
- セキュリティグループを作成
- セキュリティグループ名 : fargate-demo-sg-for-alb
- 説明:fargate-demo-sg-for-alb
- VPC:fargate-vpc-demo
- インバウンドルール
- タイプ: HTTP
- ソース : Anywhere
また、ターゲットグループも事前に作成しておきます
- ターゲットタイプの選択:IPアドレス
- ターゲットグループ名: fargate-demo-tg
- プロトコル:ポート
- HTTP,5000
- IPアドレスタイプ:IPv4
- VPC:fargate-demo-vpc
- プロトコルバージョン:HTTP1
- IPアドレス
- ネットワーク : fargate-demo-vpc
- ポート : 5000
- 次に、Application Load Balancer (ALB)の作成を行います
- IGWからのリクエストを受けて、後ろのターゲットグループに流していきます。
- EC2のロードバランサーから「ロードバランサーの作成」をクリック
- [Application Load Balancer] を選択
基本的な設定
- ロードバランサー名 : fargate-demo-alb
- スキーム : インターネット向け
- IP アドレスタイプ : IPv4
- VPC : fargate-demo-vpc
- マッピング
- fargate-demo-public-subnet01
- fargate-demo-public-subnet02
- セキュリティグループ : fargate-demo-sg-for-alb
- リスナー
- プロトコル : HTTP
- ポート : 80
- デフォルトアクション : fargate-demo-tg
サービス統合で最適化
- こちらはECS特有と言うより一般的なサービス
- 必要に応じて有効化する
7. ECS作成
1. タスク定義作成
- タスクロール : タスクのコンテナがAWSサービスへのAPIリクエストすることの許可
- タスク実行ロール : コンテナエージェントがユーザーに代わってAWS APIリクエストを行うために使用
新しいタスク定義の作成
- タスク定義ファミリー : fargate-demo-task-definition
- 起動タイプ : AWS Fargate
- OS/アーキテクチャ : Linux/X86_64
- ネットワークモード : awsvpc
- タスクサイズ
- CPU :1 vCPU
- メモリ : 3GB
- タスクロール : なし
- タスク実行ロール : ecsTaskExecutionRole
※タスク実行ロール
Fargateを設定する際にAWSサービスへアクセスする必要がある場合、「タスク実行ロール」を作成することが必要。
(コンテナから他のS3、DynamoDBなどのサービスにアクセスする場合には「タスクロール」に権限を渡して実行する。)
- CloudWatchへのログ保存を設定
- コンテナイメージにECRのリポジトリを指定
- Secrets Managerのシークレット情報を環境変数に設定
「AmazonECSTaskExecutionRolePolicy」をアタッチして利用する方針で良いが、ユースケースによってはインラインポリシーを作成してアタッチする場合もある。
作成方法
- 「ecsTaskExecutionRole」に下記ポリシーを追加
- 「AmazonECSTaskExecutionRolePolicy」(管理ポリシー)
- 「CloudWatchFullAccess」(管理ポリシー)
- 「EcsSSMPolicy」(カスタマー管理 ※作成する)
EcsSSMPoliy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel"
],
"Resource": "*"
}
]
}
信頼関係
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
コンテナ-1
- コンテナの詳細
- 名前 : fagate-demo-container
- イメージURI : public.ecr.aws/XXXXXXXXX/ecs-demo-app
- 必須コンテナ : はい
- ポートマッピング
- コンテナポート : 5000
- プロトコル : TCP
- ポート名 : 5000
- アプリケーションプロトコル : HTTP
2. クラスター作成
「クラスターの作成」
クラスター設定
- クラスター名 : fargate-demo-cluster
- デフォルトの名前空間 -オプション- : fargate-demo-cluster
- インフラストラクチャ : ✔️ AWS Fargate
- モニタリング : ✔️ Container Insightsの使用
ECS Anywhere
- ECSでの一機能で、オンプレのサーバや仮想マシンなどの外部のインスタンスをECSで管理できる
- https://blog.serverworks.co.jp/ecs-anywhere-try
Container Insights
- コンテナワークロードに特化したモニタリング機能
- 従来のCloudWatchでは取得できなかったタスクやコンテナ単位のメトリクスが取得可能
- 参考 : ECS で Container Insights を使ってみた
3. サービス作成
- 環境
- 既存のクラスター : fargate-demo-cluster
- コンピューティングオプション : 起動タイプ
- 起動タイプ : FARGATE
- プラットフォームバーション : LATESET
- デプロイ設定
- アプリケーションタイプ : サービス
- タスク定義
- ファミリー : fargate-demo-task-definition
- リビジョン : 1
- サービス名 : fargate-demo-app-servicec
- サービスタイプ :レプリカ
- 必要なタスク数 : 2
- デプロイ不具合の検出
- ✔️ Amazon ECS デプロイサーキットブレーカーを使用する
- ✔️ 失敗時のロールバック
- ✔️ Amazon ECS デプロイサーキットブレーカーを使用する
ECS deployment circuit breaker
-
ECSサービスのデプロイで異常が発生した場合に、以前にデプロイが成功していたバージョンに自動でロールバックする機能
-
rolling updateデプロイタイプでサポートされる
-
もともとrolling updateのデプロイには失敗というステータスが無かったので、デプロイに異常があった場合にECSサービスがタスクの起動を繰り返すという問題があった
-
https://dev.classmethod.jp/articles/awssummit2021-ecs-deployment-circuit-breaker/
-
下記設定は任意
Service Connect
- マイクロサービスアーキテクチャなどの構成において、ECSサービス間の通信を簡単に設定できる
- ELB/ECS Service Discovery/AWS App Meshで実現可能だがこれらのサービスはいくつかの課題もあり、そのあたりの課題を上手くやってくれるのが、Service Connect
- https://dev.classmethod.jp/articles/try-amazon-ecs-service-connect/
ネットワーキング
- VPC : fargate-demo-vpc
- サブネット
- fargate-demo-private-subnet01
- fargate-demo-private-subnet02
- セキュリティグループ
- 新しいセキュリティグループ作成
- セキュリティグループ名
- セキュリティグループの説明
- インバウンドルール
- HTTP, TCP, 80, Source group, [sg:ALBのsg]
- カスタムTCP,TCP,5000,Source group, [sg:ALBのsg]
- パブリックIP : OFF
ロードバランシング
- ロードバランサの種類 : Application Load Balancer
- コンテナ : farrgate-demo-container 5000:5000
- Application Load Balancer : 既存のロードバランサー
- ロードバランサー : fargate-demo-alb
- ヘルスチェックの猶予期間 : 5
- リスナー : 既存のリスナーを選択
- 80:HTTP
- ターゲットグループ
- 既存のターゲットグループを使用
- ターゲットグループ名 : fargate-demo-tg
- ヘルスチェックパス : /
- ヘルスチェックプロトコル : HTTP
- ブラウザにALBのDNS名を利用してアクセスしてみて、コンテナの中身 「Hello World」が表示されれば完了です
さらに取り組む方は、、、
これをさらにバージョンアップさせていって欲しいです。
証明書の追加でhttpsでアクセスできるようにしたり、今回ECRをパブリックにしていたのでプライベートにしてVPCエンドポイント経由でアクセスしたり、ドメイン購入してRoute53で紐付けしたりと。今回はボリューミーになるので割愛させていただきました。
終わりに
以前書いた記事のupdateをしてみました。AWSのマネコンは頻繁に変更されるのでちょっと困る気もしますが便利な機能も追加されていることが多いのでありがたいですね。