ファイルを持ち出す動機
ECS Fargete上のタスクから障害調査などの目的でログファイルやコンフィグを外に持ち出したいシーンがあります。
アプリのログなどは基本的にCloudWatchLogsなど、タスク外部のログ収集機能にほぼリアルタイムで転送していると思いますが、Java Flight Recorder(JFR)で収集した性能情報などは、常時収集しておくこともできないため、何かしら問題が発生した場合に収集、持ち出すことが多いと思います。
S3で良いのでは?
ベースイメージとしてAmazon Linux 2023などを利用していれば、はじめからaws cliがインストールされていて、S3に必要なファイルをコピーすれば持ち出すことができます。
ただ、場合によってはS3バケットへの書き込み権限が設定されていなかったり、そもそもaws cliがインストールされていない場合もあります。
本番稼働中のため、設定変更や新たなツールを導入するには障壁が高く、現実的ではない場合があります。
代替え案
SSH、FTPなども実装されていないため、残るはECSExecのみ。
ただし、ECSExecそのものにはファイル転送機能はありません。
(※ 2024年以降のバージョン2.17以降であればaws cpコマンドが利用できます。)
そこで、ECSExecのプロンプトにファイルの内容を出力し、それをリダイレクトすることでローカルにファイルを出力する方法を検討しました。
実際のコマンド
普通のログファイル程度であれば、プロンプト上に出力されたものをコピーして、ローカルファイルに貼り付ければよいかもしれません。ただし、JFRのようなバイナリでかつある程度の容量があるものはこの方法では難しいです。
そこで一手間挟みます。
接続とファイル準備
まずは下記コマンドでタスクに接続し、必要なファイルをGZIPでまとめます。
aws ecs execute-command --cluster クラスタ名 --task タスクID --container コンテナ名 --command "/bin/sh" --interfactive
gzip 対象のファイル
exit (一旦接続を切断)
この後、上記コマンドでGZIP化したファイルをodコマンドで16進数に変換しながらプロンプト上に出力し、それをローカル環境のファイルにリダイレクトします。
ローカルへの転送
aws execute-command --cluster クラスタ名 --task タスクID --container コンテナ名 --command "od -tx1 -An GZIPファイル名" --interactive > ローカルファイル名
再バイナリ化
上記コマンドで生成されたファイルには、aws cliが余分なメッセージを付与しているため、一度viなどのエディタで開いて、該当箇所を削除します。
余分な行が削除できたら下記のコマンドでバイナリに再変換します。
xxd -p -r ローカルファイル名 > ローカルファイル名.gz
これでGZIPファイルに戻っているのであとはgzip -dコマンドで解凍するだけです。
まとめ
いかがでしょうか?
若干力技ではありますが、目的は達成できました。