Fargateですで起動しているコンテナ（運用中）にあとからecs execする

## abstract
2021年の3月より、AWS ECSがアップデートされ、実行中のコンテナに[`ecs exec`できるようになった](https://aws.amazon.com/jp/blogs/news/new-using-amazon-ecs-exec-access-your-containers-fargate-ec2/)。AWSの公式ドキュメントでは、新しいコンテナをデプロイする際に、あらかじめ`ecs exec`できるようにする手段が記載されているが、ここでは、すでに実行中のコンテナに対して、`ecs exec`できるようにするために行った手順を記録しておく。先述のリンク先にも記載のある通り、コンテナにexec機能を事後にオプトインすることで、デプロイ時にはecs execできない設定のコンテナも、あとからecs execを利用できる。なお、EC2上で起動するECSタスクは本稿の対象でない。

## prerequisite

### client-side

AWS CLIを利用可能な最新バージョンにアップグレードすること
必要であれば[SSM Plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)をインストールすること
なお、[AWSCloudShell](https://aws.amazon.com/jp/blogs/news/aws-cloudshell-command-line-access-to-aws-resources/)を用いるとクライアント側のツール導入作業フリーで本稿の作業を実施できるのでおすすめである

### server-side

Fargate v 1.4.0以上を利用すること

## assumption
nginxコンテナを実行中。80ポートで通信を受け付けている。
タスクロールとしてecsTaskRoleTest(カスタムロール)を使用。タスク実行ロールとしてecsTaskExecutionRole(AWSマネージドロール)を使用。
今のnginxコンテナは、`ecs exec`を受け付けない状態。

## protocol
1. 実行中のタスクのECSタスクロールに、SSMを経由してAWSサービスとやりとりするための権限を付与する
1. 実行中のタスクにECSタスク実行ロールが付与されていることを確認する（されていなければ付与する）
1. 実行中のタスクの`enableExecuteCommand`を`true`に変更する
1. ecs execを使ってコンテナの中に入れることを確認する

### 実行中のタスクのECSタスクロールに、SSMを経由してAWSサービスとやりとりするための権限を付与する

まず、SSMを使う権限をECSタスクロールに付与する。
以下の内容は、`ecs exec`するにあたって最低限必要なSSMに関する部分のみの抜粋である。このほか、対象とするコンテナがDynamoDBとやりとりしたり、S3とやりとりしたりする必要がある場合は、それらも明示的な許可が必要である。すでに運用中のコンテナであれば、タスクロールですでにそれらが明示的に許可されているはずであるので、その場合は、すでに許可されているエンティティに追加して、以下のjsonで示すエンティティも許可する。以下の内容を`ecsExecTestTaskRolePolicy.json`として保存する。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssmmessages:CreateControlChannel",
                "ssmmessages:CreateDataChannel",
                "ssmmessages:OpenControlChannel",
                "ssmmessages:OpenDataChannel"
            ],
            "Resource": "*"
        }
    ]
}
```

ここでは、`ecsTaskRoleTest`というすでに付与しているタスクロールに対して、上記の`ecsExecTestTaskRolePolicy`をアタッチする。以下のコマンドを実行する（マネコンからも実施可能である）。

```bash
aws iam put-role-policy \
    --role-name ecsTaskRoleTest \
    --policy-name ecsExecTestTaskRolePolicy \
    --policy-document file://ecsExecTestTaskRolePolicy.json
```

これでタスクロールに`ecs exec`するうえで最低限必要な権限が付与できた。

### 実行中のタスクにECSタスク実行ロールが付与されていることを確認する（されていなければ付与する）

ここでは、タスク実行ロールは、タスク定義を作成するときに`ecsTaskExecutionRole`（AWSマネージドロール）を利用した想定である。参考までに、もし、独自のロールを設定した場合、次のコマンドで、すでに実行中のタスクのタスク実行ロールに`ecsTaskExecutionRole`を付与できそうである。

```bash
aws iam attach-role-policy \
    --role-name yourCustomRoleName \
    --policy-arn "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
```

### 実行中のタスクの`enableExecuteCommand`を`true`に変更する

`aws ecs describe-services --services yourServiceName`を実行すると、以下のように表示される。`enableExecuteCommand`が`false`になっているので、現状、このコンテナに対して`ecs exec`できない状態であることがわかる。

```json
{
    "services": [
        {
            "networkConfiguration": {
                "awsvpcConfiguration": {
                    "subnets": [

(中略）

            "enableExecuteCommand": false
        }
    ], 
    "failures": []
}
```

下記のコマンドを発行し、実行中のタスクを更新する。ここでは、`ecs exec`できるように状態を変更する(サービスでない場合は、`run-task`コマンドを使い、タスクを再デプロイする）。ここが本稿のキモである。`enableExecuteCommand`が`False`の既存のコンテナであっても、 exec 機能をオプトインすることができる。なお、新規にサービスを実行したり、タスクを実行したりする場合は、`--enable-execute-command`オプションを付けることで、exec機能を有効にしてデプロイできる。

```bash
$ aws ecs update-service \
    --cluster yourClusterName \
    --service yourServiceName \
    --enable-execute-command
```

実行した結果、下記のように、`enableExecuteCommand`が`true`に切り替わっている（`aws ecs describe-tasks`コマンドでも確認できる）。

```json
(前略)
        "enableExecuteCommand": true
    }
}
```

最後に、サービス自体を再デプロイする必要がある。コンソールで、サービスを強制的にデプロイにチェックを入れ、再デプロイする。これで、これまで実施してきた変更が実行中のタスクに対して適用される。

### ecs execを使ってコンテナの中に入れることを確認する

以上で、ecs execの準備は整った。以下のコマンドで、コンテナの中に入る。なお、タスクのIDはマネコンから確認可能である。

```bash
aws ecs execute-command  \
    --region yourAWS_REGION \
    --cluster yourClusterName \
    --task yourTaskId \
    --container nginx \
    --command "/bin/bash" \
    --interactive
```

下記のように、コンテナの中でBashシェルを操作できている。

```bash
The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.


Starting session with SessionId: ecs-execute-command-013e4b9c436ac6bbe
root@1a098f439dc742ef98a596612e581195-2531612879:/# ls
bin  boot  dev  docker-entrypoint.d  docker-entrypoint.sh  etc  home  lib  lib64  managed-agents  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@1a098f439dc742ef98a596612e581195-2531612879:/# 
```

## Summary
すでに運用しているタスク（の中のコンテナ）に、`ecs exec`を使い、Bashシェルでログインする手順を記載した。運用中のコンテナのトラブルシューティングの際に役立つ。