はじめに
この記事ではEC2 HostingのECSにデプロイしたアプリケーションのログをSplunkにインデックスする方法についての記事を書きます
Fargateについては別の記事に書きます
概要
ECSのログはコンテナごとにLog Driverを選択することでログの出力先を指定できます
Splunkにはre:Invent 2019で発表された FireLens を使ってログを送ります
log_routerはFluentdです(Fluent Bitじゃないよ)
Log DriverにSplunkを指定することもできますが、あえてFireLensのfluentdを使います
理由は↓
- fluentdを使うことでSplunkが障害やメンテナンスで落ちてるときに再送してくれる
- JavaのStack Traceのような複数行のログイベントも1イベントとしてまとめてくれる
Splunk log driverはこのようなメリットの裏返しのデメリットがあります
HTTP Event Collectorに直接HTTP POSTするだけなので、再送処理はしてくれません
また、デフォルトでログがJSON形式になってしまいます
Dockerコンテナ内のログをSplunkに入れてみた を参考にログを強引にいい感じの形式にしても、複数行のログをまとめることはできないのです
Splunkで props.conf
や transforms.conf
でなんとかしようとしても、HTTP POSTで1行ずつ送ってくるっぽいので、どうしようもありません
うーん、過去の自分の記事を否定してるみたいでやだな
ということで、この ドキュメント(いちおう公式) を参照しながら設定しました
設定方法
以下の手順で設定します
1. SplunkでHTTP Event Collectorを有効化
設定方法は ここらへんの記事 を参考にしてください
2. log_routerコンテナ追加
ログを取りたいサービスが入っているタスク定義に log_router
コンテナを追加して登録します
- cpu: 0
environment: []
essential: true
firelensConfiguration:
type: fluentd
options:
config-file-type: s3
config-file-value: arn:aws:s3:::mybucket/fluent.conf
image: splunk/fluentd-hec:1.2.0
logConfiguration:
logDriver: awslogs
options:
awslogs-group: /ecs/kikeyama-services
awslogs-region: us-west-2
awslogs-stream-prefix: ecs
memoryReservation: 100
mountPoints: []
name: log_router
portMappings: []
user: '0'
volumesFrom: []
# タスク定義を登録
aws ecs register-task-definition --cli-input-yaml file://./kikeyama-services-task.yaml
ポイントは↓
- コンテナイメージは
splunk/fluentd-hec:1.2.0
を指定 -
firelensConfiguration
でS3からfluentdの設定ファイルをとってきているところ(以下抜粋)
firelensConfiguration:
type: fluentd
options:
config-file-type: s3
config-file-value: arn:aws:s3:::mybucket/fluent.conf
オプションとして、log_routerそのもののログをCloudWatch Logsに送ってます
うまくいかなかったとき用のトラブルシューティングとしてね
3. Fluentd設定ファイルを作成してS3に保存
以下のファイルを作成してタスク定義に指定しているS3バケット、パスにアップロードします
<system>
log_level info
</system>
<filter **spring-sfx-demo**>
@type concat
key log
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
use_first_timestamp true
</filter>
<match **>
@type relabel
@label @SPLUNK
</match>
<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>
ポイントは↓
- ラベル
@SPLUNK
でsplunk_hec
プラグインを利用 -
<fiter xxxxx>
でコンテナごとにconcat
を使ってmultiline_start_regexp
でログイベントの最初の文字を正規表現で指定して複数行ログも取り込み可能に
といったところです
今回はJava Spring Bootで作った spring-sfx-demo
という名前のコンテナのアプリケーションのログを取得します(filter
で指定してる名前ね)
@SPLUNK
ラベル内の <SPLUNK_XXXX>
については適宜自分の環境の値を入れてください(<
>
は要らないよ)
では、このファイルをS3にアップロードしましょう
4. サービスを更新
ECSのサービスを更新して上記ステップ2.で登録したタスク定義を指定しましょう
これでログはSplunkに送信されます
Splunkでログを確認
ちゃんと複数行のStack Traceも1ログイベントにまとまってますね
今気づいたけどデフォルトでは日付時刻の抽出がちゃんとできてないですね
fluent.conf でちゃんとparseする必要がありますが忘れてました
さいごに
fluentdを使ったのはほぼ初めてなのでけっこう苦戦しました
もう少し設定をちゃんとする余地はあるものの、とりあえずログは取れてるのでヨシとしましょう
タイムスタンプのparseについては、気が向いたら対応します
Fargateは若干クセがあったので、ECSと全く同じというわけにはいかなかったです
それについては後日別の記事に書きます乞うご期待