CLIでECS(EC2 Container Serviceを)を試す

[Amazon EC2 Container Service(ECS)をGUIから試してAWS側で用意したサンプルWebアプリを動かしたときのメモ](http://qiita.com/toshihirock/items/dfd42314158aff073e9d)

GUIからECSを実行することが出来たので、次にCLIを使ってやってみます。nginxが動作するコンテナを作成し、アクセスしてみます。

# 前提

+ AWS CLIが使えること
+ Docker実行環境が存在すること
+ [DockerHub](https://hub.docker.com)のアカウントが存在すること

# 参考

+ [Amazon EC2 Container Service (ECS)を試してみた](http://dev.classmethod.jp/cloud/ecs-ataglance/)
+ [Amazon EC2 Container Service(ECS)で静的Webサイトをデプロイする](http://dev.classmethod.jp/cloud/aws/ecs-deploy-static-website/)

というかほとんど上記をCLIをメインで再度やってみた形になります。

# Dockerコンテナの作成

[Amazon EC2 Container Service(ECS)で静的Webサイトをデプロイする](http://dev.classmethod.jp/cloud/aws/ecs-deploy-static-website/)

上記リンクの通り、Dockerfileを作成します。

```
$ mkdir nginx
$ cd nginx
$ vi Dockerfile
FROM nginx
COPY html /usr/share/nginx/html
```

また、コピーするHTMLも作成します。

```
$ mkdir html
$ vi html/index.html
<html>
<head><title>Amazon ECS deployed!</title></head>
<body><h1>Amazon ECS deployed!</h1></body>
</html>
```

`docker build`コマンドを利用してビルドし、コンテナ化します。**toshihirock**の部分はDockerhubのアカウント名に置き換えてください。

```
$docker build -t toshihirock/mynginx .
```

試しにローカルで起動してみます


```
$docker run -d -p 80:80 toshihirock/mynginx
1eff877751a7
$curl http://localhost
<html>
<head><title>Amazon ECS deployed!</title></head>
<body><h1>Amazon ECS deployed!</h1></body>
</html>
```

`docker inspect`を使う設定内容が確認できます。Cmdに以下が設定されるのが確認でき、 **deamon off(つまりフォアグラウンド）**で実行される事が分かります。（コマンドをフォアグランドで動作させないとコンテナが終了するので)

```
        "Cmd": [
            "nginx",
            "-g",
            "daemon off;"
        ],
```

# Dockerhubへの登録

確認ができたらDockerhubにコンテナを登録します。

まず、Dockerhubにログインします。

```
$docker login
```

次に`docker push`でDockerhubにコンテナを登録します。

```
$docker push toshihirock/mynginx
```


# ECS用のIAMロールの作成

コンテナを実行するEC2からECSにアクセスを行うために必要なIAMロールの作成を行います。

作成時に以下のサイトが参考になりました。

[AWS CLIでサービスの各種コマンドを動かしてみる(IAM編3: ロール)](http://dev.classmethod.jp/cloud/aws/awscli-iam-3-role/)

最初にロールを作成するためのファイルを作成します。

```lang:role.json
{
  "Version": "2012-10-17",
  "Statement": [
     {
       "Action": "sts:AssumeRole",
       "Principal": {
         "Service": "ec2.amazonaws.com"
        },
        "Effect": "Allow",
        "Sid": ""
     }
  ]
}
```

作成後、以下の操作でロールを作成します。

```
# 作成
$aws iam create-role --role-name ecs-full-access --assume-role-policy-document file://role.json

#確認
$aws iam get-role --role-name ecs-full-access
```

次にECSへアクセスするポリシーの作成をします。

```lang:role-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "ecs:*",
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
```

先ほど作成したロールに適用します。

```
$aws iam put-role-policy --role-name ecs-full-access --policy-name  ECSFullAccess --policy-document file://role-policy.json
```

確認します。

```
$ aws iam list-role-policies --role-name ecs-full-access
{
    "PolicyNames": [
        "ECSFullAccess"
    ]
}
```

先ほどのポリシーが作成したロールに適用されているのが確認できました。

EC2のIAMロールとして利用するためにインスタンスプロファイルを作成します。

```
$aws iam create-instance-profile --instance-profile-name ecs-full-access
```

作成したプロファイルをロールに適用させます。

```
$aws iam add-role-to-instance-profile --instance-profile-name ecs-full-access --role-name ecs-full-access
```

# クラスタの作成

コンテナを動作させるEC2群まとめるクラスタを作成します

```
$aws ecs create-cluster --cluster-name MyCluster
```

クラスタの作成を確認します
```
$aws ecs describe-clusters --clusters MyCluster
```

# ECS-Optimized Amazon Linuxの起動とクラスタへの参加

[Launching an Amazon ECS Container Instance](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html)

CoreOSも使えるようですが、最新のAmazonLinuxのECS readyなAMIを使います。20150623現在、ap-northeast1で使える最新のものは**ami-fa12b7fa**だったのでこれを使って起動します。

また、先ほど作ったクラスタに参加するために起動するEC2のUserDataで以下を設定するようにします。

```
#!/bin/bash
echo ECS_CLUSTER=MyCluster >> /etc/ecs/ecs.config
```

CLIから操作する場合、UserDataはBase64エンコードしたものを設定するようにします。
`--subnet-id`、`--security-group-ids`、`--key-name`については適宜自分の環境にあったものを設定して下さい。また、セキュリティグループについては80ポートを開放したものを設定してください。

```
$aws ec2 run-instances \
--image-id  ami-fa12b7fa \
--instance-type t2.micro \
--subnet-id subnet-d949e1ae \
--iam-instance-profile Name=ecs-full-access \
--user-data IyEvYmluL2Jhc2gNCmVjaG8gRUNTX0NMVVNURVI9TXlDbHVzdGVyID4+IC9ldGMvZWNzL2Vjcy5jb25maWc= \
--security-group-ids sg-baca56df \
--key-name hogeFugaKey \
|jq -r '.Instances[].InstanceId'
```

上記実行により、インスタンスIDのみ出力するようにjqでフィルタしています。
あとで利用するのでメモしておいて下さい。

少し時間を置いてからクラスタに先ほどのインスタンスが参加しているか確認します。

```
$aws ecs list-container-instances --cluster MyCluster
{
    "containerInstanceArns": [
        "arn:aws:ecs:ap-northeast-1:694273932022:container-instance/b16efbb0-c12f-4f74-bd2f-aa7756a5cc2d"
    ]
}
```

上記のようにcontainerInstanceArnsに一つ値が入っていればOKです。

# タスクの追加

タスク（実行するコンテナの詳細をまとめたもの）を追加します。指定するファイルでの詳細なパラメーターは[こちら](http://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_definition_parameters.html)を参照のこと。

今回の例では最初に作成したnginxのコンテナを利用するタスクを設定し、コンテナとホストでは80ポートのマッピングをしています。cpu、memoryはコンテナのスペックを表し、essentialをtrueにするとこのコンテナの実行が失敗するとタスクとして失敗したものとしてみなしてくれます。

```lang:nginx-task.json
[
  {
    "image": "toshihirock/mynginx",
    "name": "mynginx",
    "cpu": 10,
    "memory": 500,
    "essential": true,
    "environment": [],
    "portMappings": [
      {
        "containerPort": 80,
        "hostPort": 80
      }
    ]
  }
]
```

タスクを登録します。

```
$ aws ecs register-task-definition --family mynginx  --container-definitions file://nginx-task.json
```

タスクが登録されたことを確認します。

```
$aws ecs describe-task-definition --task-definition mynginx
```

上記ではタスクを登録しただけで、クラスタとの関連づけはされていません。先ほど登録したクラスタで上記タスクを実行させたいので登録を行います。
下記コマンドの`--task-definition`パラメーターでは**family:revision**という形式で指定します。今回のタスクのリビジョンは1なので**mynginx:1**という指定を行います。

```
$aws ecs run-task --cluster MyCluster --task-definition mynginx:1
{
    "failures": [],
    "tasks": [
        {
            "taskArn": "arn:aws:ecs:ap-northeast-1:694273932022:task/bf71c7b8-6fd0-40e5-b106-a14e588a3b04",
            "overrides": {
                "containerOverrides": [
                    {
                        "name": "mynginx"
                    }
                ]
            },
            "lastStatus": "PENDING",
            "containerInstanceArn": "arn:aws:ecs:ap-northeast-1:694273932022:container-instance/f053e789-7aaf-4be7-a90c-2f868b2802f0",
            "clusterArn": "arn:aws:ecs:ap-northeast-1:694273932022:cluster/MyCluster",
            "desiredStatus": "RUNNING",
            "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:694273932022:task-definition/mynginx3:1",
            "containers": [
                {
                    "containerArn": "arn:aws:ecs:ap-northeast-1:694273932022:container/18de6ec3-66b6-4b72-91a1-044c03ad60ba",
                    "taskArn": "arn:aws:ecs:ap-northeast-1:694273932022:task/bf71c7b8-6fd0-40e5-b106-a14e588a3b04",
                    "lastStatus": "PENDING",
                    "name": "mynginx"
                }
            ]
        }
    ]
}
```

登録直後は**lastStatus**がPENDDINGとなっており、コンテナが起動しておりません。少し時間をおいてから登録されたタスクの状態を確認します。`--tasks`パラメーターには先ほどタスクを登録した時に表示されたタスクのARN(taskArn)を指定します。

```
$aws ecs describe-tasks --cluster MyCluster --tasks arn:aws:ecs:ap-northeast-1:694273932022:task/bf71c7b8-6fd0-40e5-b106-a14e588a3b04
```

lastStatusを確認し、PENDDINGがRUNNINGになっていればコンテナが起動し、準備が完了していることになります。

# Webサイトにアクセスする

インスタンス登録時に表示したインスタンスIDを利用してEC2のPublicDNS名を取得します。

```
$aws ec2 describe-instances --instance-ids i-6004f292 |jq -r '.Reservations[].Instances[].PublicDnsName'
```

上記URLにアクセスするとnginxが起動しているコンテナにアクセスし、以下の内容が確認できるかと思います。


![Screen Shot 2015-06-24 at 8.38.06 AM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/23464d4d-0208-2740-71c5-af44239dc2ab.png)


# お掃除

まず、クラスタに登録したタスクを停止します。

```
$aws ecs stop-task --cluster MyCluster --task arn:aws:ecs:ap-northeast-1:694273932022:task/bf71c7b8-6fd0-40e5-b106-a14e588a3b04
```

次にECSを動作させているEC2をterminateします。

```
$aws ec2 terminate-instances --instance-ids i-6004f292
```


最後にクラスタを削除します。

```
# 削除
$aws ecs delete-cluster --cluster MyCluster

#　確認
$ aws ecs describe-clusters --clusters MyCluster
{
    "clusters": [
        {
            "status": "INACTIVE",
            "clusterName": "MyCluster",
            "registeredContainerInstancesCount": 0,
            "pendingTasksCount": 0,
            "runningTasksCount": 0,
            "clusterArn": "arn:aws:ecs:ap-northeast-1:694273932022:cluster/MyCluster"
        }
    ],
    "failures": []
}
```

statusが**INACTIVE**となっていればOKです。

ECSのタスク、ECS用のロールを削除したい人は各自お願いします。