こんにちは、エンジニアのよこやまです。
EC2インスタンス内のログをawslogsでCloudWatch連携する方法について紹介します。
やりたいこと
- ログをCloudWatchに送信する
- CloudWatchでログを監視してSlackやメールでアラートする
- 日々溜まっていくCloudWatchログを定期的にS3にエクスポートする
ログをCloudWatchに送信する
Amazon LinuxのログのCloudWatch連携は、「awslogs」を使うと簡単に実現できます。以下のサイトを参考に、非常に簡単に主要なログをCloudWatch連携できました。
https://qiita.com/zaburo/items/57bf357065b7391e1a9d
まず、EC2にCloudWatchログ出力可能なロールを関連付けします。リファレンスを参考に、必要なポリシーを設定します。
ロールの関連付けをしたあとは、awslogsのインストール、confファイル修正、ログ出力の定義を設定してサービス起動して終了です。設定手順は以下の通りです。
※ 3行目の「awscli.conf」は、"region"を
region = us-east-1
↓
region = ap-northeast-1
に変更します。
※ 4行目の「awslogs.conf」は、以下のように取得したいログファイルの定義を追加します。
[HttpdAccessLog]
datetime_format = %d/%b/%Y:%H/%M/%S
file = /path/to/access_log.*
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /HttpdAccessLog
[/var/log/messages]
datetime_format = %b %d %H:%M:%S
file = /var/log/messages
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/messages
[/var/log/mysqld.log]
datetime_format = %Y-%m-%dT%H:%M:%S%z
file = /var/log/mysqld.log
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/mysqld.log
[/var/log/supervisord.log]
datetime_format = %Y-%m-%d %H:%M:%S
file = /var/log/supervisord.log
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/supervisord.log
[/var/log/audit/audit.log]
file = /var/log/audit/audit.log
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/audit/audit.log
※awslogs.confの"file"にはログファイルのパスを記述します。
※awslogs.confの"datetime_format"は、対象ログから時刻を抽出する際に設定します。
日付書式設定については、リファレンスに記載されています。正しく設定ができていれば、CloudWatch上にログが出力されます。
CloudWatchでログを監視してSlackやメールでアラートする
CloudWatchログでは、指定されたものに一致する語句や値をログから検索できる「メトリクスフィルタ」と、フィルタ結果を基にアラート通知させる「アラーム」を設定することができます。
フィルタ設定内容はログによって様々なので、本記事では具体的な手順は記載しませんが、参考にさせていただいた記事を載せておきます。
Nginxの500系エラー検知
https://remotestance.com/blog/2433/
フィルタとパターン構文
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html
アラーム設定時に"アクション"で通知先のSNSトピックを設定することで、アラートのメール通知ができます。通知は、アラームの状態が変化する毎に通知されます。「警告(Alert)」「OK(OK)」それぞれ通知を設定しておくと、警告〜警告の解消が把握できるので便利です。
アラートのSlack通知は、Lambdaに標準で提供されているSlack通知用のBlueprint(cloudwatch-alarm-to-slack-python3)を使うと簡単に実現できます。
参考
http://blog.serverworks.co.jp/tech/2016/02/16/lambda-cloudwatch-alarm-to-slack/
このような感じでアラートがSlack通知されます(文面はBlueprintの"slack_message"をカスタマイズします)。
CloudWatchログを定期的にS3にエクスポートする
Amazon LinuxのログをCloudWatchに出力して監視もできましたが、このままではCloudWatch上に延々とログが蓄積されてしまうので、自動でS3にエクスポートしてCloudWatchログは一定期間のみ保持するようにします。
S3へのエクスポートはLambdaを使って自動化できますが、CloudWatchのCreateExportTaskは複数同時に実行できないため、1つエクスポートが終わってから次...と実行していく必要があります。
そのため、今回はStepFunctionsとLambdaを組み合わせて実現します。
まずは、ログをエクスポートするS3バケットを作成します。また、作成したS3バケットに以下のようにバケットボリシーを設定しておきます。
次に、作成したS3バケットにCloudWatchログをエクスポートするLambda関数を作成します。
Lambdaは以下の通り作成しました(python3.6)。
参考
https://www.soudegesu.com/aws/export-cloudwatchlogs-to-s3/
なお、Lambdaには以下のIAMロールのポリシーを設定しました。
次に、ロググループ毎に上記Lambda関数を実行するStepFunctionsステートマシンを定義します。ステートマシンでは、ロググループ毎にcreate export taskを行い、タスクが処理中の場合は数秒待ってリトライを行います。
こちらは、上記参考サイトの手順そのままに実装して実現できました。
あとは、CloudWatchの「ルール>ルールの作成」で、
- イベントソース:任意のパターン、スケジュール
- ターゲット:Step Functions ステートマシン
- ステートマシン:上記で作成したステートマシン
を設定すると、自動でCloudWatchログが定期的にS3エクスポートされます。
また、S3に過去ログを退避させることで、CloudWatchのログ保持期間やS3のライフサイクルルールを設定して、
- CloudWatchログは1週間保持
- S3にはログを3ヶ月保持
といった管理ができます。
以上が、CloudWatchへのログ出力からログ監視、S3へのエクスポートまでの連携方法でした。
いやぁ、ほんと便利ですね。