概念図
とりあえずECSに出てくるエンティティがそれぞれどんな多重度で関連しているのかをまとめてみました。ここからはそれぞれのエンティがどんな概念なのかを解きほぐしていきたいと思います。
Serviceが中心
ECSは平たく言うと
- クラスター(=複数EC2インスタンスの集合)の上で
- Dockerコンテナを使って、
- Serviceを動作させる
ものです。
上図は、
- Front Service
(裏にいるAPIをCallしてWEB UIを提供するもの) - API Service
(ビジネスロジック、DBへの読み書きをRESTful APIで提供するもの)
と言う2つのService で構成されるWEBアプリケーションの例です。
ECSで言うServiceは、Serviceは利用者から見た「サービス」よりも一段階か二段階細かいもので、APIサーバーとか、フロントサーバーとかそういった単位の単機能なものです。ロールとかそういう言い方が近いのかもしれません。
(作り方によってはサービス=Serviceにもできるのですが、ECSのスケールアウトが容易であるという特性を使うためには先に述べたような単機能な単位になってくるかと思われます。)
Serviceってなんなの?
最初の時点では非常に説明しづらい概念なのですが、以下の情報を管理するものです。
管理する情報 | 指定する方法 |
---|---|
どんなコンテナを起動するのか | どのTask Definitionを使うかを指定する |
何個起動するのか | Number of Tasksとして常時起動しておきたい個数を指定する |
リクエスト分散するのか | コンテナとELBの紐付けを指定する |
Serviceの実体はDockerコンテナである
さて、実行中のServiceというのは複数個のDockerコンテナの集合体です。
上の図2の例では
- Front Serviceは2種類のコンテナから成り立つ
- expressのアプリケーション のコンテナ
- nginx(expressにプロキシする) のコンテナ
- API Serviceは1種類のコンテナから成り立つ
- Djangoを使ったAPI実装 のコンテナ
という構造を表しています。(今回の例ではDBはRDSを利用するものとして、ECSの外の要素としています)
Dockerコンテナを束ねるのがTask
図2の例では計3種類のコンテナが動作している図ですが、3種類それぞれがバラバラに管理されている訳ではありません。
Taskと言う単位で2つのグルーピングがされています。
- Front Task
- express コンテナ
- nginx コンテナ
- API Task
- Django コンテナ
Taskは複数個並列で動く
さて、図2は、
- Front Service の中で FrontのTaskが3個 起動している
- API Service の中で 、APIのTaskが4個 起動している
と言う状態を示しています。
図2のような構成を物理で組んだ場合には当然ながら対障害性、負荷分散を目的として冗長化をするかと思います。
このような冗長化をする場合、ELBを使って分散する事になるかと思いますが、ECSでも同様にELBを使用します。
ECSではServiceに一つELBを指定します。
ELBの作成自体は事前に済ませておき、既存のELBを指定する感じになります。
(ELBを使わないNo ELBも選択可能です。その場合はDNSラウンドロビンなどの方法を取ることになるでしょう)
Taskの定義はTask Definition(ってそんまんま)
オブジェクト指向の喩えでタスクをインスタンス(オブジェクト)とするとTask Definitionはクラスになります。
Task DefinitionはほぼほぼDockerコンテナの起動方法を指定するもので、Docker Composeのcompose.ymlファイルとだいたい同じです。
Task DefinitionはJSON形式で記述する設定ファイルで、書き方についてはとりあえずこちらを見てねという形でお茶を濁しておきます。
http://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html
ということでServiceの作り方
まずServiceはTask Definitionを元にして作ります。
項目 | なんとなく説明 |
---|---|
Task Definition | Serviceの元となるTask DefinitionでTask Definitionは事前に作成されている必要があります |
Cluster | Serviceを動作させるクラスタを指定します(後述) |
Service name | Serviceの識別子で適当にわかりやすい名前をつけてください |
Number of tasks | このService上でTaskをいくつ動かすかを定義します。あとから変更可能です。 |
Load Balancer | 前述の通り負荷分散するためのELBの名前と使うポート番号を指定します。 |
クラスター
クラスターはContainer Instanceの集合体で、要するにEC2インスタンスの集合体です。
クラスター内のそれぞれのインスタンスはただのリソース量(CPU,メモリ,ポートを供給するリソース量)として捉えられ、個々はあまり重要ではありません。
- 足りなくなればインスタンスを足せリソース量が増える
- 状況に対してリソース量が過剰であればインスタンスを減らす
というもので、どのインスタンス上で何のタスクを動かすかはECSの采配で自動的に決まります。
Container Instance
Container InstanceとなるEC2インスタンスは、
- Docker入り
- Amazon ECS Container Agent 入り
である必要がありますが、通常はECS最適化されたAMIからインスタンスを作るので特に気にする必要はないでしょう。
2017/11時点での最新のAMIはamzn-ami-2017.09.b-amazon-ecs-optimized
ですが、ECS Container AgentのアップデートとともにAMIもアップデートされていくので下記の公式ページを時々チェックすると良いでしょう。
また、Container Instanceを構成するためには以下も必要になります。
- インスタンスにアタッチするIAMロール
- ECSクラスタの名前(インスタンスのuser-dataに以下のように設定する)
#!/bin/bash
echo ECS_CLUSTER=MyCluster>> /etc/ecs/ecs.config
See:
- http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ECS_instances.html
- http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/launch_container_instance.html
普通はAuto Scalingグループを使う
上記のようなEC2インスタンスをポコポコ作っていけばクラスタのメンバーを増やしていく事ができますが、結構面倒です。普通はAuto Scalingグループを使うことになるでしょう。
ECSの管理画面を初めて起動した時に出てくるチュートリアルを実施すると上記のような起動設定のAuto Scalingグループが作られるので、その起動設定をコピーしてAuto Scalingグループを作ってインスタンス管理をするのが良いでしょう。
クラスタの上でService、タスクがどう動くのか
- Frontサービスはタスクを2つ起動
- APIサービスはタスクを3つ起動
上図3-AはHogeクラスター上でFront、APIの両サービスを稼働させている例です。
お財布都合でインスタンス数を抑えたい時にはこのようなクラスタ構成になるでしょう。
ただし状況によっては逆にリソースが有効に使われていないインスタンスがあるかもしれません。(図3-パターンAの003の例)
図3-Bはfront用とapi用でクラスターを分けている例です。
ピーク特性などが違う場合にはこちらのパターンのようにクラスタを分けて構成したほうがインスタンス数の調整はし易いでしょう。この例では1インスタンスに一つのTaskとなることでそれぞれのインスタンスタイプは下げる事ができて、結果的にお財布に優しくなるかもしれません。
さて、上図3(A,Bとも)ではfrontのタスクが別インスタンスに分散されていますが、CPU,メモリといっったリソースの状況が許せば一つのインスタンス上で複数タスクが動作するという事も有り得ます。
ECSが出た頃の2015年当時はELBと組み合わせるためにタスクのポート
をホストのポート
にマッピングする必要があり、上記の構成ではホストの80番ポートの衝突をするという理由でfrontタスクが同じインスタンス上で複数動作することはかないませんでしたが、2016年に登場したALBによってこの縛りはなくなりました。ALBと動的ポートを使ったロードバランスについてはこちらを参照してください。
ちょっと嘘つきました
ECSは平たく言うと
- Dockerコンテナを使って、
- クラスターの上で
- Serviceを動作させる
ものです。
実はクラスターの上ではServiceだけではなくて、タスクを直接動作させることもできます。
バッチジョブなどがこれに該当するでしょう。
Google Kubernetes Engine(GKE)も大体似たような概念になっています。
余力があれば別途GKEについても書きたいと思います。