はじめに
先日、とあるスライドを読み返して「そういえばFireLensって聞いたことあるけど、触ったことないなぁ」と思ったのと、先日のアップデートでECSマネージドインスタンスが発表されてたなと思い、両方まとめてキャッチアップすることにしました。
FireLensとは
スライドを見るのが一番早いですが、簡単にまとめます。
FireLensはECS Task上で実行されるアプリケーションのログを収集する手段の一つです。通常はCloudWatch Logsで事足りますが、システムが大規模で、ログの量が多い場合はCloudWatch Logsの取り込み料金が高額になる可能性があります。
そのためログの活用方法次第で、CloudWatch LogsではなくS3等に保存するというのも選択肢になります。
FireLensはCloudWatch Logs以外のAWSサービス(S3やOpenSearchなど)やSaaS (Splunkなど)へのログ転送が可能となるログルーティングの仕組みです。
FluentdまたはFluent BitというOSSをサイドカーパターンで配置することで、CloudWatch Logs以外へのログ転送が可能となります。ちなみに、AWSではFluent Bitの利用を推奨しています。
AWS は、CloudWatch Logs と Firehose の両方のプラグインに Fluent Bit イメージを提供します。Fluent Bit は、リソース使用率が Fluentd よりも低いため、ログルーターとして使用することをお勧めします。
ECSマネージドインスタンスとは
これまで、ECSのデータプレーンとして利用できるものはFargateかEC2の2択でした(ECS Anywhereは別)。AWS管理かユーザー管理かで選択することになっていましたが、今回登場したマネージドインスタンスは中間に当たる仕組みで、EC2で起動はするものの、セキュリティパッチ当てなどがAWS管理となり、本来ユーザーの責務であったことをAWSにて行ってくれるものになります。
Fargateでは実現できない高性能なEC2やGPUインスタンスを使いたけど、管理はしたくない...そんなニーズに応えるサービスです。
試してみる
構成
今回作成する構成はこちらです。図には記載していませんが、ECSで動かすコンテナはマネージドインスタンスを利用します。
S3バケットを作成する
まずはログの保存先となるS3バケットを作成します。
バケットタイプは「汎用」を選び、バケット名は任意の名前にします。他の設定はデフォルトにしておきます。
任意の名前でOKですが、全世界で一意な名前である必要があります。ご自身の名前や日付などを入れることで一意になりやすいです。
ECS用のVPCを作成する
続いて、ECSのコンテナを動作させるためのVPCを作成します。今回は検証用ということでパブリックサブネットを1つ、インターネットゲートウェイを作成します。
VPC作成後、パブリックサブネットで「パブリックIPv4アドレスの自動割り当てを有効化」します。
※今回、検証用ということでパブリックサブネットにECS Taskを配置します。
ECSクラスターを作成する
続いて、ECSクラスターを作成していきます。コンピューティングキャパシティは「Fargateインスタンスとマネージドインスタンス」を選択します。その下でインスタンスプロファイルとインフラストラクチャロールの設定が必要になります。今回は新規作成が必要になるので手順に従って作成していきます。
インスタンスプロファイルの作成
まずはこちらのドキュメントを参照しながらインスタンスプロファイルを作成します。
インスタンスプロファイルをマネコンから作成することはできなさそうなため、AWS CLIで作成しています。
まずは信頼ポリシーとなるJSONファイルを用意します。
{
"Version":"2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}
]
}
このJSONファイルを作成後、IAMロールを作成します。
aws iam create-role \
--role-name ecsInstanceRole \
--assume-role-policy-document file://ecsInstanceRole-trust-policy.json
こちらのIAMロールにマネージドポリシーをアタッチします。
aws iam attach-role-policy \
--role-name ecsInstanceRole \
--policy-arn arn:aws:iam::aws:policy/AmazonECSInstanceRolePolicyForManagedInstances
その後、インスタンスプロファイルを作成します。
aws iam create-instance-profile --instance-profile-name ecsInstanceRole
最後に、インスタンスプロファイルにロールを追加します。
aws iam add-role-to-instance-profile \
--instance-profile-name ecsInstanceRole \
--role-name ecsInstanceRole
インスタンスプロファイルが作成できているか確認します。
aws iam get-instance-profile --instance-profile-name ecsInstanceRole
これでインスタンスプロファイルは作成完了です。
インフラストラクチャロールの作成
続いてインフラストラクチャロールを作成します。
インスタンスプロファイルと同じように、信頼ポリシーを記載したJSONファイルを作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAccessToECSForInfrastructureManagement",
"Effect": "Allow",
"Principal": {
"Service": "ecs.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
IAMロールを作成します。
aws iam create-role \
--role-name ecsInfrastructureRole \
--assume-role-policy-document file://ecs-infrastructure-trust-policy.json
IAMポリシーをアタッチします。
aws iam attach-role-policy \
--role-name ecsInfrastructureRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes
aws iam attach-role-policy \
--role-name ecsInfrastructureRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForServiceConnectTransportLayerSecurity
ここでは2つIAMポリシーをアタッチしていますが、これだけでは動作しませんでした。(詳細は後述します。)
ユースケース(VPC Latticeを利用する場合)によってはAmazonECSInfrastructureRolePolicyForServiceConnectTransportLayerSecurity
の代わりにAmazonECSInfrastructureRolePolicyForVpcLattice
をアタッチする必要がありそうです。
この後、インフラストラクチャロールをECSで利用するために、操作するユーザにはiam:PassRole
の権限が必要になります。
VPCの設定
続いてVPCの設定を行います。先ほど作成したVPC情報を入力していきます。サブネットは作成したパブリックサブネットを選択します。
セキュリティグループは後からでも修正可能ですが、自端末のIPアドレスからのHTTPアクセスを許可するインバウンドルールを設定します。(後ほどnginxコンテナを立ち上げてアクセスするためHTTPを許可しています)
改めて設定する
ここまでで必要な設定は完了し、クラスターを作成しようとしたのですが、エラーが発生しました。
Resource handler returned message: "Invalid request provided: You are not authorized to perform this operation. User: arn:aws:sts::【AWSアカウントID】:assumed-role/ecsInfrastructureRole/ECSManagedInstances is not authorized to perform: ec2:DescribeSubnets because no identity-based policy allows the ec2:DescribeSubnets action (Service: Ec2, Status Code: 403, Request ID: 3a128192-2c2a-4753-9fca-da3cfbd8cf7a) (SDK Attempt Count: 1)" (RequestToken: 99ff4c5f-7d0b-7f07-a4ee-b31e54b4d9c3, HandlerErrorCode: InvalidRequest)
どうやらインフラストラクチャロール(ecsInfrastructureRole)にec2:DescribeSubnets
の権限がないとのことです。
ec2:DescribeSubnetsが含まれているAmazonEC2ContainerServiceRoleをアタッチしてみました。
aws iam attach-role-policy \
--role-name ecsInfrastructureRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole
今度は別のエラーでec2:CreateLaunchTemplate
が不足しているとエラーになりました。マネージドインスタンスとはいえ、EC2が動いていますのでECS on EC2で必要な権限は一通り必要だと思われます。
本番では推奨されませんが、検証ということでAmazonECS_FullAccess、AmazonEC2FullAccessをつけることにしました。
aws iam attach-role-policy \
--role-name ecsInfrastructureRole \
--policy-arn arn:aws:iam::aws:policy/AmazonECS_FullAccess
aws iam attach-role-policy \
--role-name ecsInfrastructureRole \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess
これらのポリシーをアタッチすることで無事にECSクラスターの作成が完了しました。
ECSタスク定義を作成する
起動タイプは「マネージドインスタンス」を選択します。ネットワークモードは今回「host」を選択しています。
コンテナ1ではnginx:latestからコンテナイメージを取得し、起動するためのイメージURIを入力します。
ログ収集コンテナ
ログ記録では、ログ収集の使用にチェックを入れた上で、「AWS FireLens経由でS3にログをエクスポートする」を選択します。
キーと値は以下のように設定します。(Nameはデフォルトでs3が入ると思います)
キー | 値 |
---|---|
region | (S3バケットがあるリージョン、ここではap-northeast-1) |
bucket | (作成したS3バケット名) |
total_file_size | 1M(デフォルト) |
upload_timeout | 1m(デフォルト) |
use_put_object | On |
今回は設定していませんが、必要に応じてs3_key_format
を設定することで、S3のパス形式を指定可能です。例えばAthena等で分析を行う際はs3_key_format
の設定もしておいた方が良いでしょう。
ログルーター(FireLens)自体のコンテナも設定します。このコンテナのログ収集はCloudWatchにします。
ここまででタスク定義は作成完了ですが、作成されたECSタスクロール(ecsTaskExecutionRole
)にはS3にオブジェクトをPUTする権限がついていないのでAmazonS3FullAccess
付与します。ここも本来は権限を絞った方が良いです。
タスクを起動する
キャパシティープロバイダ戦略を選択しないと、マネージドインスタンスでは起動出来なさそうです。
ネットワーキングはクラスター作成時の設定が入っているので、変更不要です。
必要なタスク数を1にした上で、いざ起動!
動作確認
IPアドレスはEC2のコンソールから確認します。(ネットワークモードがawsvpcではECSタスクにはパブリックIPが振られていないようでした(=ネットワークモードをhostにした理由))
ECSクラスター作成時、「ECSのデフォルトを使用」を選択すると、画像の通りm7a.mediumインスタンスで立ち上がりました。
このIPにHTTPでアクセスすると、nginxの画面が表示されます。
そしてS3のコンソールに行くとログが記録されていることを確認できます。
ログもしっかり記録されています。
{"date":"2025-10-16T14:34:09.782489Z","log":"【送信元IP】 - - [16/Oct/2025:14:34:09 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36\" \"-\"","container_id":"9774889e8bfc47488ab6acd664e9f88e-2531612879","container_name":"nginx","source":"stdout","ecs_cluster":"alchemy-ecs-cluster","ecs_task_arn":"arn:aws:ecs:ap-northeast-1:124878107919:task/alchemy-ecs-cluster/9774889e8bfc47488ab6acd664e9f88e","ecs_task_definition":"alchemy-ecs-task-definition:3"}
補足
これまではAWS for Fluent Bit自体は、Fluent Bit 1.9.10までしかサポートされていなかったようですが、AWS for Fluent Bit 3.0.0が最近(2025/10/14)リリースされ、Fluent Bit 4.1.1をサポートしているようです!
まとめ
初めてFireLens/Fluent Bitを触ってみましたが、想像していたよりも容易に設定ができました。また、マネージドインスタンスでのECSタスク起動も経験できました。今後ECSでコンテナを立ち上げる際の参考にしたいと思います。
参考
記事を書くきっかけになったスライド
インフラストラクチャロールとインスタンスプロファイル関連