各コンテナインスタンスで Amazon ECSタスクを走らせるには

 ECS EC2 Docker
2015.09.16

Running an Amazon ECS Task on Every Instance | AWS Compute Blog の意訳です。
翻訳を手伝ってくださった @seiyakubo さんありがとうございました。

 
記事更新 (2015.09.17): IAMロールの Actionを一部修正しました

 

ーー
 

同僚の Matt McCleanが、クラスタ内の 全てのインスタンスで特定のタスクを実行する方法 について素晴らしいゲスト投稿をしてくれました。
 


 

ECSは Dockerコンテナをサポートするハイスケーラブルでハイパフォーマンスなコンテナ管理サービスです。ECSを使えば、EC2クラスタ上で 簡単にアプリケーションを実行することができます。
 

コンテナベースのアーキテクチャーでアプリケーションをデプロイしようとすると、全てのEC2インスタンス上でエージェントを起動しなければいけないことがありますよね。運用やセキュリティ上の懸念に由来する、監視・セキュリティ・メトリクス・サービスディスカバリー・ロギングなどなど。従来のやり方なら、UserDataスクリプト、もしくは Upstartや Systemdといった initシステムを使って エージェントを起動するための docker run をコールすることになります。たしかにこの方法でも動きはするのですが、実はいくつか不利な面があります。まず、このようにしてエージェントを起動してしまうと ECSがそのコンテナを把握することができず、CPUやメモリ、使用するポートについての情報が追跡できません。それにおそらく、新しいエージェントを立てたり、変更したり、インスタンスから取り除いたりする エージェントの管理も難しいでしょう。そういった変更は各インスタンスのローカルで行う必要があるわけで、つまり、各マシンに SSH接続する必要がでてきてしまいます。
 

この記事では UserDataスクリプトを使って、どうすれば特定の TaskDefinitionを ECSインスタンスで起動できるのかをお伝えします。
 

Example セットアップ

以下、サンプルアプリケーションを作り、すべての ECSインスタンスで cAdvisor (container advisor) エージェントを走らせる例をとりあげます。読んでいただければ、コンテナのリソース利用やパフォーマンス上の特性を理解する一助になるかと思います。cAdvisorについてのより詳細な情報は GitHubのリポジトリ をご覧ください。
 

まずはじめに、以下の要件をご確認ください。

 

ECSクラスタを作るには

 

  1. ECSコンソールを開き、「Create cluster」を押下。
  2. 固有のクラスタ名をつけて「Create」。

 

cAdvisorエージェント用の Task Definitionを定義するには

 

  1. ECSコンソールを開き、左のメニューから「Task Definitions」を選びます。
  2. Task Definitionsページで「Create new task definition」を押下。
  3. JSONタブを選び、以下の JSONテキストをコピー&ペースト。
{
    "family": "cadvisor",
    "containerDefinitions": [
        {
            "name": "cadvisor",
            "image": "google/cadvisor",
            "cpu": 10,
            "memory": 300,
            "portMappings": [
                {
                    "containerPort": 8080,
                    "hostPort": 8080
                }
            ],
            "essential": true,
            "mountPoints": [
                {
                    "sourceVolume": "root",
                    "containerPath": "/rootfs",
                    "readOnly": true
                },
                {
                    "sourceVolume": "var_run",
                    "containerPath": "/var/run",
                    "readOnly": false
                },
                {
                    "sourceVolume": "sys",
                    "containerPath": "/sys",
                    "readOnly": true
                },
                {
                    "sourceVolume": "var_lib_docker",
                    "containerPath": "/var/lib/docker",
                    "readOnly": true
                }
            ]
        }
    ],
    "volumes": [
        {
            "name": "root",
            "host": {
                "sourcePath": "/"
            }
        },
        {
            "name": "var_run",
            "host": {
                "sourcePath": "/var/run"
            }
        },
        {
            "name": "sys",
            "host": {
                "sourcePath": "/sys"
            }
        },
        {
            "name": "var_lib_docker",
            "host": {
                "sourcePath": "/var/lib/docker/"
            }
        }
    ]
}

4. Builderタブを開き、内容が確認できたら「Create」しましょう。
 

 

IAM ECSロールを作るには

 
ここで作る IAMロールは標準的な ECS操作権限をもっており、ECSインスタンスに 先ほど定義した Task Definitionを起動するための StartTaskを許可するものです。

  1. 以下のポリシーに基づく新しい ECS IAMロールを作ります。より詳しい情報は Amazon ECS Container Instance IAM Role をご覧ください。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecs:CreateCluster",
                "ecs:RegisterContainerInstance",
                "ecs:DeregisterContainerInstance",
                "ecs:DiscoverPollEndpoint",
                "ecs:StartTelemetrySession",
                "ecs:Submit*",
                "ecs:Poll",
                "ecs:StartTask"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

(訳者注:原文にはない ecs:StartTelemetrySession を Actionに追加しています。2015年9月16日現在 ECSのバージョンアップに伴いデフォルトになったこの権限がないと CloudWatchから ECSのメトリクスを確認することができないためです)

 

定義したタスクをもった ECSインスタンスを起動するには

 
以下の UserDataスクリプト はその EC2インスタンスが入る ECSクラスタを設定し、[ECSコンテナエージェント イントロスペクション API])http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-agent-introspection.html)から ECSコンテナインスタンス ARNを取得し、ECS StartTaskを実行します。これによって、事前に生成した cadvisor:1 という名前の Task Definitionが始まるわけです。
 

  1. ECSインスタンスを立ち上げます。詳細は こちら で確認できますが、今回の例で必要になる、以下の UserDataスクリプト指定については書かれていません。 your_cluster_nameをご自分のクラスタ名に置き換え、UserDataフィールドに貼り付けてください。
#!/bin/bash
cluster="your_cluster_name"
echo ECS_CLUSTER=$cluster >> /etc/ecs/ecs.config
start ecs
yum install -y aws-cli jq
instance_arn=$(curl -s http://localhost:51678/v1/metadata | jq -r '. | .ContainerInstanceArn' | awk -F/ '{print $NF}' )
az=$(curl -s http://instance-data/latest/meta-data/placement/availability-zone)
region=${az:0:${#az} - 1}
aws ecs start-task --cluster $cluster --task-definition cadvisor:1 --container-instances $instance_arn --region $region

メモ: サーバ再起動時にもタスクが動作するよう、upstartや systemdのような initスクリプトにも追加すべきですね

 

タスクが起動したことを確認するには

 

  1. ECSコンソールを開きます。
  2. 左のメニューから「Clusters」を選び、設定してきたクラスタを選びます。
  3. Tasksタブをひらくと cadvisor:1と名前のついた Task Definitionが RUNNINGになっていることが確認できるはずです。

 

おわりに

 

すべてのステップを踏んできたのであれば、目指していたシステムは完成です!クラスタ内のすべての ECSインスタンスで cadvisorが動いているかと思います。このように、すべてのインスタンスで起動したいタスクがあれば、上述のUserDataスクリプトを書き換えることで実現できます。