Amazon ECS Execを使ってコンテナ内部でコマンド実行してみた [amazon-ecs-exec-checker]

はじめに

少し前にリリースされた機能ですが、Fargateのコンテナ内部でデバッグ等を行う機会が増えたので
ECS Execの手順をまとめたいと思います。

目次

ECS Execとは?

一言で言うと

ECS on EC2/Fargateにデプロイされたタスク内のコンテナに “Exec” する機能です。
コンテナに対して対話型のシェル、あるいは一つのコマンドを実行できるようになります。

料金は?

追加費用はなく、ECSが使えるパブリックなAWSリージョン全てをサポートしています。
また現時点(2021/10/5)では、 ECS ExecはAWS SDK, AWS CLI および AWS Copilotを介してサポートされていますが、将来的にはAWS コンソールからも利用出来る予定だそうです。

何が嬉しいのか?

これまでは…
ECS on EC2であればsshにてインスタンスにログインしコンテナ内部に入ることが可能でしたが、
ECS on Fargateのケースではコンテナ内部に入れずトラブルシューティングがしにくいといった課題がありました。
(EC2の場合も接続までのステップが多く大変 & セキュアな接続手段ではないといった課題もありました)

しかし ECS Execの登場によりEC2/Fargate共にコマンドライン1つでコンテナ内部に入ることが可能になります。
EC2の場合もssh用にポート開放をする必要がないため、よりセキュアに接続が可能になります。

当ブログのゴール

Fargateのコンテナ内部に入り、index.htmlを編集して画面表示を変えてみよう!

ECS Execの検証環境説明

  • Fargateの前段にはALBを配置(ALB -> Fargate) ※1
  • ECS on FargateはPublic Subnet内に配置 ※2
  • FargateのセキュリティグループはALBからのみHTTPアクセスを許可
  • Dockerコンテナイメージは「nginx:latest」を使用

※1 ALB経由でのアクセスに設定していますが、ECS Execするために必要な条件ではありません
※2 ECS Execで特に必要ないECSの設定箇所は説明を省略します

上記の検証環境を構築すると、現時点でこのような画面が表示されます。
コンテナ内部に入ってindex.htmlを修正し表示内容を修正するのがゴールとなります。

ECS Execの前提条件

ECS/クライアント側でそれぞれ以下の条件である必要があります。

ECS側

  • EC2 起動モード
    ECS Agent 1.50.2 以降を利用する ECS Optimized AMI

  • Fargate 起動モード
    プラットフォームバージョン 1.4.0 以降をサポート

クライアント側

  • jqのインストール
    ECS Exec時には必要ありませんが
    後ほど紹介するecs-exec-checkerで必要となるため入れた方が良いです。
    Macであればbrewでjqをインストール可能です。

  • AWS CLI用のSession Manager pluginのインストール
    こちらは公式インストール手順をご確認ください。

ECS Execの設定手順

ざっと以下の 4Step が設定手順になります。
1〜3は初回時のみ設定、2回目以降は4のみで接続が可能です。

  1. タスク定義に紐付くECSタスクロールを修正
  2. AWS CLIにて「enableExecuteCommand」を有効化
  3. ECSサービスの強制デプロイ
  4. ECS Execコマンドを実行

0. amazon-ecs-exec-checkerにて事前チェック!

ECS Execにおいて、必要な設定に漏れがないかなどをチェックしてくれるツールがGitHubで公開されています。
AWSの方が作成してくださったAWS公式チェッカーツールになります。
ECS Execチェッカーの使い方はREADMEを参照して下さい。
シンプルな手順となっています。

GitHubからCloneし、ECS Execチェッカーで一度確認してみましょう。
「ECS Execの前提条件」がきちんと設定出来ていれば、おそらく以下のようなチェック結果になるかと思います。

  • Exec Enabled for Task / No
  • Task Role Permissionsの4項目がDeny
  • それ以外はAll OK!

設定手順で記載した1〜3を実施することで、上記項目が全てOKになります。乞うご期待!
ということで、上から順に設定していきましょう。

1. タスク定義に紐付くECSタスクロールを修正

ECSタスクは SSMエージェントが SSMサービスを呼び出すための適切なIAM権限を必要とします。
権限付与のためにタスクロールを修正します。

まずはECSのコンソール画面より対象のタスク定義を開きます。
タスク定義の「タスクロール ※」を選択し、必要なIAMポリシーを設定します。
※似たような名前の「タスク実行ロール」がありますが「タスクロール」を選択してください。

インラインポリシーの追加にて以下のポリシーをアタッチします。

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

タスクロールの修正が完了したら、チェックツールで確認してみましょう。
きっと以下のような結果になっていることでしょう。

  • Exec Enabled for Task / No
  • Task Role Permissionsの4項目がDeny -> allowed

2. AWS CLIにて「enableExecuteCommand」を有効化

ECSサービス単位にて設定を行う必要があります。
現時点(2021/10/5)ではAWS コンソールでの設定は出来ず、CLIにて設定する必要があります。

describe-servicesで出力結果がfalseになってることを確認(出力結果が多いのでgrepしてます)

$ aws ecs describe-services --cluster YOUR_ECS_CLUSTER_NAME --services YOUR_ECS_SERVICE_NAME | grep enableExecuteCommand

ECS Exec機能を有効化し、describe-servicesで出力結果がTrueになってることを確認

$ aws ecs update-service \
    --cluster YOUR_ECS_CLUSTER_NAME \
    --service YOUR_ECS_SERVICE_NAME \
    --enable-execute-command

$ aws ecs describe-services --cluster YOUR_ECS_CLUSTER_NAME --services YOUR_ECS_SERVICE_NAME | grep enableExecuteCommand

ここでチェックツールで確認してみましょう。
全てOK!となってるかと思いきや、まだ「Exec Enabled for Task」はNoのままです。
反映するにはサービスの更新が必要となります。(3. ECSサービスの強制デプロイにて説明)

また ECS Exec機能を無効化する場合は 以下のコマンドを実行してください

$ aws ecs update-service \
    --cluster YOUR_ECS_CLUSTER_NAME \
    --service YOUR_ECS_SERVICE_NAME \
    --disable-execute-command

3. ECSサービスの強制デプロイ

ECS Exec機能を有効化を反映させるためにサービスの更新を行います。

こちらはコンソール画面より操作します。
サービスの更新画面より「新しいデプロイの強制」にチェックを入れます。
その他の項目はそのままでサービスの更新を行います。

サービスの更新が完了したら、再度チェッカーにて確認をしてみましょう。
(注意!) 引数に設定するタスクIDですが、強制デプロイにて新しいタスクIDに変わっていますのでそちらを引数に変更しコマンドを実行してください。

  • Exec Enabled for Task / OK
    素晴らしいですね!これで全てOKとなり、ECS Execが可能な状態となりました。

4. ECS Execコマンドを実行

さぁ、待ちに待ったECS Execを実行しましょう!
execute-commandコマンドの引数のcommandには/bin/bashなどのシェルを指定します。
(コンテナにインストールされているシェルしか使えません)

コマンド実行するとセッションがスタートしコンテナ内部に入れちゃいます。
簡単に入れるのでトラブルシューティングが楽になります。
本当にありがたい機能です。

$ aws ecs execute-command \
    --cluster YOUR_ECS_CLUSTER_NAME \
    --task YOUR_ECS_TASK_ID \
    --container YOUR_CONTAINER_NAME \
    --interactive \
    --command "command"

今回はコンテナ内部に入って、index.htmlを修正したいため
以下のようなコマンドを実行しVimのインストールもしました。
index.htmlの中身は「Welcome Index.html New page!!」に変更しています。

$ apt update
$ apt install -y vim
$ vim /usr/share/nginx/html/index.html

ご覧の通り、画面表示が変わりましたね。
パチパチパチパチ!

コンテナ内部から抜け出す場合は、exit を実行すればセッションを終了させることが出来ます。

まとめ

初回時の設定は少し大変かもしれませんが
チェックツールを使うことで何が足りていないかなども簡単に分かるかと思います。
そして一度設定してしまえば、2回目以降のExec方法はコマンド1つで出来てしまうことも分かったかと思います。

ちなみにですが当ブログではご紹介出来ませんでしたが、Private Subnetの場合はVPCエンドポイントの設定等が必要になります。
どのエンドポイントが必要になるかどうかはチェックツールにて確認して頂けたらと思います。

また ECS Execはあくまでもトラブルシューティングやデバッグをすることが目的であるため
コンテナ内部にてソース修正等にしたまま本番稼働する運用は推奨されておりません。
正しいステップでコンテナイメージを更新しデプロイしましょう!
Code兄弟を駆使しCI/CDパイプラインが構築されているとなお良しです!

ECSを用いたサーバレス/コンテナ開発は、スカイアーチでは多くの実績があり得意としています。
開発のご相談等あればお問い合わせ頂ければ幸いです。
(最後はちゃっかり宣伝でした。笑)

長いブログを読んで頂きありがとうございました!

参考記事