OpenShift 上的 Logstash
更新:本文提及我们的托管式 Elasticsearch 产品时使用的是旧称 Found。请注意,Found 现已更名为 Elastic Cloud。
开始在 OpenShift 上分析您的日志。虽然 OpenShift 允许您跟踪应用程序的日志,但 Elasticsearch/Logstash/Kibana 三位一体为您提供了一个非常灵活且强大的工具链,用于可视化和分析这些日志。本文介绍了如何在 OpenShift 上制作 Logstash cartridge。该 cartridge 将您的日志馈送到 Elasticsearch,您可以在其中使用 Kibana 可视化引擎来跟踪趋势、检测异常并检查环境中的事件。
引言
OpenShift 是 RedHat 的 PaaS 计划,既提供公共产品,也提供企业版本,让您可以将日益流行的“平台即服务”(PaaS) 方法引入您自己的数据中心和私有云中。
 Logstash 是一款用于管理事件和日志的工具。Logstash 与 Elasticsearch 和 Kibana 结合使用,为您提供了一个非常强大的工具链,用于搜索、分析和可视化您的日志。这三者通常被称为 ELK Stack。
 虽然 OpenShift 可以让您轻松尾部所有应用程序的日志,但这种尾部功能远不如 ELK-stack 强大。然而,按照设计,像日志记录这类特定于应用程序的事项交由 OpenShift 所谓的 cartridges 处理。cartridge 提供非常具体的功能,您可以将它们混合到您部署的应用程序的 gears 中。gear 是一个具有特定用途的容器,您的应用程序可以由多个 gear 组成。
 在本文中,我们将制作一个简单的 Logstash-cartridge,您可以轻松将其集成到您的应用程序中,从而深入了解您的日志。
 假设与目标
Logstash 有许多输出,其中包括 Elasticsearch、Graphite 和 S3 等。Elasticsearch 是最广泛使用的输出之一。我们将配置 Logstash 以将日志输出到 Elasticsearch,但这种方法也可以轻松推广到其他输出。您甚至可以输出到上游 Logstash,以区分日志传输和日志处理。
 如果您需要托管的 Elasticsearch 集群,不妨试试Found 。
 我们假设您对 OpenShift 有一定的了解。如果您没有任何 OpenShift 使用经验,请查看他们的入门指南。
 目标是拥有一个可以添加到应用程序中的 cartridge,然后观察日志出现在 Elasticsearch 集群中。之后,您可以使用 Kibana 来可视化和分析您的日志,并检查事件、跟踪趋势以及检测环境中的异常情况。
 OpenShift 配置和日志
Cartridge 通常通过环境变量使用特定于应用程序的配置(例如数据库凭证)进行自定义。其中一个变量 $OPENSHIFT_LOG_DIR 指示了 Cartridge 应将日志记录到的位置。
 Cartridges 可以运行任何内容,因此没有标准的日志格式,甚至没有标准的格式化时间戳。这是日志记录中的一个普遍问题,而 Logstash 处理得非常好。Logstash 拥有许多不同的输入和筛选器。在接下来的示例中,我们将配置带有 file 输入的 Logstash,使用一些筛选器来处理 Apache 日志、时间戳和 IP,最后将日志输出到 Elasticsearch。Logstash 的功能远不止于此,而且其文档也非常完善。
 日志格式具有高度的应用程序特定性,因此您需要相应地配置 Logstash 的处理方式。为了提供一个真实的示例,我们将查看一个生成访问日志的简单 Python 应用程序:
 # 创建一个应用程序。任何会生成日志的程序均可。通过此应用,我们将运行一个会生成访问日志的 Web 服务器,这正是我们所需要的。 $ rhc 应用 create my-应用 python-2.6 应用程序选项 ------------------- 域:命名空间 Cartridges: 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 --应用 my-app --env "OPENSHIFT_LOGSTASH_ES_PASSWORD=secret" 正在设置环境变量……完成 # 最后,添加 cartridge。 $ rhc cartridge add -a my-app https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge 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}。在下一节中,我们将了解如何使用它。
 自定义 Cartridge
基础 cartridge 可在 GitHub (foundit/openshift-logstash-cartridge) 上获取,其配置非常简单,可生成上述日志。
 为了配置 Logstash 以正确处理日志并提取数据,我们需要对配置稍作修改。首先,我们将 python.log 文件指定为 apache 类型,然后确保随后对任何 apache 类型的日志进行适当的过滤。
 我们希望 Logstash 的配置输入和筛选部分看起来像下面这样。请参阅 GitHub 上完整的 logstash.conf.erb。logstash.conf.erb 是用于生成 Logstash 配置文件的模板,它会插入 URL 和身份验证信息等环境变量。
 输入 {
# 任何日志,python.log 除外
file {
path => "<%= ENV['OPENSHIFT_LOG_DIR'] %>*.log"
# 添加一些 openshift-元数据 以用于筛选。
tags => ["<%= ENV['OPENSHIFT_APP_NAME'] %>", "<%= ENV['OPENSHIFT_GEAR_NAME'] %>", "<%= ENV['OPENSHIFT_NAMESPACE'] %>"]
排除 => "python.log"
}
# 我们知道 python.log 中包含 Apache 访问日志。
file {
path => "<%= ENV['OPENSHIFT_LOG_DIR'] %>python.log"
tags => ["<%= ENV['OPENSHIFT_APP_NAME'] %>", "<%= ENV['OPENSHIFT_GEAR_NAME'] %>", "<%= ENV['OPENSHIFT_NAMESPACE'] %>"]
type => “apache”
}
}
filter {
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 仪表板示例。
要自定义插件,只需 fork 该存储库并使用您所需的 Logstash 配置编辑conf/logstash.conf.erb即可。
 然后,在添加 cartridge 时自定义 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
默认情况下,它将使用主分支。您也可以在 URL 中传递?commit=branch-or-commit-id选项,例如https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge?commit=python-sample 。
 有关自定义 Cartridge 以及使用非公开 Cartridge 的更多信息,请参阅 OpenShift 关于 如何下载 Cartridge 的指南。
 日志友好型映射
正如我们所见,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
}
}
}
}
}
如要应用模板,请向 /_template/logstash 发送一个 PUT 请求,并附带以下 JSON 主体:
 $ curl https://user:pass@cluster-id.foundcluster.com:9243/_template/logstash -XPUT -d @index-template.json
{"acknowledged":true}
然后,每当 Elasticsearch 创建新的 logstash 索引时,它都会使用索引模板中指定的设置和映射。
 总结
我们现在拥有一个可以作为自定义 Logstash cartridge 基础的 cartridge,它具有更具应用程序针对性的配置。将日志导入 Elasticsearch 集群以进行出色的搜索和分析,现在只需添加一个 OpenStack cartridge 即可。