ECS FargateのログをSplunkに送る


はじめに

先日、ECS (EC2タイプ) のログをSplunkに送る記事 を書きました
今回はFargateにデプロイしたアプリケーションコンテナのログをSplunkに送る方法について書きます

EC2 ECSとはちょっと勝手が違うためハマった点や注意点について書いていきます

概要

FargateもEC2 ECSと同様にSplunkのLog Driverが利用可能ですが、再送処理だったり複数行のログの扱いだったりで、自分の思い通りにログをとれないことがあったので FireLensFluentd でログをSplunkに送ります

設定方法

以下の手順で設定します

1. SplunkでHTTP Event Collectorを有効化

設定方法は ここらへんの記事 を参考にしてください

2. log_routerコンテナ追加

今回はJava Spring Bootのデモ用アプリケーションを適当に作ってFargateにデプロイしてみます
ログを取りたいサービスが入っているタスク定義に log_router コンテナをFireLensのサイドカーとして追加して登録します

kikeyama-services-fargate-task.yaml
containerDefinitions:
- cpu: 0
  dependsOn:
  - condition: START
    containerName: log_router
  dockerLabels:
    app: spring-sfx-demo
  essential: true
  image: ************.dkr.ecr.**-****-*.amazonaws.com/kikeyama-spring-sfx-demo:latest
  logConfiguration:
    logDriver: awsfirelens
    options:
      '@label': '@CONCAT'
      '@type': relabel
  memoryReservation: 512
  mountPoints: []
  name: kikeyama-spring-sfx-demo
  portMappings:
  - containerPort: 8080
    hostPort: 8080
    protocol: tcp
  volumesFrom: []
- cpu: 0
  environment: []
  essential: true
  firelensConfiguration:
    type: fluentd
    options:
      config-file-type: file
      config-file-value: /mnt/fluent.conf
  image: splunk/fluentd-hec:1.2.0
  logConfiguration:
    logDriver: awslogs
    options:
      awslogs-group: /ecs/kikeyama-sfx-demo-services-fargate
      awslogs-region: **-****-*
      awslogs-stream-prefix: fargate
  mountPoints:
  - containerPath: /mnt
    readOnly: true
    sourceVolume: efs_volume
  name: log_router
  portMappings: []
  user: '0'
  volumesFrom: []
cpu: '1024'
executionRoleArn: arn:aws:iam::************:role/fargateTaskExecutionRole
family: kikeyama-sfx-demo-services-fargate
memory: '2048'
networkMode: awsvpc
placementConstraints: []
requiresCompatibilities:
- FARGATE
volumes:
- efsVolumeConfiguration:
    authorizationConfig:
      iam: DISABLED
    fileSystemId: fs-********
    rootDirectory: /
    transitEncryption: DISABLED
  name: efs_volume
# タスク定義を登録
aws ecs register-task-definition --cli-input-yaml file://./kikeyama-services-fargate-task.yaml

ECSとの違い

1. Fargateでは config-file-type にS3を指定できない

FargateではFluentdの設定ファイル fluent.conf をS3から取得できないので、EFSでマウントしたファイルシステムから読み込みます
今回はS3に配置したfluent.confをDataSync通してEFSに同期しました
なので、設定の変更はS3にアップロードしてDataSyncを動かして反映します
aws CLIで処理できるので楽でした

ここらへんの設定は本題から外れてしまうので割愛しますが、ヒマなときにでも記事を書くかもしれません
といってもAWS関連は他の方がたくさん記事書いてるので、ググればいろいろ情報出てくるんだけどね

2. FargateではLog Driverのオプションに @type 指定必須

これはかなり悶々とハマりました
アプリケーションコンテナの↓の部分です

アプリケーションコンテナのログ設定抜粋
  logConfiguration:
    logDriver: awsfirelens
    options:
      '@label': '@CONCAT'
      '@type': relabel

ちなみに @type ブランクにしたら↓のメッセージで怒られました

2020-07-10 05:38:36 +0000 [info]: parsing config file is succeeded path="/fluentd/etc/fluent.conf"
2020-07-10 05:38:36 +0000 [error]: config error file="/fluentd/etc/fluent.conf" error_class=Fluent::ConfigError error="Unknown output plugin ''. Run 'gem search -rd fluent-plugin' to find plugins"

EC2 ECSの場合は options 省略可だったのですけどね

ECSの場合はoptions省略可
  logConfiguration:
    logDriver: awsfirelens

この制約に伴って、fluent.confも少しEC2 ECSとは違ってきます

fluent.conf
<system>
  log_level info
</system>

<label @CONCAT>
  <filter **spring-sfx-demo**>
    @type concat
    key log
    #stream_identity_key container_id
    stream_identity_key stream
    multiline_start_regexp /^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3}/
    flush_interval 5s
    timeout_label @SPLUNK
    #separator ""
    use_first_timestamp true
  </filter>

  <match **>
    @type relabel
    @label @SPLUNK
  </match>
</label>

<label @SPLUNK>
  <match **>
    @type splunk_hec
    protocol SPLUNK_HEC_SCHEME(http|https)
    hec_host SPLUNK_HEC_HOST
    hec_port SPLUNK_HEC_PORT
    hec_token SPLUNK_HEC_TOKEN
    index SPLUNK_INDEX
    host_key ec2_instance_id
    source_key ecs_cluster
    sourcetype_key ecs_task_definition
    insecure_ssl true
    <fields>
      container_id
      container_name
      ecs_task_arn
      source
    </fields>
    <format>
      @type single_value
      message_key log
      add_newline false
    </format>
  </match>
</label>

<label @ERROR>
  <match **>
    @type relabel
    @label @SPLUNK
  </match>
</label>

何が違うかっていうと、 <filter><match> をlabel @CONCAT で括ってるんですね
タスク定義で @type 指定する必要があったので、 relabel としてこの @CONCAT の処理をさせてます

Fluentd初心者なのでここらへんちょっと苦労しました

あとはこの設定ファイルをS3に置いてDataSync動かすだけです

3. サービス更新

ステップ2で作成したタスク定義を指定してサービスを動かせば、Java SpringのログはSplunkに送られます

Splunkでログ確認

ということでSplunkにログが送られてきてるのを確認できました
複数行のログもまとまってます

さいごに

ドキュメント にしたがって設定したのですがLog Driverのオプションに @typ 必須というところは記載がなく、何度ドキュメント通りに設定しても原因不明のエラーになってファッ!?となってました
かなり苦戦しました

とはいえ、前回の記事 も含めてECSはEC2タイプもFargateもログをSplunkに送って無事検索したり可視化できるのでひと安心です