AWS : Fluentdを使ってEC2からApacheのログをS3へ
月花です。
久しぶりの技術記事です。
最近AWSを触っていて、わかりにくいなあと思ったS3との連携について。
AWSでは、障害が起こったりAutoScalingしてたりすると、EC2インスタンスが勝手にシャットダウンされてしまう。
このとき、ログが吹っ飛ぶのでS3へ逃しておく必要がある。
やりたいこと
アプローチ
まずはどのみちS3へ転送が必要なため、EC2インスタンスそれぞれにS3フルアクセス権限を付与する。
これで、S3への操作権限を得た。このままcpコマンドでコピーすることもできるが、勝手にシャットダウンされて吹っ飛ぶので極めて短い間隔のcronかなにかでcpすることになる。
しかも、都度時間を見て、ディレクトリなければ作るなんてコード書くのめんどくさいし非効率。
そこで Fluentd を用いて、自動化してもらう。
こういうのを、Web Storage Archiveパターン と呼ぶらしい。
CDP:Web Storage Archiveパターン - AWS-CloudDesignPattern
S3へのアクセス権限を与える
まずはIAMロール・・・ではなく、既にEC2インスタンスは動いてしまっているので、IAMユーザを作成する。
サーバ分作ったら(1つでもいいのかしら)、アクセスキーとかをメモしておく。
下記の「AWS CLI を使用してロールを切り替えるには」を参考に、起動中EC2インスタンスに接続し、ユーザを割り当てる。
docs.aws.amazon.com
$ aws configure AWS Access Key ID [None]: your_key_id AWS Secret Access Key [None]: your_sec_key Default region name [None]: ap-northeast-1 Default output format [None]: json
これでアクセス権限を付与できた。
Amazon LinuxにはデフォルトでAWS CLIという、AWSサービスをいじるためのクライアントが搭載されており、S3関連のコマンドは以下の記事に詳しい。
www.task-notes.com
なお、再起動は必要ないので、そのまま叩いてみて、成功なら成功である。失敗したら頑張れ。
NTPを設定する
Amazon LinuxのデフォルトはUTCなので、設定してないと、Fluentdくんが作るファイルを時刻を使って階層化するとき、めちゃくちゃになる。
docs.aws.amazon.com
インスタンスのセキュリティグループのルールでは、ポート 123 (NTP) でアウトバウンド UDP トラフィックを許可する必要があります。ネットワーク ACL のルールでは、ポート 123 でインバウンドとアウトバウンドの UDP トラフィックを両方許可する必要があります。
筆者はこれを忘れてハマった。
Fluentd のインストール
公式ページ
docs.fluentd.org
を参考に、とりあえず入れるだけ入れる。
$ curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sh
こういうインストール方法、めちゃめちゃ助かる。
素のままでも使いやすいっぽいのだが、やりたいことがあるので、Fluentdのプラグインをいれる。
github.com
$ /usr/sbin/td-agent-gem install fluent-plugin-forest
Fluentd の設定
どのファイルをどれくらいの間隔で、どんな名前でどこに転送するのかを定義する。
その定義ファイルは、以下にある。
/etc/td-agent/td-agent.conf
まずは、source節を編集して、どのファイルを対象とするかを定義する。
なお、基本的に末尾に追記で問題ない。
<source> @type tail format apache path /var/log/httpd/access_log pos_file /var/log/td-agent/httpd.access.log.pos tag s3.httpd.access </source>
type | tailにするとtailコマンドで末尾をフォローしてくれる。このタイプによってオプションが変わる。ここから先は全部tailが対象のオプション |
format | 対象とするログのフォーマットを選択する*1 |
path | 対象のログへのフルパス |
pos_file | 前回どこまで読んだかが書いてある栞ファイル。Fluentdが勝手に生成するので、わかりやすい名前にしておく |
tag | ソースごとにタグ付けが行える |
このあと、エラーログを見るsourceも書いておいた。
タグは s3.httpd.error とした。
次に、さきほどのソースを、どれくらいの間隔で、どんな名前で、どこに転送するのかを定義するために、match節を記述する
<match s3.*.*> type forest subtype s3 <template> aws_key_id your_key_id aws_sec_key your_sec_key s3_bucket bucket_name s3_region ap-northeast-1 path ${tag_parts[1]}/${tag_parts[2]}_log/ buffer_path /var/log/td-agent/s3/${tag_parts[2]}_log time_slice_format %Y/%m/%d/${tag_parts[2]}_log_%Y-%m-%d_%H time_slice_wait 10m #flush_interval 3s buffer_chunk_limit 256m </template> </match>
match | タグに対応している。このmatch節はどのソースに使うのか、ここで定義する |
type | さきほどインストールしたプラグインを使うのでforestとする |
subtype | S3に投げるため。この辺は用途によって決まってくる |
aws_key_id | IAMユーザのキーID |
aws_sec_key | IAMユーザのシークレットキー |
s3_bucket | S3バケット名。なければ作ってくれる |
s3_region | S3のあるリージョン。例では東京 |
path | バケット直下からの共通のパス。forestによって、${tag_parts}が有効になっている。matchのところで指定した、*の部分が配列になって1から順に収まっている。このおかげで、複数のソースに対して1つのmatchで済むようになる |
buffer_path | S3へ転送する前のバッファファイル。わかりやすい名前にしておく |
time_slice_format | 生成したいファイル名。年月日とかはforestがなくても取れるから階層化しておこう |
time_slice_wait | S3へ転送する間隔 |
flush_interval | こいつがあると、上記の間隔より優先される。例ではコメントアウトしているが、3秒なのでテスト向け |
buffer_chunk_limit | 指定したサイズを超えたバッファファイルはエンキューされて、次のバッファファイルが作られる |
Fluentd を起動してみる
いつものやつで起動して、ログを見てみる。
$ chkconfig td-agent on $ service td-agent start $ td-agent td-agent: [ OK ] $ cat /var/log/td-agent/td-agent.log
起動はしたが、エラーがでていた。
2016-11-08 17:13:58 +0900 [error]: Permission denied @ rb_file_s_stat - /var/log/httpd/access.log 2016-11-08 17:13:58 +0900 [error]: suppressed same stacktrace
出たー、Permissionだ!!!!
ありがちなハマり。
多少強引だが、他の設定をいじらなくてよいので、Fluentd の実行ユーザをrootにしてしまおう。
kenzo0107.hatenablog.com
TD_AGENT_USER=td-agent TD_AGENT_GROUP=td-agent
↓ここをこう↓
TD_AGENT_USER=root TD_AGENT_GROUP=root
restartしてログを見てみると、
2016-11-08 18:51:54 +0900 [info]: listening fluent socket on 0.0.0.0:24224 2016-11-08 18:51:54 +0900 [info]: listening dRuby uri="druby://127.0.0.1:24230" object="Engine" 2016-11-08 18:51:54 +0900 [info]: following tail of /var/log/httpd/access_log 2016-11-08 18:51:54 +0900 [info]: following tail of /var/log/httpd/error_log
ということで、無事にログファイルがフォローされた。
S3を確認
AWSのサイトでバケットを見に行こう。
今回の例では
すべてのバケット /bucket_name/httpd/access_log/2016/11/08/access_log_2016-11-08_17_2.gz
という具合になって、終わり。
*1:一覧 : docs.fluentd.org