产品

OpenShift 上的 Logstash

更新:本文提及我们的托管式 Elasticsearch 产品时使用的是旧称 Found。请注意,Found 现已更名为 Elastic Cloud。

开始在 OpenShift 上分析您的日志。虽然 OpenShift 允许您跟踪应用程序的日志,但 Elasticsearch/Logstash/Kibana 三位一体为您提供了一个非常灵活且强大的工具链,用于可视化和分析这些日志。本文介绍了如何在 OpenShift 上制作 Logstash cartridge。该 cartridge 将您的日志馈送到 Elasticsearch,您可以在其中使用 Kibana 可视化引擎来跟踪趋势、检测异常并检查环境中的事件。

引言

OpenShift 是 RedHat 的 PaaS 计划,既提供公共产品,也提供企业版本,让您可以将日益流行的“平台即服务”(PaaS) 方法引入您自己的数据中心和私有云中。

&nbsp

Logstash 是一款用于管理事件和日志的工具。Logstash 与 Elasticsearch 和 Kibana 结合使用,为您提供了一个非常强大的工具链,用于搜索、分析和可视化您的日志。这三者通常被称为 ELK Stack

&nbsp

虽然 OpenShift 可以让您轻松尾部所有应用程序的日志,但这种尾部功能远不如 ELK-stack 强大。然而,按照设计,像日志记录这类特定于应用程序的事项交由 OpenShift 所谓的 cartridges 处理。cartridge 提供非常具体的功能,您可以将它们混合到您部署的应用程序的 gears 中。gear 是一个具有特定用途的容器,您的应用程序可以由多个 gear 组成。

&nbsp

在本文中,我们将制作一个简单的 Logstash-cartridge,您可以轻松将其集成到您的应用程序中,从而深入了解您的日志。

&nbsp

假设与目标

Logstash 有许多输出,其中包括 Elasticsearch、Graphite 和 S3 等。Elasticsearch 是最广泛使用的输出之一。我们将配置 Logstash 以将日志输出到 Elasticsearch,但这种方法也可以轻松推广到其他输出。您甚至可以输出到上游 Logstash,以区分日志传输和日志处理。

&nbsp

如果您需要托管的 Elasticsearch 集群,不妨试试Found 。

&nbsp

我们假设您对 OpenShift 有一定的了解。如果您没有任何 OpenShift 使用经验,请查看他们的入门指南。

&nbsp

目标是拥有一个可以添加到应用程序中的 cartridge,然后观察日志出现在 Elasticsearch 集群中。之后,您可以使用 Kibana 来可视化和分析您的日志,并检查事件、跟踪趋势以及检测环境中的异常情况。

&nbsp

OpenShift 配置和日志

Cartridge 通常通过环境变量使用特定于应用程序的配置(例如数据库凭证)进行自定义。其中一个变量 $OPENSHIFT_LOG_DIR 指示了 Cartridge 应将日志记录到的位置。

&nbsp

Cartridges 可以运行任何内容,因此没有标准的日志格式,甚至没有标准的格式化时间戳。这是日志记录中的一个普遍问题,而 Logstash 处理得非常好。Logstash 拥有许多不同的输入和筛选器。在接下来的示例中,我们将配置带有 file 输入的 Logstash,使用一些筛选器来处理 Apache 日志、时间戳和 IP,最后将日志输出到 Elasticsearch。Logstash 的功能远不止于此,而且其文档也非常完善。

&nbsp

日志格式具有高度的应用程序特定性,因此您需要相应地配置 Logstash 的处理方式。为了提供一个真实的示例,我们将查看一个生成访问日志的简单 Python 应用程序:

&nbsp
# 创建一个应用程序。任何会生成日志的程序均可。通过此应用,我们将运行一个会生成访问日志的 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 中:

&nbsp
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 中:

&nbsp
{
    "_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 [...]" 中。

&nbsp

此字符串遵循 Apache Combined 格式,Logstash 具有用于匹配该格式的预定义模式。通常,如果您正在使用某些知名软件,很有可能找到相应的 Logstash 模式。请查看 Logstash 的 patterns 目录。Grok Debugger 的 Discover 功能也很有用。如果您将上述日志消息粘贴到其中,它将输出 %{COMBINEDAPACHELOG}。在下一节中,我们将了解如何使用它。

&nbsp

自定义 Cartridge

基础 cartridge 可在 GitHub (foundit/openshift-logstash-cartridge) 上获取,其配置非常简单,可生成上述日志。

&nbsp

为了配置 Logstash 以正确处理日志并提取数据,我们需要对配置稍作修改。首先,我们将 python.log 文件指定为 apache 类型,然后确保随后对任何 apache 类型的日志进行适当的过滤。

&nbsp

我们希望 Logstash 的配置输入和筛选部分看起来像下面这样。请参阅 GitHub 上完整的 logstash.conf.erb。logstash.conf.erb 是用于生成 Logstash 配置文件的模板,它会插入 URL 和身份验证信息等环境变量。

&nbsp
输入 {

    # 任何日志,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 将生成如下文档:

&nbsp
{
    "_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 仪表板示例。Using Kibana to analyze access logs

&nbsp

要自定义插件,只需 fork 该存储库并使用您所需的 Logstash 配置编辑conf/logstash.conf.erb即可。

&nbsp

然后,在添加 cartridge 时自定义 URL,即:将 foundit/openshift-logstash-cartridge 更改为 your-organization/repository-name。

&nbsp
$ 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 。

&nbsp

有关自定义 Cartridge 以及使用非公开 Cartridge 的更多信息,请参阅 OpenShift 关于 如何下载 Cartridge 的指南。

&nbsp

日志友好型映射

正如我们所见,Logstash 负责将日志发送到 Elasticsearch。我们仍然需要告诉 Elasticsearch 如何处理这些日志。我们需要配置生成的索引的映射。(另请参阅: Elasticsearch 映射简介映射的数据探索工作流

&nbsp

通常,Logstash 会将日志发送到索引 logstash-YYYY-MM-DD,其中 YYYY-MM-DD 是日志的日期。这使您可以将搜索限制在特定的日期范围内,并归档或删除旧日志。

&nbsp

要配置我们的日志映射,我们需要定义一个 索引模板,它为所有名称匹配 logstash-* 的索引定义映射。

&nbsp

以下是针对上述所生成日志的适当映射。字符串字段默认不进行分析,但 message 字段除外;geoip-location 配置为 geo_point 类型,clientip 配置为 ip 类型,等等。

&nbsp
{
    "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 主体:

&nbsp
$ curl https://user:pass@cluster-id.foundcluster.com:9243/_template/logstash -XPUT -d @index-template.json
{"acknowledged":true}

然后,每当 Elasticsearch 创建新的 logstash 索引时,它都会使用索引模板中指定的设置和映射。

&nbsp

总结

我们现在拥有一个可以作为自定义 Logstash cartridge 基础的 cartridge,它具有更具应用程序针对性的配置。将日志导入 Elasticsearch 集群以进行出色的搜索和分析,现在只需添加一个 OpenStack cartridge 即可。

&nbsp