ちょっと話題の記事

[アップデート] 実行中のコンテナに乗り込んでコマンドを実行できる「ECS Exec」が公開されました

もう、コンテナ調査のためにEC2に乗り込む必要は無い! もう、Fargateだからコンテナの状況が見れないと悩むこともない! ECS開発者待望の機能がリリースされました!
2021.03.16

みなさん、こんにちは!
AWS事業本部の青柳@福岡オフィスです。

Amazon Elastic Container Service (ECS) において、実行中のコンテナに乗り込んでコマンドを実行できる機能「ECS Exec」が公開されました。

Amazon ECS now allows you to execute commands in a container running on Amazon EC2 or AWS Fargate

どんなものなのか、早速使ってみたいと思います。

これまでの方法

デバッグやトラブルシューティングを行うために、実行中のコンテナに乗り込んでコマンドを実行したいという時があると思います。

これまで、これをECSで行おうとする場合、コンテナを実行しているEC2インスタンスにSSHでログインした後にdocker execコマンドを実行するという方法が取られてきました。
この方法では、以下のような問題 (手間) がありました。

  • 予めEC2インスタンスにSSHで接続できるようにしておく必要がある (SSMセッションマネージャーを使うという方法もありますが)
  • 複数のEC2インスタンスでECSサービスを実行している場合、目的のコンテナが稼働しているEC2インスタンスを特定する必要がある

また、コンテナをFargateで実行している場合、そもそも上記の方法すら使えませんでした。

ECS Execでは、これらの問題が一気に解決できます。

ECS Execの仕組み

ECS Execでは、AWS Systems Manager (SSM) の「セッションマネージャー」の仕組みを使うことで、クライアントからSSMコンポーネントを経由してコンテナにアクセスすることを実現しています。

そのため、EC2インスタンスにログインする必要はありませんし、コンテナにSSHポートを開けたりする必要もありません。

SSMをベースとしているために、EC2インスタンスやFargateでSSMエージェントが動作している必要があります。
ただし、後述するように、ECS Execに対応済みの特定バージョン以降のECSインスタンス (ECS-optimized AMI) やFargate (プラットフォームバージョン) を利用することで、ユーザーが手作業でSSMエージェントをインストールしたりすることなくECS Execを利用することができます。

前提条件

ECS Execを利用するための前提条件は以下の通りです。

ECS側

前述の通り、ECS Execに対応したSSMエージェントが導入済みのEC2インスタンスまたはFargateを使用する必要があります。

  • コンテナをEC2インスタンスで実行する場合:
    • ECS-optimized AMIの「2021年1月20日」以降にリリースされたバージョンを使う
  • コンテナをFargateで実行する場合:
    • Fargateのプラットフォームバージョン「1.4.0」以降を使う

EC2インスタンスの場合は、上記対応バージョンAMIから起動したEC2インスタンスをECSクラスターに追加または置き換えてください。

Fargateの場合は、ECSサービスを作成する際にFargateのプラットフォームバージョンを「1.4.0」以上に指定するか、既存のECSサービスを更新してください。

クライアント側

コンテナ上でコマンドを実行するためにAWS CLIのaws ecs execute-commandコマンドを使います。
このコマンドを使うことができる以下のバージョンにアップデートする必要があります。

  • AWS CLI v1の場合:
    • バージョン 1.19.28 (2021/03/16リリース) またはそれ以降
  • AWS CLI v2の場合:
    • 2021/03/16時点で対応したバージョンがリリースされていません (今後数週間でリリース予定とのこと)
      バージョン 2.1.31 (2021/03/20リリース) またはそれ以降

普段AWS CLI v2を利用されている方は、AWS CLI v1を追加でインストールするか (AWS CLIのv1とv2の共存は可能です)、AWS CLI v2が対応するのを待ちましょう。

2021/03/20更新 AWS CLI v2も対応しました!

加えて、「Session Managerプラグイン」をインストールする必要があります。

これは、AWS CLIを使ってEC2インスタンスにSSMセッションマネージャーでログインするためにaws ssm start-sessionコマンドを使ったことのある方であれば、インストールしたことがあるかと思います。

まだインストールしたことがない方は、以下の手順でインストールしておきましょう。

(オプション) AWS CLI 用の Session Manager plugin をインストールする - AWS Systems Manager

なお、Session Managerプラグインのバージョン要件については特に触れられていませんが、多少古めのバージョンでも動作はしました。
念のために最新バージョンを導入することをオススメします。

ECS Execを利用するための設定

ECS Execを利用するまでの流れは以下のようになります。

  1. SSMセッションマネージャー関連の権限を付与したIAMロール (ECSタスクロール) を用意する
  2. 1で用意したECSタスクロールを使って、ECSタスク定義を新規作成または更新する
  3. ECSサービスで「enableExecuteCommand」の設定を有効にする
  4. 2で作成/更新したECSタスク定義を使って、ECSサービスを新規作成または更新する
  5. (ECS Execを使ってコンテナ上でコマンドを実行する)

順に説明していきます。

1. SSMセッションマネージャー関連の権限を付与したIAMロール (ECSタスクロール) を用意する

以下の定義でIAMポリシーを作成します。

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

ECSタスクロールを新規作成して、上記で作成したIAMポリシーをアタッチします。
または、既存のECSタスクロールがある場合は、そちらのECSタスクロールにIAMポリシーをアタッチします。

ECSタスクロールの作成手順は下記を参照してください。

タスク用の IAM ロール - Amazon Elastic Container Service

2. 1で用意したECSタスクロールを使って、ECSタスク定義を新規作成または更新する

細かな手順は割愛しますが、一般的な手順 (マネジメントコンソール、AWS CLI、CloudFormation、etc.) でECSタスク定義を新規作成または更新する際に、ステップ1で作成したIAMロールを「タスクロール」に指定してください。

3. ECSサービスで「enableExecuteCommand」の設定を有効にする

ECS Exec機能の利用可否は、ECSサービス単位で設定します。

現時点で、AWSマネジメントコンソールの画面からECS Exec機能の利用可否の設定を行ったり、現在の設定状態を確認することはできないようです。

そこで、AWS CLIを使って設定を行うことにします。

ECSサービスを新規作成する場合

ECS Exec機能を有効にするためには、aws ecs create-serviceコマンドを実行する際に--enable-execute-commandオプションを付与します。

また、明示的にECS Exec機能を無効にしたい場合は--disable-execute-commandオプションを付与します。

※ 「前提条件」で説明したEC2インスタンスまたはFargateの条件が整っていない場合に--enable-execute-commandオプションを指定すると、エラーが発生します。

作成または更新したECSサービスの設定を確認するには、aws ecs describe-servicesコマンドを実行します。

$ aws ecs describe-services \
    --cluster example-cluster \
    --services example-service
{
  "services": [
    {
      "serviceArn": "arn:aws:ecs:ap-northeast-1:123456789012:service/example-cluster/example-service",
      "serviceName": "example-service",
・・・(中略)・・・
      "enableExecuteCommand": true
    }
  ]
}

既存のECSサービスの設定を変更する場合

ECS Exec機能を有効にしたい場合は、aws ecs update-serviceコマンドに--enable-execute-commandオプションを付けて実行します。

$ aws ecs update-service \
    --cluster example-cluster \
    --service example-service \
    --enable-execute-command

ECS Exec機能を無効にしたい場合は、aws ecs update-serviceコマンドに--disable-execute-commandオプションを付けて実行します。

$ aws ecs update-service \
    --cluster example-cluster \
    --service example-service \
    --disable-execute-command

4. 2で作成/更新したECSタスク定義を使って、ECSサービスを新規作成または更新する

こちらも細かな手順は割愛しますが、一般的な手順 (マネジメントコンソール、AWS CLI、CloudFormation、etc.) でECSサービスを新規作成する際にステップ2で作成したECSタスク定義を指定するか、ECSサービスを更新する際にステップ2で更新したECSタスクのリビジョンを指定してください。

なお、ECS Exec機能は「enableExecuteCommand」を有効にした後に起動したタスクでのみ利用可能です。

タスク定義のリビジョンに変更が生じない場合は、サービスの更新の際に「新しいデプロイの強制」にチェックを入れることで、強制的にタスクの起動を行わせるとよいでしょう。

起動したタスクで「enableExecuteCommand」が有効になっているかどうかを確認するには、aws ecs describe-tasksコマンドを実行します。

$ aws ecs describe-tasks \
    --cluster example-cluster \
    --tasks XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{
  "tasks": [
    {
      "attachments": [ ... ],
      "availabilityZone": "ap-northeast-1a",
・・・(中略)・・・
      "enableExecuteCommand": true,
・・・(中略)・・・
    }
  ]
}

ECS Execを使って、コンテナ上でコマンドを実行してみる

さて、準備ができましたので、実際にECS Execを使ってコンテナ上でコマンドを実行してみましょう。

AWS CLIに新たに追加されたコマンドaws ecs execute-commandを使います。
オプションには「ECSクラスター名」「タスクID」「コンテナ名」そして「実行するコマンド」を指定します。

対話形式のコマンド実行を意味する--interactiveオプションは必須ですので注意してください。
なお、--non-interactiveオプションも用意されていますが、現時点では対応していないようです。(指定するとエラーになる)

$ aws ecs execute-command \
    --cluster example-clustr \
    --task XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
    --container nginx \
    --interactive \
    --command "ps aux"

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

Starting session with SessionId: ecs-execute-command-XXXXXXXXXXXXXXXXX
PID   USER     TIME   COMMAND
    1 root       0:00 nginx: master process nginx -g daemon off;
    9 nginx      0:00 nginx: worker process
   10 root       0:00 /managed-agents/execute-command/amazon-ssm-agent
   23 root       0:00 /managed-agents/execute-command/ssm-agent-worker
  304 root       0:00 /managed-agents/execute-command/ssm-session-worker ecs-ex
  312 root       0:00 ps aux

Exiting session with sessionId: ecs-execute-command-XXXXXXXXXXXXXXXXX.

SSMセッションマネージャーのセッションが開始され、コマンドps auxが実行され、セッションを終了したことが確認できます。

コンテナに対してシェルログインを行いたい場合は、コマンドに/bin/sh/bin/bashを指定します。(当然ながらコンテナにインストールされているシェルしか使えません)

$ aws ecs execute-command \
    --cluster example-clustr \
    --task XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
    --container nginx \
    --interactive \
    --command "/bin/sh"

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

Starting session with SessionId: ecs-execute-command-XXXXXXXXXXXXXXXXX
/ #

これで、コンテナ上で自由にコマンドを実行することができます。

シェルを終了するにはexitコマンドを実行します。

/ # exit

Exiting session with sessionId: ecs-execute-command-XXXXXXXXXXXXXXXXX.

シェルの終了後、SSMセッションマネージャーのセッションも終了します。

おわりに

これで、ECS環境においてコンテナ上のアプリのデバッグやトラブルシューティングが捗るのではないでしょうか。

ECS Execでは他にも「実行したコマンドのロギングと監査」「IAMポリシーによる細かなアクセス制御」などを行うことができます。
これらについては、また調べて試してみたいと思います。