コンテンツにスキップ

FireLens@AWSリソース

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. FireLensの仕組み

アーキテクチャ

fluent-bit_aws-firelens

(1)

awsfirelensドライバーはFluentdログドライバーをラッピングしたものであり、ログをFireLensコンテナに送信する。Fluentdログドライバーについては、以下のリンクを参考にせよ。

(2)

FireLensコンテナは、これを受信する。

(3)

コンテナ内で稼働するFluentBitのログパイプラインのINPUTに渡され、FluentBitはログを処理する。FireLensコンテナのパイプラインでは、ログは『<コンテナ名>-firelens-<AWS ECSタスクID>』というタグ名で処理されている。

# 本来、改行はないが、わかりやすいように改行している。
# <コンテナ名>-firelens-<AWS ECSタスクID>
[0] foo-firelens-*****: [
    *****,
    {
        "log"=>"127.0.0.1 -  01/01/2022:0:00:00 +0000 "GET /index.php" 200",
        "container_id"=>"*****",
        "container_name"=>"foo",
        "source"=>"stderr"
    }
]
(4)

OUTPUTに渡され、FluentBitは指定した外部にログをルーティングする。

FireLensコンテナ

AWSが提供するFluentBitイメージによって作成されるコンテナである。

サイドカーパターンでFluentBitを採用したい場合に、FireLensを採用する。

FireLensコンテナでは、FluentBitがログルーティングプロセスとして稼働する。

FireLensコンテナを使用せずに、ユーザー定義のコンテナを作成して稼働できるが、FireLensコンテナを使用すれば、主要なセットアップがされているため、より簡単な設定でFluentBitを使用できる。


ログルーティング

▼ サイドカーコンテナとして

AWS ECS Fargateのサイドカーコンテナとして配置する必要がある。

Fargateからログを送信すると、コンテナ内で稼働するFluentBitがこれを収集し、これを外部にルーティングする。

作成のための実装例については、以下のリンクを参考にせよ。

▼ ログのルーティング先

FluentBitが対応する宛先にログをルーティングできる。


02. セットアップ

Dockerfile

▼ AWS ECRパブリックギャラリーを使用する場合

AWS ECSタスクのコンテナ定義にて、AWS ECRパブリックギャラリーのURLを指定し、AWS ECRイメージのプルする。

デフォルトで内蔵されているconfファイルの設定をそのまま使用する場合は、こちらを採用する。

▼ プライベートAWS ECRリポジトリを使用する場合

あらかじめ、DockerHubからFluentBitイメージをプルするためのDockerfileを作成し、プライベートAWS ECRリポジトリにコンテナイメージをプッシュしておく。

AWS ECSタスクのコンテナ定義にて、プライベートAWS ECRリポジトリのURLを指定し、AWS ECRイメージのプルする。

デフォルトで内蔵されているconfファイルの設定を上書きしたい場合は、こちらを採用する。

FROM amazon/aws-for-fluent-bit:latest


コンテナ定義

container_definition.jsonファイル

AWS ECSタスクのコンテナ定義にて、アプリコンテナとlog_routerコンテナを設定する。

log_routerという名前以外を設定できないことに注意する。

[
  {
    "name": "foo",
    "image": "<イメージリポジトリURL>:<バージョンタグ>", # <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/<イメージリポジトリ名>:latest
    "essential": "false",
    "logConfiguration": {
        # FluentBitの設定はconfファイルで実行するため、optionsキーは何も設定しない。
        "logDriver": "awsfirelens",
      },
  },
  {
    # log_router以外の名前を設定できない
    "name": "log_router",
    "image": "<イメージリポジトリURL>:<バージョンタグ>", # <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/<イメージリポジトリ名>:latest
    "essential": "false",
    "logConfiguration": {
        # ログドライバー
        "logDriver": "awslogs",
        "options": {
            # FireLensコンテナ自体がAWS CloudWatchログにログアウトプット
            "awslogs-group": "<ログストリーム名>",
            "awslogs-region": "ap-northeast-1",
            "awslogs-stream-prefix": "<ログストリームの接頭辞>",
          },
      },
    "firelensConfiguration": {
        # FireLensコンテナでFluentBitを稼働させる
        "type": "fluentbit",
        "options": {
            "config-file-type": "file",
            # 設定上書きのため読み出し
            "config-file-value": "/fluent-bit/etc/fluent-bit_custom.conf",
            # AWS ECSの情報をFireLensコンテナに送信するか否か
            "enable-ecs-log-metadata": "true",
          },
      },
    "portMappings": [],
    "memoryReservation": 50,
    "environment":
      [
        {"name": "DD_ENV", "value": "prd"},
        {"name": "DD_SERVICE", "value": "foo"},
        {"name": "REGION", "value": "ap-northeast-1"},
      ],
    "secrets": [{"name": "DD_API_KEY", "valueFrom": "DD_API_KEY"}],
  },
]

logConfigurationキーの詳細

項目 説明
type メインコンテナからFireLensコンテナにログを送信できるように、ログドライバーのタイプとして『fluentbit』を設定する。
config-file-type FluentBitの設定ファイルを読み込むために、fileとする。
config-file-value optionsキーにて、ログルーティングを設定できるが、それらはfluent-bit.confファイルにも設定できるため、ルーティングの設定はできるだけfluent-bit.confファイルに実装する。FireLensコンテナ自体のログは、AWS CloudWatchログに送信するように設定し、メインコンテナから受信したログは、ログ監視バックエンド (Datadogなど) にルーティングする。
enable-ecs-log-metadata (デフォルトで有効化) 有効化した場合、Datadogのログコンソールで、例えば以下のようなタグが付けられる。
ecs-meta-data_true
反対に無効にした場合、以下のようなタグが付けられる。
ecs-meta-data_false
- https://tech.spacely.co.jp/entry/2020/11/28/173356
environmentsecrets コンテナ内のfluent-bit.confファイルに変数をアウトプットできるように、コンテナの環境変数に値を設定する。
options FluentBitの設定ファイルでOUTPUTセクションを定義する代わりに、optionsキーからも設定できる。


03. 設定ファイルの種類

設定ファイル一覧

aws-for-fluent-bitイメージの/fluent-bit/etcディレクトリにはデフォルトで設定ファイルが用意されている。

追加設定を実行するファイルはここに配置する。

[root@<コンテナID>:/fluent-bit/etc]$ ls -la

-rw-r--r-- 1 root root  251 Sep  1 17:57 fluent-bit.conf
-rw-r--r-- 1 root root 1564 Sep 27 02:15 fluent-bit_custom.conf # 追加設定用
-rw-r--r-- 1 root root 4664 Sep  1 18:07 parsers.conf
-rw-r--r-- 1 root root  584 Sep  1 18:07 parsers_ambassador.conf
-rw-r--r-- 1 root root  226 Sep  1 18:07 parsers_cinder.conf
-rw-r--r-- 1 root root 2798 Sep  1 18:07 parsers_extra.conf
-rw-r--r-- 1 root root  240 Sep  1 18:07 parsers_java.conf
-rw-r--r-- 1 root root  845 Sep  1 18:07 parsers_mult.conf
-rw-r--r-- 1 root root  291 Sep 27 02:15 parsers_multiline.conf
-rw-r--r-- 1 root root 2954 Sep  1 18:07 parsers_openstack.conf
-rw-r--r-- 1 root root  579 Sep 27 02:15 stream_processor.conf # 追加設定用


/fluent-bit/etc/fluent-bit.conf

fluent-bit.confとは

FireLensコンテナのデフォルトの設定ファイル。

ローカルマシンでFluentBitコンテナを起動した場合と異なる構成になっていることに注意する。

[INPUT]
    Name tcp
    Listen 127.0.0.1
    Port 8877
    Tag firelens-healthcheck

[INPUT]
    Name forward
    unix_path /var/run/fluent.sock

[INPUT]
    Name forward
    Listen 127.0.0.1
    Port 24224

[FILTER]
    Name record_modifier
    Match *
    Record ecs_cluster sample-test-cluster
    Record ecs_task_arn arn:aws:ecs:ap-northeast-1:123456789012:task/sample-test-cluster/d4efc1a0fdf7441e821a3683836ad69a
    Record ecs_task_definition sample-test-webapp-taskdefinition:15

[OUTPUT]
    Name null
    Match firelens-healthcheck


/fluent-bit/etc/fluent-bit_custom.confファイル

fluent-bit_custom.confファイルとは

FireLensコンテナにカスタム値を設定する。

コンテナ定義のconfig-file-valueキーで指定し、追加設定を実行する。

これにより、FireLensコンテナのfluent-bit.confファイルに、カスタムファイルを読み込むためのINCLUDE文が挿入される。

[INPUT]
    Name tcp
    Listen 127.0.0.1
    Port 8877
    Tag firelens-healthcheck

[INPUT]
    Name forward
    unix_path /var/run/fluent.sock

[INPUT]
    Name forward
    Listen 127.0.0.1
    Port 24224

[FILTER]
    Name record_modifier
    Match *
    Record ecs_cluster prd-foo-ecs-cluster
    Record ecs_task_arn arn:aws:ecs:ap-northeast-1:<AWSアカウントID>:task/prd-foo-ecs-cluster/*****
    Record ecs_task_definition prd-foo-ecs-task-definition:1

# fluent-bit.confファイルに、カスタムファイルを読み込むためのINCLUDE文が挿入される。
@INCLUDE /fluent-bit/etc/fluent-bit_custom.conf

[OUTPUT]
    Name laravel
    Match laravel-firelens*

[OUTPUT]
    Name nginx
    Match nginx-firelens*

▼ INPUTセクション

標準出力/標準エラー出力に出力されたログをそのままインプットするために、FireLensコンテナではforwardプラグインを設定する必要がある。

ただし、デフォルトの設定ファイルには、INPUTがすでに定義されているため、fluent-bit_custom.confファイルではINPUTを定義しなくても問題ない。

[INPUT]
    Name        forward
    Listen      0.0.0.0
    Port        24224

[OUTPUT]
    Name cloudwatch
    Match **
    region us-east-1
    log_group_name fluent-bit-cloudwatch
    log_stream_prefix from-fluent-bit-
    auto_create_group true

▼ OUTPUTセクションとプラグイン

AWSやDatadogにルーティングするための設定が必要である。

もしfluent-bit_custom.confファイルでOUTPUTセクションを設定した場合は、awsfirelensログドライバーのoptionsキーは何も設定する必要がない。

"logConfiguration": {
    "logDriver": "awsfirelens",
}

ファイルで設定する代わりに、optionsキーでOUTPUTセクションを設定もできる。

"logConfiguration": {
    "logDriver": "awsfirelens",
    "options": {
       "Name": "datadog",
       "Host": "http-intake.logs.datadoghq.com",
       "TLS": "on",
       "apikey": "<DATADOG_API_KEY>",
       "dd_service": "prd-foo",
       "dd_source": "prd-foo",
       "dd_tags": "env:prd-foo",
       "provider": "ecs"
   }
}

AWSから提供されているベースイメージには、AWSリソースにログをルーティングするためのOUTPUTプラグインがすでに含まれている。

補足として、datadogプラグインはFluentBit自体にインストール済みである。

AWS ECRパブリックギャラリーからプルしたコンテナイメージをそのまま使用する場合と、プライベートAWS ECRリポジトリで再管理してから使用する場合がある。

[root@<コンテナID>:/fluent-bit]$ ls -la

-rw-r--r-- 1 root root 26624256 Sep  1 18:04 cloudwatch.so # 執筆時点 (2023/05/29) でcloudwatch_logsプラグインという名前に変わった模様
-rw-r--r-- 1 root root 26032656 Sep  1 18:04 firehose.so   # kinesis_firehoseプラグイン
-rw-r--r-- 1 root root 30016544 Sep  1 18:03 kinesis.so    # kinesis_streamsプラグイン
...


/fluent-bit/etc/parser.confファイル

parser.confファイルとは

FireLensコンテナで処理中のログのキーの値を修正したい場合、parser.confファイルでPARSERセクションを設定する必要がある。

▼ PARSERセクション

AWS ECSが送信したログ

AWS ECSのプラットフォームバージョンがv1.3.0の時、メタデータのDockerNameは『/ecs-<AWS ECSタスク定義名>-<リビジョン番号>-<コンテナ名>-<通し番号>』になる (例:/ecs-foo-task-definition-1-bar-123456789) 。

これをv1.4.0にアップグレードすればコンテナ名になるが、すぐにアップグレードに対応できないこともある。

その場合はPARSERセクションにて、正規表現の名前付きキャプチャを使用してコンテナ名を抽出すると、以降のセクションで処理しやすくなる。

[PARSER]
    Name      docker-name-parser
    Format    regex
    # 例:/ecs-foo-task-definition-1-bar-123456789
    # 正規表現の名前付きキャプチャを使用する
    Regex     ^\/ecs-.*-(?<container_name>.*)-(.*)$
[SERVICE]
    Parsers_File    parser.conf

[FILTER]
    Name            parser
    Match           *
    Key_Name        container_name
    # 使用するパーサールール
    Parser          docker-name-parser
    # 解析されたキーの元の値を保持するか否か
    Preserve_Key    false
    # 解析されたキー以外を保持するか否か
    Reserve_Data    true

PARSERセクションでコンテナ名を抽出したおかげで、STREAM_TASKのログクエリのWHERE句で指定できるようになる。

# WHERE句でコンテナ名を指定
[STREAM_TASK]
    Name foo-stream-task
    # SELECT句の結果に、WITH句でfooタグを付与し、fooデータストリームを作成する。
    Exec CREATE STREAM foo WITH (tag='foo') AS SELECT log FROM TAG:'*-firelens-*' WHERE container_name = 'foo';


/fluent-bit/etc/parsers_multiline.confファイル

parsers_multiline.confファイル

FireLensコンテナで複数行のログを処理したい場合、parsers_multiline.confファイルでMULTILINE_PARSERを設定する必要がある。

▼ MULTILINE_PARSERセクション

[MULTILINE_PARSER]
    name          laravel
    type          regex
    flush_timeout 1000
    rule          "start_state"   "/(Dec \d+ \d+\:\d+\:\d+)(.*)/"  "cont"
    rule          "cont"          "/^\s+at.*/"                     "cont"
[SERVICE]
    ...
    parsers_file          /parsers_multiline.conf

[FILTER]
    name                  multiline
    match                 *
    multiline.key_content log
    # ファイルを読み込む。ビルトインパーサ (goなど) を使用することも可能。
    multiline.parser      go, laravel


/fluent-bit/etc/stream_processor.confファイル

stream_processor.confファイルとは

ログの作成元のコンテナごとに異なる処理を設定したい場合、stream_processor.confファイルでSTREAM_TASKセクションを定義する必要がある。

▼ STREAM_TASKセクション

FireLensコンテナで処理中のログのタグ名は『<コンテナ名>-firelens-<AWS ECSタスクID>』になっている。

そのため、Stream Processorでログを抽出するためには、クエリで『FROM TAG:'*-firelens-*'』を指定する必要がある。

補足として、STREAM_TASKでタグ付けされたログは、INPUTから再び処理し直される。

*実装例*

# laravelコンテナのログへのタグ付け
[STREAM_TASK]
    Name laravel
    # SELECT句の結果に、WITH句でfooタグを付与し、laravelデータストリームを作成する。
    Exec CREATE STREAM laravel WITH (tag='foo') AS SELECT log FROM TAG:'*-firelens-*' WHERE container_name = 'foo';

# nginxコンテナのログへのタグ付け
[STREAM_TASK]
    Name nginx
    # SELECT句の結果に、WITH句でbarタグを付与し、nginxデータストリームを作成する。
    Exec CREATE STREAM nginx WITH (tag='bar') AS SELECT log FROM TAG:'*-firelens-*' WHERE container_name = 'bar';

# 全てのコンテナのログへのタグ付け
[STREAM_TASK]
    Name containers
    Exec CREATE STREAM container WITH (tag='containers') AS SELECT * FROM TAG:'*-firelens-*';
[SERVICE]
    ...
    Streams_File stream_processor.conf