前書き
システム開発部のMNです。
この度、監視業務を改善するため、検索/分析エンジンのElasticsearchを導入してみました。
今回の記事では、ElasticsearchService導入に至った経緯、システムの構成について書いていこうと思います。
システム構成
今回ElasticsearchServiceを導入したシステムは、AWS (Amazon Web Service) 上で構成されています。
BackendのフレームワークはRuby on Rails、FrontendはReactを使用しています。
ElasticBeanstalkのMultiDockerを利用しています。
ElasticsearchService導入の経緯
サービスイン当初は最小限の構成で運用していましたが、利用者が増えるにつれ、耐障害性が求められてきました。
対策の一つとして、ElasticLoadBalancerを使用し、EC2インスタンスのスケールアウトを行いました。
これにより負荷分散を実現できましたが、インスタンスのログが管理しづらい問題が発生します。
そこで、AWS ElasticsearchService、Kibanaを用い、ログの監視/可視化を行うことにしました。
構成
今回は上記の構成でRuby on Railsのログを取得してみます。
アプリケーションが動作しているEC2インスンタンスからCloudwatchLogsにログ情報を転送し、そこからElasticsearchServiceに転送します。
閲覧にはKibanaを使用します。
logrageを使ってformatを整える
ElasticserachでRailsのログを閲覧するためには、Railsのログがjson形式になっている必要があります。
そこで、lograge (https://github.com/roidrage/lograge) というgemを使用し、これを実現します。
インストール後は、環境ごとのrbファイルに設定を記載します。
config.lograge.logger = ActiveSupport::Logger.new(STDOUT) config.lograge.enabled = true config.lograge.keep_original_rails_log = true config.lograge.formatter = Lograge::Formatters::Logstash.new config.lograge.ignore_actions = ["xxxxController#index"] config.lograge.custom_options = lambda do |event| { time: event.time, } end
Railのログを追うことが目的ですので、Railsの標準出力を取得します。
optionには時刻情報しか設定しませんでしたが、リクエストのID等を設定しても良さそうですね。
不要なリクエストがあれば、ignore_actionsで無視するactionを選択しましょう。
もし、unicornのstdout_pathを設定している場合、標準出力がファイルに出力されます。
stdout_pathをnilに設定することで、標準出力となりますので、必要に応じて設定してください。
EC2インスタンスからCloudwatchLogsへログを転送
次は標準出力をCloudwatchLogsに転送します。
サービスがDocker+ElasticBeanstalkで構成されているので、とても簡単です。
dockerrun.aws.jsonに以下の設定を追加します。
"containerDefinitions": [ { "name": "app", "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "<log_name>", // ex. aws/production/rails_json.log "awslogs-region": "<region_name>", // ex. ap-northeast-1 "awslogs-stream-prefix": "<any>", // ex. production } } ... ],
logdriverを設定することで、インスタンスのログ情報をCloudwatchLogsに送信することができます。
group, regionが送信先の情報です。
prefixはログストリームの一部になります。今回は、わかりやすいように環境名をつけることにしました。
設定反映後は、cloudwatchlogsにログ情報が溜まっていきます。
ElasticsearchServiceドメインの作成
次にElasticsearchServiceドメインを作成します。
システムの規模や、ログの量に応じて、インスタンスタイプやストレージのサイズを決めます。
今回は、社外からのアクセスを拒否したかったため、アクセスポリシーで特定のIPだけ閲覧できるよう設定しました。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "es:*", "Resource": "arn:aws:es:XXXXXXXXXXXXXXXXXXXXXXXX*", "Condition": { "IpAddress": { "aws:SourceIp": [ "XX.XX.XX.XX/XX", ] } } }, ] }
設定後、10分程度でステータスがアクティブになり、ログ転送の準備が整います。
AWSLambdaを使って、CloudwatchLogsからElasticsearchServiceへログを転送
次はCloudwatchLogsに蓄積されたログ情報をElasticsearchServiceに転送します。
作成したロググループに対し、アクションから「AWS ElasticSearchServiceへのストリーミングの開始」を選択します。
クラスターに先ほど作成したドメイン名を指定し、実行ロールを選択します。
ロールはElasticsearchへの書き込みが許可されたRoleを選択します。
"Statement": [ { "Effect": "Allow", "Action": "es:ESHttpPost", "Resource": "*" } ]
Lambdaに自動作成された関数ができるので確認してみましょう。
Kibanaを使ってデータ閲覧
最後に、Kibanaの設定を行います。もう少しです!
Kibana初回起動時にはindexを登録する必要があります。
自動的に日付で分類されるので、cwl-*
のように指定します。
登録が完了すると、転送したログを確認することができます。
今回はRailsのログから、以下のグラフを作成し、遅延している処理がないかを確認してみましょう。
- リクエスト数
- 主要なリクエストのDuration
- 処理に10秒以上かかったリクエスト数
- ヒートマップ
完成したダッシュボードがこちらです。(一部画像を加工しています。)
どうやら遅延している処理はなさそうです。(安心)
検索対象の期間や、キーワードを指定することができるので、例えばピーク時の状況を一目で確認することもできます。
今回は遅延状況を確認しましたが、エラーリクエストをまとめたダッシュボードを作成するのもいいと思います。
確認したいデータによって、ダッシュボードを作成できるのもKibanaのいいところですね。
まとめ
ElasticsearchService、Kibanaを使うことで、ログの可視化を行いました。
普段の監視業務の改善はもちろんのこと、不具合や障害が起こったときに問題を特定しやすくなったと思います。
分析したいデータに合わせて専用のダッシュボードを作るともっと便利になりそうです。
しかし、課題としてElasticsearchServiceの料金の問題があります。
ログ情報を無制限に保存すると、ストレージがすぐにいっぱいになってしまいます。
Elasticsearchで監視する情報を数日程度の短期間にして、長期で保存したいデータはS3で保管する等、対策が必要です。
今後、自動でローテーションする仕組みなどを設け、改善に努めていきたいと思っています。
最後に
ウェイブではエンジニアを募集しています。
新しいことに挑戦したい方、興味のある方は、ぜひ採用情報をご覧ください。
また、不定期でもくもく会を開催していますので、ぜひ参加し、会社の雰囲気を感じていただければと思います。