[JAWS-UG CLI] AWS Batch #1 環境構築（Managed 編）

# 前提条件

## EC2への権限

EC2、ECS、AWS Batch などに対してフル権限があること。

# 0. 準備

## 0.1. AWS CLIのバージョン

以下のバージョンで動作確認済

* AWS CLI 1.11.36

```sh:コマンド
aws --version
```

```sh:結果（例）
 aws-cli/1.11.36 Python/2.7.5 Darwin/13.4.0 botocore/1.4.93
```

バージョンが古い場合は最新版に更新しましょう。

```sh:コマンド
sudo -H pip install -U awscli
```

## 0.2. リージョンの決定

2017 年 6 月、[AWS Batch が東京でリリースされた](https://aws.amazon.com/about-aws/whats-new/2017/06/aws-batch-is-now-available-in-tokyo/)ので、東京を指定してみましょう。

```sh:変数の設定
export AWS_DEFAULT_REGION='ap-northeast-1'
```

## 0.3. 資格情報の確認

プロファイルが想定のものになっていることを確認します。

```sh:変数の確認
aws configure list
```

```sh:結果（例）
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                  default           manual    --profile
access_key     ****************XXXX shared-credentials-file    
secret_key     ****************XXXX shared-credentials-file    
    region                ap-northeast-1              env    AWS_DEFAULT_REGION
```

## 0.4. AWS アカウントの属性

EC2-Classic が見えない AWS アカウントであること。

```sh:コマンド
AWS_SUPPORT_PLATFORMS=$( \
         aws ec2 describe-account-attributes \
           --query 'AccountAttributes[?AttributeName == `supported-platforms`].AttributeValues[].AttributeValue' \
           --output text \
) && echo ${AWS_SUPPORT_PLATFORMS}
```

```sh:結果
 VPC
```

注釈: `VPC` の他に `EC2` が表示される場合、別のアカウントを作成してください。

## 0.5. VPC / IAM ロールの作成

CloudFormation テンプレートのファイル名を定義

```sh:コマンド
CFN_STACK_NAME="aws-batch-`date +%s`"
```

テンプレートの取得

```sh:コマンド
curl --location --output ${CFN_STACK_NAME}.yaml \
  https://raw.githubusercontent.com/supinf/aws-batch-refarch/master/cloudformation/base.yaml
```

CloudFormation スタックの生成

```sh:コマンド
aws cloudformation create-stack \
  --stack-name ${CFN_STACK_NAME} \
  --template-body file://${CFN_STACK_NAME}.yaml \
  --capabilities CAPABILITY_IAM
```

```sh:結果（例）
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxxxx:stack/aws-batch-xxxxxxxxxx/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

このスタックにより以下のリソースが作成されます

* AWS Batch 用 VPC
* AWS Batch 用サービスロール
* SpotFleet 用サービスロール
* EC2 インスタンスプロフィール
* EC2 インスタンス用セキュリティグループ

## 0.6. EC2 キーペアの作成

以下の手順を参考にキーペアを作ります。

[[JAWS-UG CLI] EC2:#1 キーペアの作成 (新規)](http://qiita.com/tcsh/items/59303d9506ca7d13f744)

キーペアの確認

```sh:コマンド
aws ec2 describe-key-pairs \
  --key-names ${EC2_KEY_NAME}
```

指定したキーペアの情報が返ることを確認します

```sh:結果（例）
{
    "KeyPairs": [
        {
            "KeyName": "your-keypair-name", 
            "KeyFingerprint": "xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
        }
    ]
}
```

## 0.7. jq や jsonlint のインストール

最新の aws-cli には `jp.py` が入っていない気がします・・
というわけで [`jq`](https://stedolan.github.io/jq/download/) と [`jsonlint`](https://github.com/zaach/jsonlint) をそれぞれ入れておいてください。

# 1. クラスタ起動

## 1.1. コンピューティング環境名の指定

環境名の指定

```sh:コマンド
COMPUTE_ENV_NAME="aws-batch-managed-`date +%s`"
```

同名の環境がないことを確認

```sh:コマンド
aws batch describe-compute-environments \
  --compute-environments ${COMPUTE_ENV_NAME}
```

```sh:結果
{
    "computeEnvironments": []
}
```

## 1.2. 利用する VPC / IAM の変数定義

スタックの生成を待機

```sh:コマンド
aws cloudformation wait stack-create-complete \
  --stack-name ${CFN_STACK_NAME}
```

```sh:結果
返り値なし
```

生成結果を取得

```sh:コマンド
CFN_STACK_RESULT=$( aws cloudformation describe-stacks \
  --stack-name ${CFN_STACK_NAME} \
) && echo ${CFN_STACK_RESULT} | jq .
```

スタックの生成結果（Output）から、必要な変数を抜き出します。

```sh:コマンド
BATCH_SERVICE_ROLE=$( echo ${CFN_STACK_RESULT} \
  | jq '.Stacks[].Outputs[]' \
  | jq -r 'select(.OutputKey=="AWSBatchServiceRole").OutputValue' )

EC2_INSTANCE_PROFILE=$( echo ${CFN_STACK_RESULT} \
  | jq '.Stacks[].Outputs[]' \
  | jq -r 'select(.OutputKey=="BatchInstanceProfile").OutputValue' )

EC2_SPOT_FLEET_ROLE=$( echo ${CFN_STACK_RESULT} \
  | jq '.Stacks[].Outputs[]' \
  | jq -r 'select(.OutputKey=="AmazonEC2SpotFleetRole").OutputValue' )

VPC_SUBNET_IDS='["'$( echo ${CFN_STACK_RESULT} \
  | jq '.Stacks[].Outputs[]' \
  | jq -r 'select(.OutputKey=="PublicSubnet1").OutputValue' \
  )'","'$( echo ${CFN_STACK_RESULT} \
  | jq '.Stacks[].Outputs[]' \
  | jq -r 'select(.OutputKey=="PublicSubnet2").OutputValue' )'"]'

VPC_SECURITY_GROUPS='["'$( echo ${CFN_STACK_RESULT} \
  | jq '.Stacks[].Outputs[]' \
  | jq -r 'select(.OutputKey=="SecurityGroup").OutputValue' )'"]'

```

## 1.3. コンピュータリソースの定義

コンピュータリソースを定義するファイル名の指定

```sh:コマンド
BATCH_RESOURCES_FILE="aws_batch_compute_resources.json"
```

変数の確認

```sh:コマンド
cat << ETX

    BATCH_RESOURCES_FILE: ${BATCH_RESOURCES_FILE}
    BATCH_SERVICE_ROLE:   ${BATCH_SERVICE_ROLE}

    EC2_KEY_NAME:         ${EC2_KEY_NAME}
    EC2_INSTANCE_PROFILE: ${EC2_INSTANCE_PROFILE}
    EC2_SPOT_FLEET_ROLE:  ${EC2_SPOT_FLEET_ROLE}

    VPC_SUBNET_IDS:       ${VPC_SUBNET_IDS}
    VPC_SECURITY_GROUPS:  ${VPC_SECURITY_GROUPS}

ETX
```

結果（例）:

```

    BATCH_RESOURCES_FILE: aws_batch_compute_resources.json
    BATCH_SERVICE_ROLE:   arn:aws:iam::xxxxxxxxxxxx:role/service-role/aws-batch-xxxxxxxxxx-AWSBatchServiceRole-xxxxxxxxxxxx

    EC2_KEY_NAME:         your-keypair-name
    EC2_INSTANCE_PROFILE: arn:aws:iam::xxxxxxxxxxxx:instance-profile/aws-batch-xxxxxxxxxx-BatchInstanceProfile-xxxxxxxxxxxx
    EC2_SPOT_FLEET_ROLE:  arn:aws:iam::xxxxxxxxxxxx:role/aws-batch-xxxxxxxxxx-AmazonEC2SpotFleetRole-xxxxxxxxxxxxx

    VPC_SUBNET_IDS:       ["subnet-xxxxxxxx","subnet-xxxxxxxx"]
    VPC_SECURITY_GROUPS:  ["sg-xxxxxxxx"]

```

コンピュータリソース定義ファイルを生成します。

今回は `m3.medium` をスポットインスタンスで、入札価格の上限をオンデマンド価格に設定してみます。現在 **Managed 環境では** t2 系インスタンスが使えないためです。無料枠で収まらないのは無念ですが。

```sh:コマンド
cat << EOF > ${BATCH_RESOURCES_FILE}
{
  "instanceTypes": ["m3.medium"],
  "type": "SPOT",
  "bidPercentage": 100,
  "spotIamFleetRole": "${EC2_SPOT_FLEET_ROLE}",
  "desiredvCpus": 1,
  "maxvCpus": 1,
  "minvCpus": 1,
  "subnets": ${VPC_SUBNET_IDS},
  "securityGroupIds": ${VPC_SECURITY_GROUPS},
  "ec2KeyPair": "${EC2_KEY_NAME}",
  "instanceRole": "${EC2_INSTANCE_PROFILE}"
}
EOF
cat ${BATCH_RESOURCES_FILE}
```

コンピュータリソース定義ファイルの検証

```sh:コマンド
jsonlint -q ${BATCH_RESOURCES_FILE}
```

## 1.4. コンピューティング環境の作成

AWS Batch では、コンピューティング環境として [`MANAGED` または `UNMANAGED`](http://qiita.com/pottava/items/d9886b2e8835c5c0d30f#%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E7%92%B0%E5%A2%83) が選択できます。
`MANAGED` を選択すると、ECS クラスタも起動してくれるタイプ、
`UNMANAGED` は自分で ECS クラスタを用意するタイプです。

今回は `MANAGED` な環境を作成しましょう。

```sh:コマンド
aws batch create-compute-environment \
  --compute-environment-name ${COMPUTE_ENV_NAME} \
  --type MANAGED \
  --service-role ${BATCH_SERVICE_ROLE} \
  --compute-resources file://${BATCH_RESOURCES_FILE}
```

結果（例）:

```
{
    "computeEnvironmentName": "aws-batch-managed-xxxxxxxxxx", 
    "computeEnvironmentArn": "arn:aws:batch:ap-northeast-1:xxxxxxxxxxxx:compute-environment/aws-batch-refarch"
}
```

## 1.5. コンピューティング環境の確認

作成した環境の status が `VALID`、
state が `ENABLED` であることを確認しましょう。
status が `CREATING` である場合 `VALID` になるまでお待ちください・・

```sh:コマンド
aws batch describe-compute-environments \
  --compute-environments ${COMPUTE_ENV_NAME}
```

```sh:結果（例）
{
    "computeEnvironments": [
        {
            "status": "VALID", 
            "serviceRole": "arn:aws:iam::xxxxxxxxxxxx:role/service-role/aws-batch-xxxxxxxxxx-AWSBatchServiceRole-xxxxxxxxxxxxx", 
            "computeEnvironmentArn": "arn:aws:batch:ap-northeast-1:xxxxxxxxxxxx:compute-environment/aws-batch-refarch", 
            "computeResources": {
                "subnets": [
                    "subnet-xxxxxxxx", 
                    "subnet-xxxxxxxx"
                ], 
                "spotIamFleetRole": "arn:aws:iam::xxxxxxxxxxxx:role/aws-batch-xxxxxxxxxx-AmazonEC2SpotFleetRole-xxxxxxxxxxxxx", 
                "tags": {}, 
                "desiredvCpus": 1, 
                "minvCpus": 1, 
                "instanceTypes": [
                    "m3.medium"
                ], 
                "securityGroupIds": [
                    "sg-xxxxxxxx"
                ], 
                "bidPercentage": 100, 
                "instanceRole": "arn:aws:iam::xxxxxxxxxxxx:instance-profile/aws-batch-xxxxxxxxxx-BatchInstanceProfile-xxxxxxxxxxxx", 
                "maxvCpus": 1, 
                "type": "SPOT", 
                "ec2KeyPair": "your-keypair-name"
            }, 
            "statusReason": "ComputeEnvironment Healthy", 
            "ecsClusterArn": "arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:cluster/aws-batch-refarch_Batch_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", 
            "state": "ENABLED", 
            "computeEnvironmentName": "aws-batch-managed-xxxxxxxxxx", 
            "type": "MANAGED"
        }
    ]
}
```

# 2. ジョブキューの作成

## 2.1. ジョブキュー名の指定

ジョブキュー名の指定

```sh:コマンド
JOB_QUEUE_NAME="aws-batch-job-queue-`date +%s`"
```

同名のジョブキューがないことを確認

```sh:コマンド
aws batch describe-job-queues \
  --job-queues ${JOB_QUEUE_NAME}
```

結果:

```
{
    "jobQueues": []
}
```

## 2.2. ジョブキューの作成

ジョブキューの優先順位は 1 〜 10 で指定しますが、今回は 5 にします

```sh:コマンド
JOB_QUEUE_PRIORITY=5
```

ジョブキューには 3 つまでコンピューティング環境を関連づけられますが
今回は先ほど作成した環境でのみ実行可能なジョブキューを作成します。

```sh:コマンド
aws batch create-job-queue \
  --job-queue-name ${JOB_QUEUE_NAME} \
  --priority ${JOB_QUEUE_PRIORITY} \
  --compute-environment-order \
  order=1,computeEnvironment=${COMPUTE_ENV_NAME}
```

結果（例）:

```
{
    "jobQueueArn": "arn:aws:batch:ap-northeast-1:xxxxxxxxxxxx:job-queue/aws-batch-job-queue-xxxxxxxxxx", 
    "jobQueueName": "aws-batch-job-queue-xxxxxxxxxx"
}
```

## 2.3. ジョブキューの確認

作成したジョブキューの status が `VALID`、
state が `ENABLED` であることを確認しましょう。

```sh:コマンド
aws batch describe-job-queues \
  --job-queues ${JOB_QUEUE_NAME}
```

結果:

```
{
    "jobQueues": [
        {
            "status": "VALID", 
            "jobQueueArn": "arn:aws:batch:ap-northeast-1:xxxxxxxxxxxx:job-queue/aws-batch-job-queue-xxxxxxxxxx", 
            "computeEnvironmentOrder": [
                {
                    "computeEnvironment": "arn:aws:batch:ap-northeast-1:xxxxxxxxxxxx:compute-environment/aws-batch-refarch", 
                    "order": 1
                }
            ], 
            "statusReason": "JobQueue Healthy", 
            "priority": 5, 
            "state": "ENABLED", 
            "jobQueueName": "aws-batch-job-queue-xxxxxxxxxx"
        }
    ]
}
```

# 完了

環境構築は以上です。
[AWS Batch #2 ジョブの作成と実行](http://qiita.com/pottava/items/4151fcb9b14c51f50e9c)へ