ECSコンテナにローカルから入ってコマンドを実行してみよう ～AWS100本ノック～ 26/100

# はじめに
Dockerコンテナへコマンドを実行したい場合、ローカル環境であれば`docker compose exec`で行うことになるかと思います。
しかし、実際にAWS環境のECSへデプロイしたアプリケーションに問題があった場合、どのように調査すればいいでしょうか？

まずは、CloudWatchLogsでエラーログが出ていないかを見て、エラーログが出ていればエラー内容から実装を確認して修正していったりするかと思います。
しかし、
- エラーログが出ていない
- エラーログは出ているがローカルだと再現しない
- 開発と本番でインストールするパッケージが違うことにより、エラーが出ているようだがログだけだと調査しづらい

などの場合、少し困りますよね:cry:
AWSサポートへ問い合わせるにしても、有料サポートに加入しないといけないですし...

# ECS Execとは
そんな人のために、AWSではECSコンテナにexecコマンドを実行する**ECS Exec**が用意されています。
これを利用することによって、`docker compose exec`と同様に任意のコンテナで、コマンド実行することが出来るようになります:smile:

ユースケースとしては、
- 上記であげたようなエラー調査
- DBマイグレーション操作 ※ECSコンテナからDBへ`php artisan migrate`などでマイグレーションを実行している場合のロールバックなど
- (あんまりやらないほうがいいですが)一時的にコードを手動で変えてデバッグ
 
が主かなーとは思っています

# やってみた
では、実際にやっていきます。
なお、以下作業については既に終わっている前提になります。
- ECSコンテナの作成
- ローカル環境への[AWS CLIコマンドインストール](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html)
- ローカル環境への[Session Managerプラグインのインストール](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) ※ECS ExecではAWS Session Managerを利用しているため

## ローカルで利用するAWS認証情報への権限追加
ローカルからAWSへアクセスするための認証情報(アクセスキー、AWS SSOアクセスキーなど)にアタッチしているポリシーにECS Execコマンドと、ECSの設定を更新するための権限を追加します。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecs:ExecuteCommand",
                "ecs:UpdateService"
            ],
            "Resource": "*"
        }
    ]
}
```

## ECSのタスクロールへの権限追加
ECSのタスクロールに以下のSessionManagerに関する権限を追加します。

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

## ECS Execコマンドの有効化
対象のECSサービスを更新し、ECS Execコマンドを有効化します。

```bash
aws ecs update-service \
    --cluster ${ECSクラスター名} \
    --service ${ECSサービス名} \
    --enable-execute-command
```

:::note warn
2025年2月現在、AWSコンソールからは変更出来ないようなので、AWS CLIやCDK(CloudFormation)で更新する必要があります。
:::


## ECS Execコマンドの実行
準備が出来たので、最後にECSコンテナへ入ってみましょう。
※`--command`の部分は、任意のコマンドに変えてください

以下のようにコマンドを実行し、コンテナに入れれば成功です:smile:
後は、任意の操作などシーンに応じて対応してください！
```bash
aws ecs execute-command \
    --cluster ${ECSクラスター名} \
    --task ${ECSタスクID} \
    --container ${ECSコンテナ名} \
    --interactive \
    --command "bash"

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


Starting session with SessionId: ecs-execute-command-pyqund86re33xitvzd6e7ouiby
root@ip-10-1-73-229:/var/www/html# ls -la
```

![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/59383ca1-7f91-423f-8bba-ccbe2899425b.png)


### エラーが出た場合

基本的に上記の対応をしていれば問題なく入れるとは思いますが、以下のようなエラーが出ることがあります。
正直、これだと原因がよくわからないですよね...
```bash
An error occurred (TargetNotConnectedException) when calling the ExecuteCommand operation: The execute command failed due to an internal error. Try again later.
```

そんなときのために[ECS Exec Checker](https://github.com/aws-containers/amazon-ecs-exec-checker)と呼ばれるチェックツールがあります。
これを利用することで、ECS Execを行う上でどこに問題がある/ないを一気に見ることが出来ます。

git cloneしてAWS認証情報を設定した状態で、`./check-ecs-exec.sh ${ECSクラスター名} ${ECSタスクID}`と実行すると以下のような形で、各設定の状態を見ることが出来ます

```bash
Prerequisites for check-ecs-exec.sh v0.7-------------------------------------------------------------  jq      | OK (/usr/bin/jq)
  AWS CLI | OK (/usr/local/bin/aws)

-------------------------------------------------------------
Prerequisites for the AWS CLI to use ECS Exec
-------------------------------------------------------------
  AWS CLI Version        | OK (aws-cli/2.11.0 Python/3.11.2 Linux/4.14.255-291-231.527.amzn2.x86_64 exec-env/CloudShell exe/x86_64.amzn.2 prompt/off)
  Session Manager Plugin | OK (1.2.398.0)

-------------------------------------------------------------
Checks on ECS task and other resources
-------------------------------------------------------------
Region : us-east-1
Cluster: Fargate-Testing
Task   : ca27e41ea3f54fd1804ca00feffa178d
-------------------------------------------------------------
  Cluster Configuration  | Audit Logging Not Configured
  Can I ExecuteCommand?  | arn:aws:iam::12345678:role/Admin
     ecs:ExecuteCommand: allowed
     ssm:StartSession denied?: allowed
  Task Status            | RUNNING
  Launch Type            | Fargate
  Platform Version       | 1.4.0
  Exec Enabled for Task  | NO
  Container-Level Checks |
    ----------
      Managed Agent Status - SKIPPED
    ----------
    ----------
      Init Process Enabled (Exec-check:2)
    ----------
         1. Disabled - "nginx"
    ----------
      Read-Only Root Filesystem (Exec-check:2)
    ----------
         1. Disabled - "nginx"
  Task Role Permissions  | arn:aws:iam::12345678:role/L3-session
     ssmmessages:CreateControlChannel: implicitDeny
     ssmmessages:CreateDataChannel: implicitDeny
     ssmmessages:OpenControlChannel: implicitDeny
     ssmmessages:OpenDataChannel: implicitDeny
  VPC Endpoints          | SKIPPED (vpc-abcd - No additional VPC endpoints required)
  Environment Variables  | (Exec-check:2)
       1. container "nginx"
       - AWS_ACCESS_KEY: not defined
       - AWS_ACCESS_KEY_ID: not defined
       - AWS_SECRET_ACCESS_KEY: not defined
```


# おわりに
今回はECS Execを利用してECSコンテナに入り、コマンドを実行できるようにするまでの手順を紹介しました。
頻繁にECSコンテナへ入ることはないかもしれませんが、何かしらの不具合があった際にECSコンテナへ入って調査できるかどうかで、対応スピードに影響するので覚えておいて損はなさそうです:smile: