【ECS】ecs-cliを使ってECSタスクを作成・実行する

今回はみなさん大好きコンテナ :whale: 関連のお話です。
ecsの操作に特化したecs-cliコマンドを使用してECRへイメージのプッシュ・ECSタスクの作成・実行する方法を説明します。これらの実行自体はGitHub Actions上で行いますので、GitHub Actionが有効になっている方は試してみてください。

# 定義ファイル
## :one: ECS用のdocker-compose
ローカル開発用とECS用にdocker-composeファイルを分けるので、docker-compose.ymlとは違うファイルに設定を書きます。

```ecs-compose.yml
version: '3'
services:
  app:
    build: .
    # ECRからプルするためにECRのレジストリ情報を先頭につける
    # DockerHubからプルする場合はレジストリ情報は不要
    image: $ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com/test
    container_name: test
    environment:
      PRODUCTION: true
    logging:
      # CloudWatch Logsにログを書き込む
      # FargateでECSを起動させるなら必須
      driver: awslogs
      options:
        awslogs-group: /ecs/test
        awslogs-region: ap-northeast-1
        awslogs-stream-prefix: ecs
```

## :two: ECSパラメーター

```ecs-params.yml
version: 1
task_definition:
  # Fargateを使用するのでネットワークモードにawsvpcを指定
  ecs_network_mode: awsvpc
  task_execution_role: ecsTaskExecutionRole
  task_size:
    cpu_limit: 256
    mem_limit: 512
  services:
    app:
      # System Managerのパラメーターストアから値を取得して環境変数にセット
      # 予め設定をしておく必要がある
      # ECSのマネジメントコンソールには環境変数名(TOKEN)とパラメーターキー(token_for_test)が表示される
      secrets:
        - value_from: token_for_test
          name: TOKEN

run_params:
  network_configuration:
    awsvpc_configuration:
      subnets:
        - xxxxxxxxxxxxxxxxx
      security_groups:
        - xxxxxxxxxxxxxxxxx
      assign_public_ip: ENABLED
```

# ecs-cliによる操作
コマンドの実行にはAWSアクセスキーIDとシークレットキーの設定が最低限必要です。環境変数や~/.aws/credentialsに設定をしてください。

## ecs-cliのインストール
Ubuntu 18.04でのインストール方法を説明します。他のOSでのインストール方法は[こちら](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_CLI_installation.html)を参考にしてください。

```bash
# 最新バージョンをダウンロード
sudo curl -o /usr/local/bin/ecs-cli https://amazon-ecs-cli.s3.amazonaws.com/ecs-cli-linux-amd64-latest

# ダウンロードしたコマンドの検証 (必ずしも必要ではないが検証はした方がいい)
sudo apt install -y --no-install-recommends gnupg
gpg --keyserver hkp://keys.gnupg.net --recv BCE9D9A42D51784F
curl -o ecs-cli.asc https://amazon-ecs-cli.s3.amazonaws.com/ecs-cli-linux-amd64-latest.asc
gpg --verify ecs-cli.asc /usr/local/bin/ecs-cli

# 実行権限の付与
sudo chmod +x /usr/local/bin/ecs-cli

# コマンドの実行確認
ecs-cli --version
```

## ECRへのイメージプッシュ
ecs-cliを使えばログインなどの面倒な手続きを省略することができます。$YOUR_REPOSITORYにはアカウントIDとかのレジストリ情報をつける必要もありません。単純にイメージ名と必要に応じてタグを指定してあげれば :ok:

```bash
ecs-cli push --verbose $YOUR_REPOSITORY
```

## ECSのタスク作成/実行
ローカル開発とECS用でdocker-composeファイルを分けているので`-f`ではECS用を指定します。分けていなければデフォルトで`./docker-compose.yml`となっているので、あえて`-f`を指定する必要はありません。
`--launch-type`はEC2かFARGATEを指定できます。ここではFARGATEにします。

```bash
compose -p $PROJECT -f ecs-compose.yml \
        --ecs-params ecs-params.yml --cluster $CLUSTER \
        up --launch-type FARGATE
```

|option|default value|description|
|:--:|:--:|:--|
|-p, --project|current directory name|プロジェクト名を指定|
|-f, --file|./docker-compose.yml|Docker Composeファイルを指定|
|--ecs-params|./ecs-params.yml|Docker Composeには記述できないECS特有のパラメーターを記述したファイルを指定|
|-c, --cluster||ECSのクラスターを指定|
|--launch-type||起動タイプを指定<br>EC2 or FARGATE<br>クラスターの設定によって上書きされる|

# GitHub Actions (CI/CD)
以上の説明をふまえて完成したGitHub Actionsが↓になります。

```yaml
name: ECS compose up

# masterブランチにプッシュされたらCI起動
on:
  push:
    branches:
      - master

env:
  # GitHubのSecretsから値を取得
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  AWS_DEFAULT_REGION: ap-northeast-1

jobs:
  compose_up:
    name: Compose Up
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@master

      - name: Install ecscli
        run: |
          sudo curl -o /usr/local/bin/ecs-cli https://amazon-ecs-cli.s3.amazonaws.com/ecs-cli-linux-amd64-latest
          sudo apt install -y --no-install-recommends gnupg
          gpg --keyserver hkp://keys.gnupg.net --recv BCE9D9A42D51784F
          curl -o ecs-cli.asc https://amazon-ecs-cli.s3.amazonaws.com/ecs-cli-linux-amd64-latest.asc
          gpg --verify ecs-cli.asc /usr/local/bin/ecs-cli
          sudo chmod +x /usr/local/bin/ecs-cli
          ecs-cli --version

      - name: Push image to ECR
        # $IMAGEは適宜置き換え
        run: |
          docker build -t $IMAGE .
          ecs-cli push --verbose $IMAGE

      - name: ECS compose up
        run: |
          ecs-cli compose -p $PROJECT -f ecs-compose.yml \
            --ecs-params ecs-params.yml --cluster $CLUSTER \
            up --launch-type FARGATE

      # CIが失敗したらSlackのdevelopチャンネルに通知
      - name: Slack Notification
        uses: homoluctus/slatify@master
        if: failure()
        with:
          url: ${{ secrets.SLACK_WEBHOOK }}
          type: ${{ job.status }}
          job_name: ':fargate: ECS Compose up'
          channel: develop
          icon_emoji: ':github:'
          username: 'GitHub Actions'
```

# 参考資料
- [Amazon ECS Command Line Reference](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_CLI_reference.html)
- [Using Amazon ECS Parameters](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cmd-ecs-cli-compose-ecsparams.html)