オートスケール環境ではEC2の起動、停止が動的に行われるのでログ(syslogやアプリ、ミドルウェア)を外部に出す必要があります。
やり方として
- S3にアップロード
- CloudWatchLogsを使う
- ログサーバーに転送
などが一般的だと思います。
S3にアップロードする方法を考えた場合、どのようなフォルダ構成でアップロードするかは結構大切なことだと思います。(探しずらいとあとで大変)
また、本番環境、検証環境などがある場合、どこにどうおくかをEC2のタグの情報を利用して考えたい場合もあると思います。
そこで今回はEC2のログをfluentdを使ってmetadataやタグ情報を利用したフォルダ構成でS3にアップロードすることをやってみました。
今回の例では/var/log/messagesをS3に以下の構成でアップロードするようにしてみました。
Bucket
│
├-Env(production,staging,development)
│ └─HostName
| └─Year
| └─Month
| └─Day
│ │
│ └─syslog.messages-2015-08-15-09_0.gz
環境、ホスト名、年、月、日でディレクトリが切られ、その下に時間ごとのログが圧縮されたものが配置されます(時間のあとの数字はシーケンシャル番号)
fluentdの設定を増やせばそれ以外のログのアップロードも当然可能です。
環境
- Amazon Linux AMI 2015.03 (HVM)
- td-agent 0.12.12
参考
利用するfluentdのプラグイン
今回は以下3つのfluentdのプラグインを利用しました。
EC2のmetadataを利用できるプラグイン
takus/fluent-plugin-ec2-metadata
ログをS3へアーカイブして送るプラグイン
hostnameコマンドの結果の展開やタグの分解と展開ができるプラグイン
tagomoris/fluent-plugin-forest
EC2へ設定するIAMロール
fluentdからS3への書き込み及びEC2のタグ情報を取得するため、以下の権限を持ったIAMロールを事前に作成しておきます。
- S3への書き込み権限
- EC2のdescribeInstancesAPIの利用(EC2のタグはmetadataでは取れず、describeInstancesで取得する必要があるので)
起動するEC2の設定
先ほど作成したIAMロールを付与します。
また、今回の例ではタグを以下のように設定。
- key=Name, Value=fluentd-test
- Key=Env, Value=production
Envではサーバーの環境を示してproduction,staging,developmentなどを指定するイメージ。
EC2の時刻設定
AmazonLinuxではデフォルトの時間がUTCとなっているのでJSTに変更します。
$sudo cp /etc/localtime /etc/localtime.old
$sudo cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
ZONE="Asia/Tokyo"
今回は/var/log/messagesの変更をしたいのでsyslogを再起動します(再起動しないとタイムゾーンが変更前のままでロギングされる)
$sudo service syslog restart
flunetdのインストール
$curl -L http://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sudo sh
$sudo chkconfig --add td-agent
プラグインの追加
$sudo /opt/td-agent/embedded/bin/fluent-gem install fluent-plugin-ec2-metadata
$sudo /opt/td-agent/embedded/bin/fluent-gem install fluent-plugin-s3
$sudo /opt/td-agent/embedded/bin/fluent-gem install fluent-plugin-forest
ec2-metadataプラグインの確認
Github記載の通りの形で試してみる
<source>
type forward
</source>
<match foo.**>
type ec2_metadata
output_tag ${instance_id}.${tag}
<record>
hostname ${tagset_name}
instance_id ${instance_id}
instance_type ${instance_type}
az ${availability_zone}
vpc_id ${vpc_id}
</record>
</match>
<match **>
type stdout
</match>
td-agentをトレースモードで起動
$td-agent -vv &
fluent-catを使って試してみる
$echo '{"json":"message hello ec2"}' | /opt/td-agent/embedded/bin/fluent-cat foo.bar
2015-08-13 08:25:50 +0000 [trace]: plugin/in_forward.rb:194:initialize: accepted fluent socket from '127.0.0.1:44238': object_id=26543580
2015-08-13 08:25:50 +0000 i-3d9d08cf.foo.bar: {"json":"message hello ec2","hostname":"fluentd-test","instance_id":"i-3d9d08cf","instance_type":"t2.micro","az":"ap-northeast-1a","vpc_id":"vpc-c406dea1"}
2015-08-13 08:25:50 +0000 [trace]: plugin/in_forward.rb:262:on_close: closed socket
[ec2-user@ip-172-31-22-152 td-agent]$ 2015-08-13 08:25:50 +0000 fluent.trace: {"message":"accepted fluent socket from '127.0.0.1:44238': object_id=26543580"}
2015-08-13 08:25:50 +0000 fluent.trace: {"message":"closed socket"}
無事タグ情報が取得できています!
fluentdの停止
$ps aux|grep ruby|awk '{print $2;}'|sudo xargs kill -KILL
/var/log/messageの送信をやってみる
以下になるように設定します。
Bucket
│
├-Env(production,staging,development)
│ └─HostName
| └─Year
| └─Month
| └─Day
│ │
│ └─syslog.messages-2015-08-15-09_0.gz
{Bucket}/production/ip-172-31-20-54/2015/08/14/syslog.messages-2015-08-14-11_0.gz
という感じ。
対象ログをtd-agentで読み取れるようにします。
$sudo chgrp td-agent /var/log/messages
$sudo chmod g+rx /var/log/messages
また、以下のように設定します。
<source>
type tail
format syslog
pos_file /tmp/syslog.pos
path /var/log/messages
tag syslog.messages
</source>
<match syslog.**>
type ec2_metadata
output_tag ${tagset_env}.${tag}
<record>
env ${tagset_env}
</record>
</match>
<match {production,staging,development}.**>
type forest
subtype s3
<template>
s3_bucket toshihirock-fluentd-test
s3_region ap-northeast-1
buffer_path /var/log/td-agent/buffer/${tag}
time_slice_format ${tag_parts[0]}/${hostname}/%Y/%m/%d/${tag_parts[1..-1]}-%Y-%m-%d-%H
flush_at_shutdown true
</template>
</match>
- sourceで/var/log/messagesを読み込み
- 一つ目のmatchでEC2のタグ情報(Envで指定した内容)を取得し、fluentdのタグに追加
- 2つ目のmatchでS3へのアップロードを実施。time_slice_formatでfluentdのタグの情報やhostnameの値を取得してディレクトリ構成に利用
ec2_metadataプラグインの指定部分のrecordの記述はいらない気がしますが、現在はtagset_xxxというものをoutput_tagで使う場合、recordにも入れないとダメなようなので入れています。(対応するプルリク送ってみました)
これでサービス起動し、適当に待てばいい感じにS3にアップロードされています。
$sudo service td-agent start
まとめ
EC2のログアップロードはAWS運用で避けられない作業な気がしますが、適当にするとあとあと大変なので予めやり方を確立しておくと良いと思います。
今回紹介したfluentdのやり方であれ導入障壁も少なく、ディレクトリ構成もある程度好きな感じにできるので実用的だと思います。
20150818追記
上記プルリクエストががマージされました!ありがとうございます!