ECSをSIで扱う際に知る必要のある設計、構築、運用までの知識を体系化。
SIでECSを扱う際に必要な情報一式を集約。
PJ 役割分担と本記事の前提
前提:複数の役割を兼任する場合もあるが、以下で人物定義する。
- アプリケーション開発者
AWS上で稼動するシステムのアプリケーションを開発する人を指す。ざっくりなくくりとしては、ソースコードを扱う人。 - システムの管理者
システムを監視、運用する人を指す。一般的には、AWSを所有する顧客自身になるケースが多い。 - インフラ(AWSサービス)担当者
AWSのサービスを構築し、アプリケーションが動作するための基盤(サーバやコンテナなど)を構築するする人を指す。本記事は、この担当者目線での記事となる。
以下の役割分担を想定し、本記事はインフラ担当者向けに整理している。
ECS とは?
- コンテナを統合管理するオーケストレーター。
- オーケストレーター:
- 複数コンテナを統合管理することができる。(実際には、各コンテナホスト上のAgentに対して、オーケストレーターから指示を出す。)
- コンテナの配置や、稼動タスク数の維持、コンテナ間通信の管理などを行う。
- オーケストレーター:
コンテナ実行環境(データプレーン)
- コンテナ実行環境としてDockerが稼動するEC2または、サーバレスのfargateを選択することができる。(実行環境もECSの一部のようでもあるが、下図のように実行環境は、ECSとは別サービスとして説明されている文献が多い)
以下、[AWS Black Belt Online Seminar] CON201 ECS入門より。
ECSの用語について
以下、[AWS Black Belt Online Seminar] Amazon Elastic Container Service より。
- クラスター(cluster)
- サービスの集合を指す。
- サービスを稼動する実行環境を定義する。(fargate、EC2など)
- サービス (service)
- ELBとタスク(コンテナ)のセット。アプリケーションの機能(プロセス)を提供するために可用性や拡張性を備えたインフラ一式を指す。(ELBは必須ではない。)
- 稼動するタスクの元になるタスク定義、タスク数、オートスケーリング有無を指定する。
- タスク(task)
- タスク定義に基づいて起動するコンテナ群を指す。※タスク内のコンテナは同一ホストで実行される。
- タスク定義(task definitions)
- コンテナのイメージURI、コンテナに割り当てるリソース、環境変数などを指定する。
補足事項
- サービスにおけるELBの必要性について
- 必須ではない。タスク数の維持はロードバランサの役割ではなく、ECS サービススケジューラが行う。
ECSの設計
タスク定義に含めるコンテナ数について
1つのタスクの中には、複数のコンテナを稼動することも可能だが、コンテナのスケールアウト、スケールインはタスクの単位で行われるため、複数コンテナを含めた場合にはすべてのコンテナが同時に増減する動作となり、柔軟なスケールができない。
また、タスク内のコンテナ障害時には、デフォルトで同一タスク内の残りのコンテナを停止して、新たにタスクが作成される(タスク数が維持される)動作となるため、同一タスク内に複数コンテナを格納すると、システムによっては可用性が下がる場合がある。
上記を踏まえると、タスク内には基本コンテナを1つ。または、1つのコンテナのサイドカー構成が良いと考える。ただし、同一コンテナ内であれば、コンテナ間通信が可能なため、簡易な評価目的などであれば、同一タスク定義に複数コンテナを含める方がシンプルな構成となるメリットがある。
注意事項)CodeDeployによるBlue/Greenデプロイを使用する場合の制約事項
- Blue/Greenデプロイを使用する場合は、サービスに紐づくターゲットグループが1つである必要がある。そのため、1つのサービスに複数のポートで受信する構成は不可能。つまり、1つのタスク定義の中に複数コンテナを含めて、そのコンテナがそれぞれ異なるポートで通信を受ける必要がある場合には、Blue/Greenデプロイが不可能。(ローリングアップデートであれば、可能)
- 以下のような構成をとり、且つBlue/Greenデプロイを使用する場合には、バックエンドからフロントエンドへの通信はインターネットを経由する方法しかない。仮にバックエンドからフロントエンドへ内部通信を行うには、フロントコンテナのサービスに対して複数のターゲットグループを割り当てる必要があるが、Blue/Greenデプロイでは、サービスに割り当てるターゲットグループが1つのみという制約があるため。
構成例:
「外部ALB」 -「フロントエンドコンテナのサービス」-「内部 ALB」-「バックエンドコンテナのサービス」
パラメータ前提
ECSのパラメータは多岐にわたるため、以下の前提でパラメータサンプルを記載する。
- Fargateを使用
- Blue/Greenデプロイ
- サービス1つ。
- サイドカー構成(fluentbitを利用、ビルドによるカスタマイズ含む)
クラスター設計
項目 | 設定例 | 決め方 | 備考 |
---|---|---|---|
クラスター名 | [$system]-[$env]-cluster | 任意 | |
インフラストラクチャ | Fargate | アプリ要件 | |
Container Insights | 有効 | サービスの監視要件 パフォーマンス監視用として取得を推奨。 |
タスク定義
実際のPJでは、環境変数が100個以上必要な場合もある。タスク定義全体にアプリ要件で確定する部分が多いため、アプリケーション担当が分かれている場合には、アプリケーション担当にてタスク定義を設計する仕切りを推奨。
また、タスク定義はJSONでも作成、編集が可能でありJSONの方が保守性がよい。
参考:ECSタスク定義をコンソールから作って後悔した後、コード管理するため最速でJSON登録可能にする超愚直な方法
項目 | 設定例 | 決め方 | 備考 |
---|---|---|---|
起動タイプの互換性 | AWS Fargate | サービスの保守性要件 | |
タスクロール | [$system]-[{$env}-frontapp-task-role | 名称は任意。 ロールに割り当てる権限は、コンテナから他のAWSサービスにアクセスする場合に、該当のポリシーを設定する。 | |
ネットワークモード | awsvpc | FARGATEの場合はawsvpc固定 | |
オペレーティングシステム/アーキテクチャ | Linux | アプリ要件 | |
タスク実行ロール | [$system]-[{$env}-ecs-task-ex-role | アプリ要件(コンテナ間の通信要件) | コンテナ実行に必須(ECS共通ロール想定) |
タスクメモリ | 16GB | アプリ要件 | |
タスクCPU | 2vCPU | アプリ要件 | |
コンテナ | [$system]-[{$env}-frontapp-cont, log_router | コンテナ名称は任意 | log_routerは、FireLensによるfluentbitのデフォルトコンテナ名。 |
App Mesh 統合の有効化 | 無効 | アプリ要件(サービス間の通信要件) | |
プロキシ設定 | 無効 | アプリ要件 | |
FireLens の統合を有効にする | 有効 | ログ保管要件(アプリ要件) ログを整形せず、全てCloudWatch Logsや、splunkに転送する。以外のケースでは有効にする。 | |
タイプ | fluentbit | Firelensを使用する場合に、fluentbitかfluentdを選択可能。 軽量なfluentbitを推奨。 | |
イメージ | [$system]-[{$env}-frontapp-fluentbit-repo:latest のURI | fluentbitのカスタマイズを行う場合には、該当のURI(fluentbitのイメージを格納したECRのリポジトリ)を指定。 カスタマイズしない場合は、デフォルトでイメージのURIが入力される。 | fluentbitのカスタマイズが必要なケースはこちらを参照。 |
コンテナ (frontapp)
項目 | 設定例 | 決め方 | 備考 |
---|---|---|---|
コンテナ名 | frontapp | 任意の名称 | |
イメージURI | [$system]-[$env]-frontapp-repo:[$タグ] のURI | 稼動するコンテナのイメージのURI | |
メモリ制限(MB) | ー | アプリ要件 | |
ポートマッピング | ホストポート : 8080 プロトコル : TCP コンテナポート : 8080 | アプリ要件 | |
ヘルスチェック コマンド | アプリごとに異なる。 | アプリ要件 | 動作はこちらを参照。 |
環境変数 | アプリごとに異なる。 | アプリ要件 コンテナのDockerfileで定義された環境変数に応じて設定。 | |
コンテナタイムアウト | ー | 1つのタスクに複数コンテナを使用しており、依存関係がある場合に使用を検討。 それ以外のケースでは不要。 | 参考:ECS で依存関係を設定したタスクのヘルスステータスがUNHEALTHYのまま終了しないときの対処方法 |
ネットワーク設定 | ー | アプリ要件 ネットワークを無効化する場合などに設定。 | |
ログドライバー | awsfirelens | ログ保管要件(アプリ要件) ログを整形せず、全てCloudWatch Logsや、splunkに転送する。以外のケースではawsfirelensを使用。 | |
ストレージ(ソースボリューム) | ー | アプリ要件 コンテナにEFSマウントが必要な場合に指定する。 | |
ストレージ(コンテナパス) | ー | アプリ要件 コンテナにEFSマウントが必要な場合に指定する。コンテナのマウント先。 | |
リソースの制限(NOFILE) | ソフト制限:10240, ハード制限:10240 | アプリ要件 |
コンテナ (log_router)
項目 | 設定例 | 決め方 | 備考 |
---|---|---|---|
コンテナ名 | log_router | 任意の名称 | |
イメージURI | [$system]-[$env]-frontapp-fluentbit-repo:[$タグ]のURI | 稼動するコンテナのイメージのURI カスタマイズしない場合は、デフォルトで設定される。 | |
メモリ制限(MB) | ー | アプリ要件 | |
ポートマッピング | ー | ログルータはポートを使用しない。 | |
ヘルスチェックコマンド | アプリごとに異なる。 | アプリ要件 | |
環境変数 | アプリごとに異なる。 | アプリ要件 | |
コンテナタイムアウト | ー | 1つのタスクに複数コンテナを使用しており、依存関係がある場合に使用を検討。 それ以外のケースでは不要。 | 参考:ECS で依存関係を設定したタスクのヘルスステータスがUNHEALTHYのまま終了しないときの対処方法 |
ネットワーク設定 | ー | アプリ要件 ネットワークを無効化する場合などに設定。 | |
ログドライバー | awslogs | サービスの保守性要件 fluentbit自体のログの転送先。障害調査のため、取得を推奨。 | |
ログドライバーキー awslogs-group | /ecs/[$system-[$env]/frontapp/fluent-bit | 任意のロググループの名称 | |
ログドライバーキー awslogs-region | ap-northeast-1 | 任意のリージョン | |
ログドライバーキー awslogs-stream-prefix | firelens | 任意の名称 | |
firelensConfiguration/config-file-type | file | アプリ要件 fluentbitをカスタマイズする場合に、extra.confの場所を指定する場合に指定。 | |
firelensConfiguration/config-file-value | /fluent-bit/etc/extra.conf | アプリ要件、サービスの保守性要件 fluentbitをカスタマイズする場合に、extra.confの場所を指定する場合に指定。 |
サービス設計
[$system]-[$env]-frontapp-service
項目 | 設定例 | 決め方 | 備考 |
---|---|---|---|
オペレーティングシステムファミリー | Linux | アプリ要件 | |
タスク定義 | [$system]-[$env]-frontapp-family | 起動するタスク定義を指定 | |
プラットフォームのバージョン | 1.4.0 | アプリ要件 | |
クラスター | [$system]-[$env]-cluster | サービスを稼動するクラスタ | |
サービス名 | [$system]-[$env]-frontapp-service | 任意 | |
サービスタイプ | REPLICA | FARGATEの場合はREPLICA固定 | |
タスクの数 | 2 | サービスの性能要件 | |
デプロイメントタイプ | Blue/Green デプロイメント(CodeDeploy を使用) | サービスの可用性要件(保守性要件) | |
デプロイメント設定 | CodeDeployDefault:ECSAllAtOnece | サービスの可用性要件 | |
VPC | [$system]-[$env]-vpc | サービスの通信要件 | |
サブネット | [$system]-[$env]-private-subnet01a, [$system]-[$env]-private-subnet01c | サービスの通信要件 | |
セキュリティグループ | [$system]-[$env]-frontapp_sg | サービスの通信要件 | |
パブリックIP | 無効 | アプリ要件 | |
ヘルスチェックの猶予期間 | 300秒 | アプリ要件 | |
ロードバランサー | [$system]-[$env]-frontapp-alb | 該当サービスにトラフィックを転送するALBを指定。 | |
プロダクションリスナーポート | 443:HTTPS | ALBの受信ポートを指定。 | ALBのテスト用受信ポートであり、ECSサービス(コンテナ)の受信ポートではない。 サービスの受信ポートは、コンテナの「ポートマッピング」設定を参照。 |
テストリスナーポート | 1443:HTTPS | Blue/Greenデプロイ時のALBが受けるテストポートを指定。 ALBのテスト用受信ポートであり、アプリを意識せずに指定が可能。 | |
ターゲットグループ1 | [$system]-[$env]-frontapp-alb-tg01 | アプリ要件 コンテナで受信可能なポートに対してトラフィックを転送する。 | Blue/Greenデプロイ実行の度に、サービスに紐づくターゲットグループが1と2で交互に代わる。 ※1 |
ターゲットグループ2 | [$system]-[$env]-frontapp-alb-tg02 | アプリ要件 コンテナで受信可能なポートに対してトラフィックを転送する。 | |
サービス検出の統合の有効化 | 無効 | アプリ要件 サービス間(コンテナ間)通信の要件として必要な場合は有効化。 | |
AutoScaling | Service Auto Scallingの設定を変更することで、サービスの必要数を調整する | サービスの性能要件 | |
タスクの最小数 | 2 | サービスの性能要件 | |
タスクの必要数 | 2 | サービスの性能要件 | |
タスクの最大数 | 4 | サービスの性能要件 | |
Service Auto Scaling | ターゲットの追跡 | サービスの性能要件 | |
ポリシー名 | Scalling-Policy-for-CPUUtilization | サービスの性能要件 | |
ECSサービスメトリクス | ECSServiceAverageCPUUtilization | サービスの性能要件 | |
ターゲット値 | 60 | サービスの性能要件 | |
スケールインの無効化 | OFF | サービスの性能要件 |
※1. Blue/Greenデプロイを行う場合のターゲットグループ入れ替わり動作
以下のような動作となり、デプロイの度に2つのターゲットグループは入れ替わる動作となる。そのため、ターゲットグループにBlue環境用や、Green環境用というような名称は使用しない方が良い。
- 初期状態:
- ターゲットグループ1を使用して、サービスに対してトラフィック転送される。
- ターゲットグループ2は使用されない。
- Blue/Greenデプロイ実施 1回目
- ALBのテスト用のリスナーポートのトラフィックをGreen環境へ転送する際にターゲットグループ
- ALBのテスト用のリスナーポートのトラフィックをGreen環境へ転送する際にターゲットグループ2が使用される。
- トラフィックの切り替えを行うことで、本番用のリスナーポートのトラフィックがターゲットグループ2に転送されるようになる。
- が使用される。
- トラフィックの切り替えを行うことで、本番用のリスナーポートのトラフィックがターゲットグループ2に転送されるようになる。
- Blue/Grenデプロイ実施 2回目
- ALBのテスト用のリスナーポートのトラフィックをGreen環境へ転送する際にターゲットグループ1が使用される。
- トラフィックの切り替えを行うことで、本番用のリスナーポートのトラフィックがターゲットグループ1に転送されるようになる。
ECSの構築
※カスタマイズしたfluentbitの作成や、ECRなど関連リソースの作成が必要なため、包括的に別途公開予定。
運用
イメージのビルド運用
- Cloud9などDockerが使用できるEC2上で都度手動によるビルド
- ECRの機能によりイメージを(基本 or 拡張)スキャンして、スキャン結果を踏まえて、イメージの再構築、or デプロイを判断するようなケースで使用。
- パイプライン内で自動的にビルド
- Dockerfileを更新して、CodeCommitへのpushをトリガとして自動的にビルド、&デプロイをするようなケースで使用。
イメージのタグ運用
- タグの変更可否(イミュータブル設定)
- 禁止した方が、誤ったバージョンのデプロイなどの事故が防げるため推奨。禁止するとイメージが新しくなる度に、最新イメージのタグをタスク定義に反映する必要があるが、パイプラインを使用している場合には、自動的にタスク定義を作成してくれるため、あまり意識する必要もなくなる。
- 割り当てるタグの例
- 上記イメージのビルド運用において、手動ビルドを行う場合には、「1.0」 「1.1」のようにアプリケーションの一般的なパッケージなどで使用されるバージョンを付与するケースが多い。
- パイプラインによるビルド自動化を行う場合、CodeCommit上のソースのハッシュ値の一部をタグに使用する場合もある。この方式のメリットは、ソースとイメージが対応付けできる点。
ECS Auto Scalingの動作について
- ECSのタスク障害が起きた場合は、「タスクの最小数」ではなく、「タスクの必要数」まで、タスクを稼働(復旧)する。
- スケールイン/スケールアウト時の動作
いずれかが実行されたタイミングで、タスクの稼働数が、増減するとともに「タスクの必要数」が同数に増減する。そのため、タスクの障害が発生した場合には、直前の状態(直前のタスクの必要数)に戻る動作となる。
- 仮にタスクの最小数を0とした場合、自動的にスケールインして、タスクが0になることはない。
- タスクの手動停止方法
通常タスクの必要数を0にすれば、タスクは0になるが、オートスケールが有効化されている場合には タスクの必要数を0にする直前のメトリクスによって、オートスケールする可能性がある。
そのため、以下2ついずれかを実施すると確実に停止できる。
– タスクの最大数も合わせて 0 に変更する
– AWS CLI の register-scalable-target コマンドにてスケールアウトの一時停止を実行する
<コマンド例> “`
$ aws application-autoscaling register-scalable-target \
–service-namespace ecs \
–scalable-dimension “ecs:service:DesiredCount” \
–resource-id “service/sample-cluster/sample-service” \
–suspended-state DynamicScalingOutSuspended=true