1. aokad

    No comment

    aokad
Changes in body
Source | HTML | Preview
@@ -1,328 +1,328 @@
-AWS CLI を使って AWS ECS でタスクを実行するまでを解説します。
-このドキュメントを読むためには AWS EC2、AWS S3 および docker に対する基本的な知識が必要です。
-サービス、メトリクス、タスクのスケジューリングについては解説しません。
+AWS CLI を使って AWS ECS でタスクを実行するために必要なコマンドをまとめます。
+この記事を読むためには AWS EC2、AWS S3 および docker に対する基本的な知識が必要です。
+サービス、メトリクス、タスクのスケジューリングについては記載しません。
-前記事:[AWS CLI で AWS batch にジョブを送信する (全3回)](https://qiita.com/aokad/items/f28ffa5ae984678817f6)とリンクしていますが、未読でも問題なく読めるように作成したつもりです。
+前記事:[AWS CLI で AWS batch にジョブを送信する (全3回)](https://qiita.com/aokad/items/f28ffa5ae984678817f6)とリンクしていますが、未読でも問題なく読めるように記載したつもりです。
参考:[EC2 タスクを使用した AWS CLI のウォークスルー](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ECS_AWSCLI_EC2.html)
## 目次
全4回です。
1. [はじめに](https://qiita.com/aokad/private/b3762e3cc10db6104858)
2. タスクを実行してみる ← イマココ
3. [一連の流れをスクリプト化する](https://qiita.com/aokad/private/0eacf96fcb2378c7a36c)
4. [汎用 docker イメージを使用する](https://qiita.com/aokad/private/0e6a22082122cebc30bb)
AWS CLI 公式リファレンスはこちら [aws ecs](https://docs.aws.amazon.com/cli/latest/reference/ecs/index.html)
## 1. AWS CLI の準備
手順はこちらを参照してください。 [AWS CLI のインストールと設定](https://qiita.com/aokad/items/88fe9312eea1c12ba8a2)
今回は JSON を扱うために `jq` コマンドも使用しますのでインストールしてください。
https://stedolan.github.io/jq/download/
## 2. docker イメージを作成する(オプション)
今回の作業手順ではこちらで用意した docker イメージ [aokad/aws-wordcount](https://hub.docker.com/r/aokad/aws-wordcount/) を使用しますので、この作業は不要です。
独自イメージを使用する場合は [上記イメージの DockerFile](https://raw.githubusercontent.com/aokad/qiita_aws_batch/master/Dockerfile) を参考にしてください。
この記事においてイメージに必要なもの(最終的にはなくてもよいです)
- AWS CLI ... `aws configure` はしないこと(タスク実行時に自動で一時的なアカウントが設定されます)
- docker run の時に実行するスクリプトファイル
AWS ECR を使用する場合は [AWS CLI で Amazon ECR に docker イメージを push する](https://qiita.com/aokad/items/17a06c2384041bd60d16) を参照してください。
## 3. AWS 情報を環境変数にセット
この記事ではコピペ実行できるようにアカウントの違いを環境変数にセットしておきます。
- AWS_ACCOUNTID ..... 自分のアカウントID
- AWS_REGION ..... `aws configure` で設定したリージョン
- SUBNET1,2,3 ..... 「AWSコンソール」→「VPCダッシュボード」→「VPC」からデフォルトVPCのサブネットを確認してください
- SECURITYGROUPID ..... 「AWSコンソール」→「VPCダッシュボード」→「セキュリティグループ」からデフォルトのセキュリティグループをのIDを確認してください。新しく作成する場合は22番ポートを開けてください。
- KEY_NAME ... 作成するインスタンスの SSH キーです。無ければ作製してください。
- S3_BUCKET ... 作業用の S3 バケットです。任意の名称で作成してください。
設定例
```Bash
export AWS_ACCOUNTID=123456789012
export AWS_REGION=ap-northeast-1
export SUBNET1=subnet-123a456b
export SUBNET2=subnet-789c012d
export SUBNET3=subnet-345e678f
export SECURITYGROUPID=sg-11335577
export KEY_NAME=mykey
export S3_BUCKET=mybucket
AMI_ID=ami-a99d8ad5
```
## 4. クラスターを作成
クラスターは名前の定義だけです。
```Bash
aws ecs create-cluster \
--cluster-name myCluster \
> create-cluster.log
```
作成したクラスターの ARN を取得します。
```Bash
CLUSTER_ARN=$(jq -r '.cluster.clusterArn' create-cluster.log)
```
<FONT SIZE=1>
備考:
ARN とは、Amazon リソースネームの略で、AWS リソースを一意に識別するためのものです。
</FONT>
作成したクラスターは「AWSコンソール」→「Elastic Container Service」→「Amazon ECS」→「クラスター」から確認できます。
![amazon-ecs-1.png](https://qiita-image-store.s3.amazonaws.com/0/226829/f5ab71e5-e539-392d-6e87-d75c8aad7648.png)
## 5. タスク定義を作成
まず、タスク定義に必要なコンテナ定義を作成します。
```Bash
ECSTASKROLE="arn:aws:iam::${AWS_ACCOUNTID}:role/AmazonECSTaskS3FullAccess"
cat << EOF > task_definition.json
{
"containerDefinitions": [
{
"name": "mytask-definision",
"image": "aokad/aws-wordcount:0.0.1",
"cpu": 1,
"memory": 800,
"essential": true,
"entryPoint": [
"ash",
"-c"
],
"command": [
"ash run.sh \${INPUT} \${OUTPUT}"
],
"environment": [
{
"name": "INPUT",
"value": ""
},
{
"name": "OUTPUT",
"value": ""
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "mytask",
"awslogs-region": "${AWS_REGION}",
"awslogs-stream-prefix": "ecs-test"
}
}
}
],
"taskRoleArn": "${ECSTASKROLE}",
"family": "mytask"
}
EOF
```
タスク定義を登録します。
```Bash
aws ecs register-task-definition \
--cli-input-json file://task_definition.json \
> register-task-definition.log
```
作成したタスク定義の ARN を取得します。
```Bash
TASK_DEFINITION_ARN=$(jq -r '.taskDefinition.taskDefinitionArn' register-task-definition.log)
```
## 6. ロググループを作成
AWS Batch は自動で作ってくれましたが、Amazon ECS では自分で作ります。
```Bash
aws logs create-log-group --log-group-name mytask
```
## 7. EC2 インスタンスを起動する
AWS Batch は自動で作ってくれましたが、Amazon ECS では自分で作ります。
Amazon ECS AMI を使用してインスタンスを起動します。
Amazon ECS AMI はリージョンごとにimage-idが違います。今回は東京リージョン (ap-northeast-1) を使用していますが、別リージョンを使用する場合は[こちら](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ECS_AWSCLI_EC2.html#AWSCLI_EC2_launch_container_instance)から選択してください。
```Bash
AMI_ID=ami-a99d8ad5
```
今回の例では 30GByte のディスクをアタッチし、docker コンテナから使用できるストレージも 30G に増加します。
そのためのユーザデータを作成します。
ユーザデータとは、AWS EC2 でインスタンス起動時に実行できるスクリプトです。
詳しくはこちら:[Linux インスタンスでの起動時のコマンドの実行](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/user-data.html)
```Bash
cat << EOF > userdata.sh
Content-Type: multipart/mixed; boundary="==BOUNDARY=="
MIME-Version: 1.0
--==BOUNDARY==
Content-Type: text/cloud-boothook; charset="us-ascii"
# Install nfs-utils
cloud-init-per once yum_update yum update -y
cloud-init-per once install_nfs_utils yum install -y nfs-utils
cloud-init-per once docker_options echo 'OPTIONS="\${OPTIONS} --storage-opt dm.basesize=30G"' >> /etc/sysconfig/docker
#!/bin/bash
# Set any ECS agent configuration options
echo "ECS_CLUSTER=${CLUSTER_ARN}" >> /etc/ecs/ecs.config
--==BOUNDARY==--
EOF
```
EC2 インスタンスを起動します。
```Bash
aws ec2 run-instances \
--image-id ${AMI_ID} \
--security-group-ids ${SECURITYGROUPID} \
--key-name ${KEY_NAME} \
--user-data "file://userdata.sh" \
--iam-instance-profile Name="ecsInstanceRole" \
--instance-type t2.micro \
--block-device-mappings "[{\"DeviceName\":\"/dev/xvdcz\",\"Ebs\":{\"VolumeSize\":30,\"DeleteOnTermination\":true}}]" \
--count 1 \
> run-instances.log
INSTANCE_ID=$(jq -r '.Instances[0].InstanceId' run-instances.log)
```
起動したインスタンスに名前を付けておきます。(オプション)
```Bash
aws ec2 create-tags --resources ${INSTANCE_ID} --tags Key=Name,Value=ecs-task-instance
```
インスタンスが起動完了するまで待ちましょう。
成功するとクラスターに登録されています。
![amazon-ecs-2.png](https://qiita-image-store.s3.amazonaws.com/0/226829/f17e17d7-64d9-839f-4ad8-334f1c782c89.png)
## 8. タスクの実行
ジョブを投入する前に、入出力用の S3 バケットを作成し、適当なデータを置いておきます。
```Bash
cat << EOF > Humpty.txt
Humpty Dumpty sat on a wall,
Humpty Dumpty had a great fall.
All the king's horses and all the king's men
Couldn't put Humpty together again.
EOF
aws s3 cp Humpty.txt s3://${S3_BUCKET}/
```
いよいよタスクを実行してみます。
```Bash
cat << EOF > containerOverrides.json
{
"containerOverrides": [
{
"name": "mytask-definision",
"environment": [
{
"name": "INPUT",
"value": "s3://${S3_BUCKET}/Humpty.txt"
},
{
"name": "OUTPUT",
"value": "s3://${S3_BUCKET}/Humpty.count.ecs.txt"
}
]
}]
}
EOF
aws ecs run-task \
--cluster ${CLUSTER_ARN} \
--task-definition ${TASK_DEFINITION_ARN} \
--overrides file://containerOverrides.json
```
作成したタスクは「AWSコンソール」→「Elastic Container Service」→「Amazon ECS」→「クラスター」から確認できます。
![amazon-ecs-3.png](https://qiita-image-store.s3.amazonaws.com/0/226829/99283191-0039-fca9-8499-1c8962190ae2.png)
タスク終了後に新しくタスクを投入したい場合は、この「8. タスクの実行」だけを繰り返せばよいですが、並列実行させるためには「7. EC2 インスタンスを起動する」も行う必要があります。
s3://${S3_BUCKET}/Humpty.count.txt が出力されていれば成功です。
なお、スクリプトの実行ログは「AWSコンソール」→「ClowdWatch」→「ログ」から確認できます。
## 9. 片付け
AWS batch はコンピュート環境やタスク定義には料金がかからず実際に立ち上げたインスタンスとデータ転送量、AWS ECR イメージサイズ、ClowdWatch(ログ)に課金されます。
インスタンスを削除します。
AWS Batch は自動で削除してくれましたが、Amazon ECS では自分で削除します。
ひとまずこれで安心です。
```Bash
aws ec2 terminate-instances --instance-ids ${INSTANCE_ID}
```
タスク定義、クラスターを削除します。
AWSコンソールから削除してもよいですが、AWS CLI でのコマンド例も記載しておきます。
```Bash
# タスク定義を削除
aws ecs deregister-task-definition --task-definition ${TASK_DEFINITION_ARN}
# クラスターを削除
aws ecs delete-cluster --cluster ${CLUSTER_ARN}
```
AWSが出力した log を削除します
「AWSコンソール」→「ClowdWatch」→「ログ」→該当するロググループをクリック→ログストリームを選択して、「ログストリームの削除」
「AWSコンソール」→「ClowdWatch」→「ログ」→該当するログを選択→ログストリームを選択して、「アクション」→「ロググループの削除」
AWS CLI で実行する場合は以下です。
```Bash
# ログストリームを削除
# 複数ある場合はそれぞれ削除してください
aws logs delete-log-stream --log-group-name mytask --log-stream-name ecs-test/mytask-definision/{36桁のコード}
# ロググループを削除
aws logs delete-log-group --log-group-name mytask
```
---
今回はコマンドを順に解説しました。
インスタンスの起動やタスクの終了など待ちが発生するので、実際に使うためには待ちをどうにかして実装する必要がありそうです。
次回[一連の流れをスクリプト化する](https://qiita.com/aokad/private/0eacf96fcb2378c7a36c)では、wait サブコマンドで実現する方法を記載します。