はじめに
ECSで稼働するコンテナは、awslogsというログドライバーを有効化することで標準出力がCloud Watch Logsに連携されます。
簡易的な使い方であればこれでいいものの、より細かい用件でログルーティングを行う場合は不十分であり、代わりにFirelensコンテナを利用した構成を取る必要があります。
本記事ではコンテナ内のディレクトリを指定し、そのディレクトリ配下のログをファイル毎にログストリームを分けて出力する方法について解説します。
環境情報
- ECS Fargate 1.4
- aws-cli/2.15.5
- Fluent Bit v1.9.10
実装の流れ
FirelensとはOSSのFluentdをベースにした製品であり、ログを収集したいコンテナと同一タスクで動かす必要があります。
そのため、タスク定義(Task Definition)にてFirelensの情報を記載する必要があります。また、記載する際のポイントとしてログボリュームの共有が必要です。
要はFirelensコンテナがログを出力するコンテナのログにアクセスできるようにします。今回はApacheのログを想定して以下のディレクトリを指定しました。
"mountPoints": [ { "sourceVolume": "log_directory", "containerPath": "/var/log/httpd" } ]
Firelensのコンテナイメージの作成
設定用ファイルを用意し、それをコンテナイメージの中に配置します。INPUTにてPathの場所を正規表現のアスタリスクで抽出し、そのパス名を変数にしてOUTPUTで渡しています。
[INPUT] Name tail Tag tail.app_logs.* Path /var/log/httpd/* Path_Key application_log_file_path Read_from_Head true [OUTPUT] Name cloudwatch_logs Match tail.app_logs.* Region ap-northeast-1 log_group_name xx log_stream_prefix xx auto_create_group true log_group_template /xx/xx log_stream_template $application_log_file_path
タスク定義
今回の設定に関連する箇所を抜粋しながら解説します。
{ "taskDefinitionArn": "xx", "containerDefinitions": [ { "name": "apache", "image": "xx.ecr.ap-northeast-1.amazonaws.com/xx",... "mountPoints": [ { "sourceVolume": "log_directory", "containerPath": "/var/log/httpd" } ], "volumesFrom": [], "logConfiguration": { "logDriver": "awsfirelens", "options": { "region": "ap-northeast-1", "auto_create_group": "true", "Name": "cloudwatch" } },
mountPointsでFirelens側に見せたいパスを指定し、logConfigurationのlogDriverにて"awsfirelens"を設定します。
続いてFirelensのコンテナ側。
{ "name": "log_router", "image": "xx.ecr.ap-northeast-1.amazonaws.com/xx", ... "mountPoints": [ { "sourceVolume": "log_directory", "containerPath": "/var/log/httpd" } ],... "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "log_router_group", "awslogs-create-group": "true", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "test" } }, .. "firelensConfiguration": { "type": "fluentbit", "options": { "config-file-type": "file", "config-file-value": "/fluent-bit/etc/extra.conf" } ... "volumes": [ { "name": "log_directory", "host": {} } ], ...
mountPointsは同じパスを指定し、firelensConfigurationにてコンテナイメージ内に配置した追加設定ファイルのパスを設定します。
また、全体の設定箇所にてvolumesに関する記述を行います。
動作確認
この状態でタスクを起動すると、Firelens側のログにとしてログストリームが作成されるメッセージが出力されます。
[ info] [output:cloudwatch_logs:cloudwatch_logs.0] Creating log stream /var/log/httpd/access_log in log group xx log_router
ここでCloudWatchLogsのLog streamsを確認すると以下のようなログストリームが確認でき
/var/log/httpd/access_log
/var/log/httpd/error_log
中を見るとJSON形式でログが連携されていました。
{ "application_log_file_path": "/var/log/httpd/access_log", "log": "xx - - [... +0000] \"GET /test/ HTTP/1.1\" 200 14 \"-\" \"ELB-HealthChecker/2.0\"", "ecs_cluster": "xx", "ecs_task_arn": "arn:aws:ecs:ap-northeast-1:xx:task/xx/xx", "ecs_task_definition": "xx:xx" }
追加検証
Apacheコンテナの中に入って設定しているディレクトリ配下を確認すると以下のようになっています。
# ls access_log error_log sh-4.2# ls -ltr total 32 -rw-r--r-- 1 root root 700 xx error_log -rw-r--r-- 1 root root 24360 xx access_log
ここで手動でファイルを作成し、書き込みを行いました。
sh-4.2# touch test_log sh-4.2# echo HelloWorld >> test_log sh-4.2# ls -ltr total 40 -rw-r--r-- 1 root root 700 xx error_log -rw-r--r-- 1 root root 11 xx test_log -rw-r--r-- 1 root root 27720 xx access_log
するとFirelens側のログに"inotify_fs_add()"と出力され
[ info] [input:tail:tail.3] inotify_fs_add(): inode=561837 watch_fd=3 name=/var/log/httpd/test_log [ info] [output:cloudwatch_logs:cloudwatch_logs.0] Creating log stream /var/log/httpd/test_log in log group ... [ info] [output:cloudwatch_logs:cloudwatch_logs.0] Created log stream /var/log/httpd/test_log
CloudWatchLogs側に出力されました。
{ "application_log_file_path": "/var/log/httpd/test_log", "log": "HelloWorld", "ecs_cluster": "xx", "ecs_task_arn": "xx", "ecs_task_definition": "xx" }
終わりに
ディレクトリ配下のログを出力できるため、ログ出力のために標準出力に変更する必要がない点は本方式のメリットとなります。ただし、ログ自体はコンテナの中で肥大化する可能性があるので、定期的なメンテナンスが必要な点はご注意ください。
以上、ご参考になれば幸いです。