UUUM攻殻機動隊(エンジニアブログ)

UUUMのエンジニアによる技術ブログです

AWS CloudWatch LogsでECSのログを手軽に取り扱う

AWSの監視といえばCloudWatchですが、CloudWatchの中に、CloudWatch Logsというログ管理用のサービスがあります。 特にECSとの連携が強力なので、そこに焦点を当てて紹介したいと思います。

CloudWatch Logsの概要

簡単に言えば、そこにログを出力しておいて、コンソール等からログを確認できるサービスです。

ログ分析といえばSplunkやTreasure Dataといったサービスを思い浮かべますが、それらよりはもう少しシンプルで、基本的には現在時刻近辺のログを見ることに特化しております。過去のログから集計というような機能はありません。

本格的に使うには物足りないところも多いですが、AWSで手軽かつ低予算でログを管理するにはお勧めです。

ECSからコンテナのログをCloudWatch Logsに出力する

ECSというかDockerには logging driver というものがあり、コンテナ内での標準出力及び標準エラー出力をどこに流すかを指定することができます。この中に awslogs というドライバがあり、ログを直接CloudWatch Logsに飛ばすことができます。ECSとは直接は関係のない機能なので、自前で建てたコンテナからでも送信することが可能です。

ECSで使う場合、AWSから提供されているECS用AMIでは問題がありませんが、自前で作ったコンテナインスタンスでは 以下のような環境変数を指定する必要があります

ECS_AVAILABLE_LOGGING_DRIVERS='["json-file","awslogs"]'

また、IAMロールで logs:CreateLogStream と logs:PutLogEvents を設定してあげる必要があります。

これらの設定を終えたコンテナインスタンスの上でコンテナを作り、コンテナのログ設定を以下のようにします。

  • ログドライバー : awslogs
  • ログオプション
    • awslogs-group : 適当なグループ名
    • awslogs-region : 適当なリージョン(国内なら ap-northeast-1 )
    • awslogs-stream-prefix : 適当なプリフィックス

これでコンテナのログがCloudWatchに転送されます。グループは事前に作成しておいてください。グループ名とプリフィックスについては以下で説明します。

fluentdからCloudWatch Logsにログを流す

fluentdを使っている場合であれば、他の選択肢がいろいろあるのでCloudWatch Logsを選択する必要は薄いですが、 fluent-plugin-cloudwatch-logs を使うことで流すことができます。

CloudWatch Logs ダッシュボードの使い方

AWSコンソールからCloudWatchのメニューのログの画面に行くと、未使用の場合は何もないか、何かで勝手に作られたグループが存在する状態になっていると思います。

ロググループというのは、ログを取り扱う単位になります。後述のフィルタとかはこのロググループ全体に対して影響します。通常はログの種類と環境(本番・ステージング等)毎に作成するのが良いでしょう。ロググループは事前に作成しておかないと、そこにログが流れてきません。

ロググループの中にはいくつかの「ログストリーム」があり、その中に実際のログがあります。ログストリームはファイルの単位みたいなものです。ECSで生成した場合はECSのデプロイの単位で作られます。

フィルタ

ログが整形されている場合、特定の条件によってフィルタをかけることができます。

JSONの検索

JSONの場合は、フィールド単位で細かく条件を指定することができます。

このため、CloudWatch Logsに流すログは、なるべくJSONで出力するのが良いです。

nginxの場合、1.11.8から直接JSONログを出力できるようになった( 正確に言えば、JSON用の変数エスケープができるようになった )ので、設定しておくと良いでしょう。

フィルタからグラフを作る

グラフ化しておけば、グラフのしきい値によってアラームを作ったりすることができます。例えば、エラー数が一定以上になった場合にSNSで通知、ということが可能です。

フィルタから細かい処理

CloudWatch LogsはLambdaとの連携ができるようになっており、フィルタに合致したログが来たらLambda Functionを実行することができます。

特定のフィルタから通知とかがすぐ思いつくところですが、ここでのフィルタは、「全件」という指定も可能なので、全件を常にLambda Functionに流して、それを別サービスに流す、といったことも可能です。

logseneとかの一部サービスではこの仕組みを使ってログを流せるようになっています。

微妙な点

過去ログの検索

CloudWatch Logsは過去ログの検索はできなくはないですが非常に遅いです。ローカルにダウンロードして集計するか、高速に検索できる別DBにあらかじめ入れておくのが良いでしょう。

ローカルにダウンロードするには、期間指定でS3にエクスポートすることができるので、それをダウンロードするのが簡単です。ただし都度実行しないといけない上、転送にも時間がかかります。

別DBに入れるのは、標準で Elasticsearch Serviceとの連携機能 があるので、それを使うのが一番簡単です。1設定で簡単にES上で検索できるようになり非常に手軽ですが、一方で容量単価が安くなく、かつ、ログの量次第ではあっという間にTB単位で増えてしまうので、使い所が難しいですが、lambdaで自動で過去のデータを削除するようなものを作ると実用的に使えると思います。

コンソールからは指定できないのですが、 Kinesisとも連携ができる ので、Kinesis Firehoseと連携し、S3にgzip圧縮転送するという方法もあります。

Elasticsearch Service/Kinesis Streams/Lambdaに転送するのは「サブスクリプションフィルタ」と呼ばれる設定になりますが、1ロググループに対し1つしか設定できません。事前にどれを使うか検討した上で採用しましょう。

ECSの標準出力のログを分類できない

標準出力がそのままログとして残るのはいいのですが、例えばアクセスログとエラーログといった、1アプリケーションから複数の種別のログを出力したい時に、それを分類する方法がありません。

コンテナ側でAPI経由で直接ログを出力するか、混ざるのを承知の上で混ぜてしまうかを選択する必要があります。私はとりあえず混ぜています。

まとめ

使い勝手の微妙さから、あまり話題にされない(気がする)CloudWatch Logsですが、あまり料金をかけずにログを取り扱うことができます。うまく使えば実用上は問題ないでしょう。