Producto

Logstash en OpenShift

ACTUALIZACIÓN: Este artículo se refiere a nuestra oferta de Elasticsearch hospedado con un nombre anterior, Found. Ten en cuenta que Found ahora es conocido como Elastic Cloud.

Comienza a analizar tus logs en OpenShift. Aunque OpenShift te permite seguir el final de los logs de tus aplicaciones, la trinidad de Elasticsearch/Logstash/Kibana te ofrece una cadena de herramientas muy flexible y potente para visualizar y analizar estos logs. Este artículo explica cómo crear un cartucho de Logstash en OpenShift. El cartucho envía tus logs a Elasticsearch, donde puedes usar el motor de visualización de Kibana para seguir tendencias, detectar anomalías e inspeccionar incidentes en tu entorno.

Introducción

OpenShift es la iniciativa PaaS de RedHat, con una oferta pública y una versión empresarial que te permite llevar el enfoque de plataforma como servicio (PaaS), cada vez más popular, a tus propios centros de datos y a tu cloud privado.

Logstash es una herramienta para gestionar eventos y logs. Logstash, combinado con Elasticsearch y Kibana, te ofrece una cadena de herramientas muy potente para buscar, analizar y visualizar tus logs. Esta trinidad se conoce popularmente como el ELK-stack.

Aunque OpenShift te permite seguir fácilmente el final de los logs de todas tus apps, el seguimiento no es ni de lejos tan potente como el ELK-stack. Sin embargo, por diseño, las cosas específicas de la aplicación, como el logging, se dejan a lo que OpenShift llama cartridges. Un cartridge proporciona una funcionalidad muy específica, y los mezclas en los gears de las aplicaciones que despliegas. Un gear es un contenedor con un propósito determinado, y tu aplicación puede estar compuesta por múltiples gears.

En este artículo, crearemos un Logstash-cartridge sencillo, que puedes integrar fácilmente en tu aplicación para obtener información sobre tus logs.

Suposiciones y objetivos

Logstash tiene muchas salidas, entre ellas Elasticsearch, Graphite y S3, por nombrar algunas. Elasticsearch es una de las salidas más utilizadas. Configuraremos nuestros Logstashes para enviar logs a Elasticsearch, pero el enfoque puede generalizarse fácilmente a otras salidas también. Incluso podrías enviar a un Logstash ascendente, para distinguir entre el envío de logs y el procesamiento de logs.

Si necesitas un cluster de Elasticsearch hospedado, prueba Found.

Suponemos cierta familiaridad con OpenShift. Si no tienes experiencia con OpenShift, echa un vistazo a su guía para empezar.

El objetivo es tener un cartucho que puedas añadir a tu aplicación y, luego, ver cómo aparecen los logs en un cluster de Elasticsearch. Después, puedes usar Kibana para visualizar y analizar tus logs, inspeccionar incidentes, seguir tendencias y detectar anomalías en tu entorno.

Configuración y logs de OpenShift

Los cartuchos suelen personalizarse con una configuración específica de la aplicación (como las credenciales de la base de datos) mediante variables de entorno. Una de estas variables, $OPENSHIFT_LOG_DIR, indica dónde debe realizar el log un cartucho.

Los cartuchos pueden ejecutar cualquier cosa, por lo que no existe un formato de logging estándar, ni siquiera un formato de marca de tiempo estándar. Este es un problema universal para el logging y es algo que Logstash maneja muy bien. Logstash tiene muchas entradas y filtros diferentes. En el ejemplo que sigue, configuraremos Logstash con entradas file, algunos filtros para procesar logs de Apache, marcas de tiempo e IPs, y finalmente enviaremos los logs a Elasticsearch. Logstash puede hacer mucho más y su documentación es buena.

Los formatos de log son altamente específicos de cada aplicación, por lo que deberás configurar el procesamiento de Logstash en consecuencia. Para tener un ejemplo real, veremos una aplicación simple en Python que genera logs de acceso:

.
# Crea una aplicación. Cualquier cosa que produzca log. Con esta app obtendremos un servidor web en ejecución que produce logs de acceso, que es todo lo que necesitamos.

$ rhc app create my-app python-2.6
Opciones de aplicación
-------------------
Dominio:     espacio de nombres
Cartridges: python-2.6
Tamaño del engranaje: predeterminado
Escalado:    no

Creando la aplicación 'my-app' ... listo

[ ... ]

Tu aplicación 'my-app' ya está disponible.

  URL:        http://my-app-namespace.rhcloud.com/

[ ... ]

# Configurar variables de entorno, como el nombre de host del cluster y las opciones de autenticación
$ rhc set-env --app my-app --env "OPENSHIFT_LOGSTASH_ES_HOST=dabadeee123-us-east-1.foundcluster.com"
Configurando variable(s) de entorno... listo
$ rhc set-env --app my-app --env "OPENSHIFT_LOGSTASH_ES_USER=readwrite"
Configurando variable(s) de entorno... listo
$ rhc set-env --app my-app --env "OPENSHIFT_LOGSTASH_ES_PASSWORD=secret"
Configurando variable(s) de entorno... listo

# Por último, agrega el cartucho.
$ rhc cartridge add -a my-app https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge
El cartridge 'https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge' se descargará e instalará
Agregando https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge a la aplicación 'my-app' ... listo

found-logstash-1.4.1 (Logstash 1.4.1)
-------------------------------------
  De:  https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge
  Gears: ubicado con python-2.6

Después de un tiempo, los logs deberían comenzar a aparecer en el cluster de Elasticsearch configurado. Si visitas tu aplicación web, deberían aparecer logs de acceso similares al siguiente en 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"

A continuación, Logstash los recogerá y los indexará en Elasticsearch de la siguiente manera:

{
    "_type": "logs",
    "_source": {
        "tags": ["app-name", "gear-name", "espacio de nombres"],
        "@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"
}

Aunque este es un buen comienzo, la información más interesante está agrupada en el texto 1.2.3.4 - - [10/Jun/2014:10:31:17 -0400] "GET / HTTP/1.1\" 200 39617 \"-\" \"Mozilla/5.0 [...]".

Este texto sigue el formato Apache Combined y Logstash tiene un patrón predefinido para establecer la coincidencia. Por lo general, si utilizas algún software conocido, es muy probable que encuentres patrones de Logstash para él. Echa un vistazo al directorio patterns de Logstash. La característica Discover (Descubrir)de Grok Debugger también puede ser útil. Si pegas el mensaje de log anterior allí, generará. En la siguiente sección veremos cómo %{COMBINEDAPACHELOG} usarlo.

Personalización del cartucho

El cartucho base, disponible en GitHub (foundit/openshift-logstash-cartridge), tiene una configuración muy simple que produce el log anterior.

Para configurar Logstash para procesar correctamente el log y extraer los datos, necesitamos cambiar un poco la configuración. Primero, diremos que el archivo python.loges de tipo apache y, luego, nos aseguraremos de filtrar posteriormente cualquier log de tipo apache de forma adecuada.

Queremos que la sección de entrada y filtro de la configuración de Logstash se vea similar a lo siguiente. Consulta el archivo logstash.conf.erb completo en GitHub. logstash.conf.erb es la plantilla utilizada para generar el archivo de configuración de Logstash, interpolando variables de entorno como URLs e información de autenticación.

entrada {

    # Cualquier cosa registrada, excepto python.log
    archivo {
        path => "<%= ENV['OPENSHIFT_LOG_DIR'] %>*.log"
        # Añadir algunos metadatos de openshift para fines de filtrado.
        tags => ["<%= ENV['OPENSHIFT_APP_NAME'] %>", "<%= ENV['OPENSHIFT_GEAR_NAME'] %>", "<%= ENV['OPENSHIFT_NAMESPACE'] %>"]
        exclude => "python.log"
    }

    # Sabemos que python.log contiene logs de acceso de Apache.
    archivo {
        path => "<%= ENV['OPENSHIFT_LOG_DIR'] %>python.log"
        tags => ["<%= ENV['OPENSHIFT_APP_NAME'] %>", "<%= ENV['OPENSHIFT_GEAR_NAME'] %>", "<%= ENV['OPENSHIFT_NAMESPACE'] %>"]
        type => "apache"
    }

}

filtro {
    if [type] == "apache" {

        # Esto extraerá los diferentes metadatos en el mensaje de log, como marca de tiempo, IP, método, etc.
        Grok {
            match => ["message", "%{COMBINEDAPACHELOG}"]
        }

        # Convierte el formato de hora en algo razonable.
        fecha {
            match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
        }

        # Anotar el log con información geográfica aproximada.
        geoip {
            source => "clientip"
        }

    }
}

Con esa configuración, Logstash producirá documentos como el siguiente:

{
    "_type": "apache",
    "_source": {
        "ident": "-",
        "tags": ["app-name", "gearname", "espacio de nombres"],
        "type": "apache",
        "@timestamp": "2014-06-10T15:19:31.000Z",
        "request": "/",
        "auth": "-",
        "respuesta": "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"
}

Podemos hacer mucho más con este documento. Podemos dividir los logs de acceso según de dónde sea el usuario, qué visita, encontrar fácilmente solicitudes problemáticas, etcétera. La siguiente figura muestra un ejemplo de un dashboard de Kibana que utiliza los datos anteriores. Using Kibana to analyze access logs

Para personalizar el cartucho, solo haz un fork del repositorio y edita conf/logstash.conf.erb con la configuración de Logstash que desees.

Luego, personaliza la URL cuando agregues tu cartridge, es decir, cambia foundit/openshift-logstash-cartridge por your-organization/repository-name.

$ rhc cartridge add -a my-app https://cartreflect-claytondev.rhcloud.com/github/your-organization/your-repo

De forma predeterminada, utilizará la rama master. También puedes pasar una opción ?commit=branch-or-commit-iden la URL, por ejemplo, https://cartreflect-claytondev.rhcloud.com/github/foundit/openshift-logstash-cartridge?commit=python-sample.

Para obtener más información sobre cómo personalizar cartridges y usar cartridges que no están disponibles públicamente, consulta la guía de OpenShift sobre cómo se descargan los cartridges.

mapping compatibles con log

Como hemos visto, Logstash se encarga de enviar logs a Elasticsearch. Todavía necesitamos decirle a Elasticsearch cómo tratar esos logs. Necesitamos configurar los mappings para los índices resultantes. (Ver también: Una introducción al mapping de Elasticsearch y Un flujo de trabajo de exploración de datos para mappings)

Normalmente, Logstash enviará logs al índice logstash-YYYY-MM-DD, donde YYYY-MM-DD es la fecha del log. Esto te permite limitar las búsquedas a rangos de fechas específicos y archivar o eliminar logs antiguos.

Para configurar nuestro mapping de log, necesitamos definir una plantilla de índice, la cual define el mapping para todos los índices cuyo nombre coincida con logstash-*.

El siguiente es un apropiado mapping para los logs producidos anteriormente. Los campos de tipo texto no se analizan de forma predeterminada, a excepción del campo message, la ubicación geoip está configurada para ser de tipo geo_point, clientip como ip, etc.

{
    "template": "logstash-*",
    "settings": {
        "index.refresh_interval": "5s"
    },
    "mappings": {
        "_default_": {
            "_all": {
                "enabled": true
            },
            "dynamic_templates": [
                {
                    "string_fields": {
                        "match": "*",
                        "match_mapping_type": "texto",
                        "mapping": {
                            "type": "texto",
                            "index": "not_analyzed"
                        }
                    }
                }
            ],
            "properties": {
                "geoip": {
                    "properties": {
                        "location": {
                            "type": "geo_point"
                        }
                    }
                },
                "clientip": {
                    "type": "ip"
                },
                "bytes": {
                    "type": "long"
                },
                "message": {
                    "type": "texto",
                    "index": "analyzed",
                    "omit_norms": true
                }
            }
        }
    }
}

Para aplicar la plantilla, envía una solicitud PUTa /_template/logstash con el cuerpo JSON:

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

Luego, Elasticsearch usará la configuración y los mapeos especificados en la plantilla de índice cada vez que cree un nuevo logstash-index.

Resumen

Ahora tenemos un cartridge que puede servir como base para cartridges de Logstash personalizados con una configuración más específica para la aplicación. Llevar tus logs a un cluster de Elasticsearch para realizar búsquedas y analíticas increíbles ahora es solo cuestión de añadir un cartridge de OpenStack.