AWS ECS(Fargate)で動作しているAPPのログをCloudWatchLogsとS3の2箇所に流す方法についてのメモ書きです。
構成は次のようなイメージです。
ECS ─> awsfirelens ─> fluentbit ─> CloudWatchLogs
└───> Kinesis Data Firehose ─> S3
ECSタスクの定義
FARGATEで動作するECSタスクを以下のように定義します。
name
にはコンテナの名前を設定します。
ログの出力元となるAPPのコンテナ名をapp
としています。
また、APPログを受け取り、各AWSサービスにログを流すコンテナ名をlog_router
とします。
{
"containerDefinitions": [
{
"name": "app",
"cpu": 0,
"environment": [],
"essential": true,
"image": "123456789123.dkr.ecr.ap-northeast-1.amazonaws.com/dev/APP",
"linuxParameters": {
"initProcessEnabled": true
},
"logConfiguration": {
"logDriver": "awsfirelens",
"options": null,
"secretOptions": null
},
"portMappings": [{"containerPort": 8000, "hostPort": 8000, "protocol": "tcp"}
]
},
{
"name": "log_router",
"cpu": 0,
"user": "0",
"environment": [],
"essential": true,
"firelensConfiguration": {
"options": {
"config-file-type": "file",
"config-file-value": "/fluent-bit/etc/extra.conf"
},
"type": "fluentbit"
},
"image": "123456789123.dkr.ecr.ap-northeast-1.amazonaws.com/dev/aws-fluentbit:latest",
"mountPoints": [],
"portMappings": [],
"volumesFrom": []
}
],
"family": "app-task-definition",
"requiresCompatibilities": ["FARGATE"],
"networkMode": "awsvpc",
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws:iam::123456789123:role/ecs-task-execution-role",
"taskRoleArn": "arn:aws:iam::123456789123:role/ecs-api-task-role",
"placementConstraints": [],
"runtimePlatform": {
"cpuArchitecture": "X86_64",
"operatingSystemFamily": "LINUX"
},
"tags": [],
"volumes": []
}
appコンテナには、awsfirelensモジュールを設定します。
FireLens とは ECSで使用できるモジュールで、Fluentd やFluent Bit と連携することで、ECSから出力されるログを AWS のサービスや AWS パートナーネットワークの宛先にルーティングし、ログを保存、分析することができます。
FireLensは次の箇所で設定しています。
"name": "app",
# 中略
"logConfiguration": {
"logDriver": "awsfirelens",
"options": null,
"secretOptions": null
},
ログ出力先が1箇所であれば、options
の設定でログ出力先のAWSサービスを指定できますが、今回は2箇所に出力したいので、別の設定ファイルで出力先を設定します。
※未検証ですが、options
で指定した設定がlog_router
であるfluentbitの/fluent-bit/etc/fluent-bit.conf
ファイルの設定に反映されていそうです。
次にFireLensから流れたログをfluentbit(コンテナのlog_router
)に渡すための設定を確認します。
"name": "log_router",
# 中略
"firelensConfiguration": {
"options": {
"config-file-type": "file",
"config-file-value": "/fluent-bit/etc/extra.conf"
},
"type": "fluentbit"
},
"image": "123456789123.dkr.ecr.ap-northeast-1.amazonaws.com/dev/aws-fluentbit:latest",
firelensConfiguration
を設定することで、コンテナのイメージ内にあるファイル/fluent-bit/etc/extra.conf
をfluent-bit.confの追加設定ファイルとして読み込ませることができます。
fluent-bit.confはログの出力先サービスを設定できるファイルとなります。
ここで設定したextra.conf
を読み込めるようにするには、AWS専用のfluent-bitのコンテナイメージaws-for-fluent-bitを若干修正して、そのイメージをECRにアップロードする必要があります。
上記のimage
の設定はそのイメージをECRから読み込んだものとなります。
IAM権限
タスク定義で設定しているロール"taskRoleArn": "arn:aws:iam::123456789123:role/ecs-api-task-role"
に、CloudWatchlogsとFirehoseにアクセスするための権限を付与する必要があます。
・CloudWatchLogsFullAccess
(AWS管理ポリシー)
・AmazonS3FullAccess
(AWS管理ポリシー)
・FirehosePutRecord
(カスタムポリシー)
# FirehosePutRecord ポリシーの内容
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"firehose:PutRecordBatch"
],
"Resource": "*"
}
]
}
コンテナイメージaws-for-fluent-bitの修正
コンテナイメージaws-for-fluent-bit
を修正して、ログ送信先のAWSサービスを設定します。
まず、適当なプロジェクトを作成して、次のようにファイルを作成します。
.
├── Dockerfile
└── extra.conf
Dockerfileは次のように設定します。
aws-for-fluent-bitのイメージをDocker hub
から読み込んで、そのイメージ上にextra.confを配置するだけというシンプルな内容です。
# Dockerfile
FROM amazon/aws-for-fluent-bit:2.28.2
COPY ./extra.conf /fluent-bit/etc/extra.conf
次にextra.confの設定です。
NameにAWSのサービス名を指定することで、そのサービスにログを流すことができます。
※ここにサービス名を指定することでaws-for-fluent-bit
内の対象プラグインを呼び出す仕様となっているようです。
[OUTPUT]
Name cloudwatch
Match **
region ap-northeast-1
log_group_name app-logs
log_stream_prefix app-log-
auto_create_group true
[OUTPUT]
Name firehose
Match **
region ap-northeast-1
delivery_stream S3-Delivery-Stream-app-logs
cloudwatchについてです。
region
にはログ出力対象のリージョンを指定します。
log_group_name
には、cloudwatchLogsに作成する(もしくは作成済みの)ロググループ名を指定します。
auto_create_groupをtrue
にしておくと、指定したロググループ名が存在しなくても、log_group_nameに指定した名前でロググループを作成してくれます。(fluentbitマニュアル)
firehoseについては、region
についてはcloudwatchの設定と同様で、delivery_streamについては、すでに作成してある、Amazon Data Firehose のFirehose ストリーム(※以前は配信ストリームという名称)の名前を指定することで、kinesisにログデータを流すことができるようになります。
Firehose ストリームの作成方法についてはこちらのAWSマニュアルが参考になります。
今回の例では、app-logs-bucket
というバケットを作成して、Firehose ストリームに設定します。
余談ですが、AWS kinesisのFirehose ストリームのS3 バケットプレフィックス
を設定すると、S3のフォルダをバケット名/YYYY/MM/DD
といった形にして、日付ごとにログローテーションを行うことができます。
下記はその設定例です。
# S3 バケットプレフィックス - オプション
!{timestamp:yyyy/MM/dd}/
# S3 バケットエラー出力プレフィックス - オプション
!{firehose:error-output-type}/!{timestamp:yyyy/MM/dd}/
その他の設定が行いたい場合はこちらのAWSマニュアルが参考になります。
このマニュアルに従ってFirehose ストリームを作成するとおそらくIAMロールが原因でエラーとなります。
その場合はこちらの記事の内容を参考に対応します。【Amazon Kinesis】配信ストリーム作成時のエラー
コンテナイメージをECRにPush
続いて、作成したイメージをECRにpushします。
pushの方法についてはこちらのサイトを参考にさせて頂きました。
まずは以下のようなECRリポジトリを事前に作成します。
作成したECRリポジトリに対して、AWSマネージメントコンソールから<対象リポジトリ> --> 許可 --> ポリシーJSONの編集
にアクセスして次の権限を付与してください。
< xxx >
の箇所(5行目と8行目)は自身の環境にあったものに書き換えます。
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "<任意のSID>",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::< imageをpullしてきたい環境のaccount-id >:root"
},
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer"
]
},
]
}
次に、作成したDockerファイルのあるディレクトリで下記ビルドコマンドを実行します。
# ビルド
docker image build -t aws-for-fluent-bit-extra . --no-cache
AWSのCLIにログインして状態で、Dockerにログインするコマンドを実行します。
AWSのcredentialsファイルで個別にプロファイルを管理している場合はaws ecr
コマンドのオプションに--profile プロファイル名
を追加で設定する必要があります。
コマンド内の--region
の設定値や、アカウントID (下記123456789123の部分)は自身の環境にあったものに修正してください。
# login
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789123.dkr.ecr.ap-northeast-1.amazonaws.com
ECRへプッシュするコンテナイメージのタグ付けを行います。
# タグ付け
docker tag aws-for-fluent-bit-extra:latest 123456789123.dkr.ecr.ap-northeast-1.amazonaws.com/dev/aws-for-fluent-bit-extra:latest
タグ付けが上手くいっていれば次のコマンドでECRにイメージがpushされます。
# push
docker push 123456789123.dkr.ecr.ap-northeast-1.amazonaws.com/dev/aws-for-fluent-bit-extra
# push 成功例
12669cbeacc7: Pushed
15435cf07f8c: Pushed
56c5e96f5fe1: Pushed
b0fc75156d6d: Pushed
7f30cde3f699: Pushed
fe810f5902cc: Pushed
dfd8c046c602: Pushed
4fc242d58285: Pushed
latest: digest: sha256:1234560b64c195d742c60bed0444f7abe24f0d0920cc07f02ef5fc1fe524450b size: 4280
pushされたイメージがイメージタグlatest
として登録されています。
新しいタグがpushされると前回latest
だったイメージタグは<untagged>
に変更されます。
ログ出力確認
一通りの設定は済んだので、最後にログが出力されるか確認します。
最初に設定したECSの定義を元にデプロイを行い、AWS環境で自身のAPPを実行します。
その後下記を確認してログが出力されていればOKです。
CloudWatch --> ロググループ --> app-logs --> ログストリーム
にAPPのログが出力されていること。
S3バケットapp-logs-bucket
にAPPのログが出力されていること。