OpenShift上のLogstash
更新:本記事で、マネージドのElasticsearchは旧称のFoundで表記されています。Foundの現在の名称はElastic Cloudですのでご注意ください。
OpenShiftでのログ分析を始めましょう。OpenShiftではアプリのログを末尾から確認できますが、Elasticsearch/Logstash/Kibanaの組み合わせは、これらのログを可視化・分析するための非常に柔軟で強力なツールチェーンを提供します。この記事では、OpenShift上でLogstashカートリッジを作成する方法を説明します。このカートリッジはログをElasticsearchに取り込み、Kibanaの可視化エンジンを使用して、環境内のトレンドの追跡、異常の検出、インシデントの調査を行うことができます。
はじめに
OpenShiftはRedHatのPaaSイニシアチブであり、パブリック版とエンタープライズ版の両方が提供されています。これにより、ますます普及しているPlatform-as-a-Service(PaaS)アプローチを、独自のデータセンターやプライベートクラウドに導入できるようになります。
Logstashは、イベントとログを管理するためのツールです。LogstashをElasticsearchおよびKibanaと組み合わせることで、ログの検索、分析、可視化を行うための非常に強力なツールチェーンが実現します。この3つの組み合わせは、一般的にELK Stackと呼ばれています。
OpenShiftではすべてのアプリのログを簡単にtail表示できますが、テールはELKスタックほど強力ではありません。しかし、設計上、ログ記録のようなアプリケーション固有の処理は、OpenShiftがカートリッジと呼ぶものに委ねられています。カートリッジは非常に特定の機能を提供し、これをデプロイするアプリケーションのギアに組み込みます。ギアは特定の目的を持つコンテナであり、アプリケーションは複数のギアで構成できます。
この記事では、アプリケーションに簡単に組み込んでログから洞察を得ることができる、シンプルなLogstashカートリッジを作成します。
想定と目標
Logstashには多くの出力先があり、その中にはElasticsearch、Graphite、S3などがあります。Elasticsearchは最も広く使用されている出力先の1つです。ここではLogstashがログをElasticsearchに出力するように設定しますが、このアプローチは他の出力先にも簡単に適用できます。ログの転送とログの処理を区別するために、アップストリームのLogstashに出力することも可能です。
マネージドElasticsearchクラスターが必要なら、 Found を試してみてください。
OpenShiftに関するある程度の知識があることを前提としています。OpenShiftの経験がない場合は、入門ガイドをご確認ください。
目標は、アプリケーションに追加できるカートリッジを用意し、Elasticsearchクラスターにログが表示されるようにすることです。その後、Kibanaを使用してログを可視化および分析し、インシデントの調査、傾向の追跡、環境内の異常検知を行うことができます。
OpenShiftの設定とログ
カートリッジは通常、環境変数を通じてアプリケーション固有の設定(データベースの認証情報など)でカスタマイズされます。これらの変数の1つである $OPENSHIFT_LOG_DIR は、カートリッジがログを出力する場所を示します。
カートリッジはあらゆるものを実行できるため、標準的なログ形式や標準的なタイムスタンプ形式さえ存在しません。これはログ記録における普遍的な問題ですが、Logstashはこれを非常にうまく処理します。Logstashには、さまざまなインプットとフィルターが用意されています。以下の例では、fileインプット、Apacheログ、タイムスタンプ、IPを処理するためのフィルターを使用してLogstashを設定し、最終的にログをElasticsearchに出力します。Logstashにはさらに多くの機能があり、ドキュメントも充実しています。
ログの形式はアプリケーションによって大きく異なるため、それに応じてLogstashの処理を構成する必要があります。実際の例として、アクセスログを生成するシンプルなPythonアプリケーションを見てみましょう。
# アプリケーションを作成します。ログを生成するものであれば何でも構いません。このアプリでアクセスログを生成するWebサーバーを実行します。必要なのはこれだけです。 $ rhc アプリ create my-アプリ python-2.6 アプリケーションのオプション ------------------- ドメイン: 名前空間 カートリッジ: python-2.6 ギアサイズ:デフォルト スケーリング: いいえ アプリケーション 'my-app' を作成中... 完了 [ ... ] アプリ「my-app」が利用可能になりました。 URL: http://my-app-namespace.rhcloud.com/ [ ... ] # クラスターのホスト名や認証オプションなどの環境変数を構成する $ rhc set-env --app my-app --env "OPENSHIFT_LOGSTASH_ES_HOST=dabadeee123-us-east-1.foundcluster.com" 環境変数の設定... 完了 $ rhc set-env --アプリ my-アプリ --env "OPENSHIFT_LOGSTASH_ES_USER=readwrite" 環境変数の設定... 完了 $ rhc set-env --app my-app --env "OPENSHIFT_LOGSTASH_ES_PASSWORD=secret" 環境変数の設定... 完了 # 最後に、カートリッジを追加します。 $ rhc cartridge add -a my-app https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge カートリッジ 'https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge'ダウンロードおよびインストールされます https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge を追加アプリ 'my-app' へ ... 完了 found-logstash-1.4.1 (Logstash 1.4.1) ------------------------------------- 参照元:https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge Gears:python-2.6に配置
しばらくすると、設定したElasticsearchクラスターにログが表示され始めます。Webアプリケーションにアクセスすると、以下のようなアクセスログが python.log に表示されるはずです:
1.2.3.4 - - [10/Jun/2014:10:31:17 -0400] "GET / HTTP/1.1" 200 39617 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36"
これらはLogstashによって取得され、次のようにElasticsearchにインデックスされます:
{
"_type": "logs",
"_source": {
"tags": ["アプリ-name", "gear-name", "名前空間"],
"@timestamp": "2014-06-10T14:31:18.907Z",
"host": "ex-std-node7.prod.rhcloud.com",
"path": "/var/lib/openshift/530001200012cd3502000122/app-root/logs/python.log",
"message": "1.2.3.4 - - [10/Jun/2014:10:31:17 -0400] \"GET / HTTP/1.1\"200 39617 \"-\" \"Mozilla/5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36\"",
"@version": "1"
},
"_index": "logstash-2014.06.10",
"_id": "dCfV_YUjSwOlISJWQMafaw"
}
これは良い出発点ですが、最も興味深い情報は 1.2.3.4 - - [10/Jun/2014:10:31:17 -0400] "GET / HTTP/1.1\" 200 39617 \"-\" \"Mozilla/5.0 [...]" という文字列にまとめられています。
この文字列はApache Combined形式に従っており、Logstashにはそれをマッチングするための定義済みパターンがあります。一般的に、よく知られたソフトウェアを使用している場合、それに対応するLogstashパターンが見つかる可能性が高いです。Logstashの patterns ディレクトリを確認してください。Grok Debugger の Discover の特徴も役立ちます。上記のログメッセージをそこに貼り付けると、%{COMBINEDAPACHELOG} が出力されます。次のセクションでは、その使用方法について説明します。
カートリッジのカスタマイズ
GitHub(foundit/openshift-logstash-cartridge)で入手可能なベースカートリッジには、上記のログを生成する非常にシンプルな構成が含まれています。
Logstashでログを適切に処理し、データを抽出するように構成するには、構成を少し変更する必要があります。まず、python.logファイルがapacheタイプであることを指定し、その後、apacheタイプのログが適切にフィルタリングされるようにします。
Logstashの構成のインプットセクションとフィルターセクションを以下のように設定します。GitHubで完全な logstash.conf.erb を参照してください。logstash.conf.erb は、URLや認証情報などの環境変数を補間してLogstash構成ファイルを生成するために使用されるテンプレートです。
インプット {
# python.logを除く、ログに記録されたすべて
ファイル {
path => "<%= ENV['OPENSHIFT_LOG_DIR'] %>*.log"
# フィルタリング目的でopenshift-metadataを追加します。
tags => ["<%= ENV['OPENSHIFT_APP_NAME'] %>", "<%= ENV['OPENSHIFT_GEAR_NAME'] %>", "<%= ENV['OPENSHIFT_NAMESPACE'] %>"]
exclude => "python.log"
}
# python.logにApacheのアクセスログが含まれていることは把握しています。
ファイル {
path => "<%= ENV['OPENSHIFT_ログ_DIR'] %>python.ログ"
tags => ["<%= ENV['OPENSHIFT_APP_NAME'] %>", "<%= ENV['OPENSHIFT_GEAR_NAME'] %>", "<%= ENV['OPENSHIFT_NAMESPACE'] %>"]
type => "apache"
}
}
フィルター {
if [type] == "apache" {
# これにより、タイムスタンプ、IP、メソッドなど、ログメッセージ内のさまざまなメタデータが抽出されます。
Grok {
match => ["message", "%{COMBINEDAPACHELOG}"]
}
# 時間形式を適切なものに変換します。
日時 {
match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
}
# ログに概算の地理情報を注釈として付加する。
geoip {
source => "clientip"
}
}
}
その設定により、Logstashは以下のようなドキュメントを生成します:
{
"_type": "apache",
"_source": {
"ident": "-",
"tags": ["アプリ-name", "gearname", "名前空間"],
"type": "apache",
"@timestamp": "2014-06-10T15:19:31.000Z",
"request": "/",
"auth": "-",
"response": "200",
"referrer": "\"-\"",
"bytes": "39617",
"host": "ex-std-node7.prod.rhcloud.com",
"verb": "GET",
"agent": "Mozilla/5.0(Macintosh; Intel Mac OS X 10_9_3) [...]",
"timestamp": "10/Jun/2014:11:19:31 -0400",
"path": "/var/lib/openshift/539709b8e0b8cd3502000122/app-root/logs/python.log",
"message": "1.2.3.4 - - [10/Jun/2014:11:19:31 -0400] \"GET / HTTP/1.1\"200 39617 [...]"、
"@version": "1",
"clientip": "1.2.3.4",
"httpversion": "1.1",
"geoip": {
"region_name": "16",
"ip": "1.2.3.4",
"continent_code": "EU",
"country_name": "Norway",
"city_name": "Trondheim",
"timezone": "Europe/Oslo",
"longitude": 10.416699999999992,
"country_code3": "NOR",
"country_code2": "NO",
"location": [
10.416699999999992,
63.41669999999999
],
"latitude": 63.41669999999999,
"real_region_name": "Sor-Trondelag"
}
},
"_index": "logstash-2014.06.10",
"_id": "Z1N65K5-QTOwZ9z3jPgEUw"
}
このドキュメントを使って、さらに多くのことができます。ユーザーの出身地や訪問先に基づいてアクセスログを細分化して分析したり、問題のあるリクエストを簡単に見つけたりすることが可能です。下の図は、上記のデータを使用したKibanaのダッシュボードの例です。
カートリッジをカスタマイズするには、リポジトリをフォークし、conf/logstash.conf.erbを編集して、目的のLogstash設定を記述します。
次に、カートリッジを追加する際にURLをカスタマイズします。つまり、foundit/openshift-logstash-cartridge を your-organization/repository-name に変更します。
$ rhc cartridge add -a my-app https://cartreflect-claytondev.rhcloud.com/github/your-organization/your-repo
デフォルトでは、masterブランチが使用されます。URLに ?commit=branch-or-commit-id オプションを渡すこともできます(例:https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge?commit=python-sample)。
カートリッジのカスタマイズや、公開されていないカートリッジの使用に関する詳細については、OpenShiftのガイド「カートリッジのダウンロード方法」をご覧ください。
ログフレンドリーなマッピング
これまで見てきたように、LogstashはログをElasticsearchに送信する役割を担います。しかし、それらのログをどのように扱うかをElasticsearchに指示する必要があります。そのために、生成されるインデックスのマッピングを構成しなければなりません。(以下も参照:Elasticsearchマッピング入門およびマッピングのためのデータ探索ワークフロー)
通常、Logstashはログをインデックス logstash-YYYY-MM-DD に送信します(YYYY-MM-DDはログの日付)。これにより、検索を特定の期間に限定したり、古いログをアーカイブまたは削除したりできます。
ログマッピングを構成するには、インデックステンプレートを定義する必要があります。これは、名前が logstash-* に一致するすべてのインデックスのマッピングを定義します。
以下は、上記で生成されたログに対する適切なマッピングです。messageフィールドを除き、文字列フィールドはデフォルトで分析されません。geoip-locationはgeo_pointタイプとして、clientipはipとして構成されています。
{
"template": "logstash-*",
"settings": {
"index.refresh_interval":"5s"
},
"mappings": {
「_default_」: {
"_all": {
"enabled": true
},
"dynamic_templates": [
{
"string_fields": {
"match": "*",
"match_mapping_type": "文字列",
"マッピング": {
"type": "文字列",
"index": "not_analyzed"
}
}
}
],
"properties": {
"geoip": {
"properties": {
"location": {
"type": "geo_point"
}
}
},
"clientip": {
"type": "ip"
},
"bytes": {
"type": "long"
},
"message": {
"type": "文字列",
"index": "analyzed",
"omit_norms": true
}
}
}
}
}
テンプレートを適用するには、JSONボディを添えて /_template/logstash に PUT リクエストを送信します:
$ curl https://user:pass@cluster-id.foundcluster.com:9243/_template/logstash -XPUT -d @index-template.json
{"acknowledged":true}
その後、Elasticsearchは、新しいlogstash-indexを作成するたびに、インデックステンプレートで指定された設定とマッピングを使用します。
概要
よりアプリケーション固有の設定を行うカスタムLogstashカートリッジの基盤として機能するカートリッジが利用可能になりました。Elasticsearchクラスターにログを取り込んで高度な検索や分析を行うには、OpenStackカートリッジを追加するだけです。