Cargar métricas desde el servidor Prometheus

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar libreta

Descripción general

Este tutorial cargas CoreDNS métricas de un Prometeo servidor en un tf.data.Dataset , a continuación, utiliza tf.keras para la formación y la inferencia.

CoreDNS es un servidor DNS con un enfoque de descubrimiento de servicios, y es ampliamente desplegado como parte de la Kubernetes clúster. Por esa razón, a menudo las operaciones de DevOps lo controlan de cerca.

Este tutorial es un ejemplo que podría ser utilizado por devops en busca de automatización en sus operaciones a través del aprendizaje automático.

Configuración y uso

Instale el paquete tensorflow-io requerido y reinicie el tiempo de ejecución

import os
try:
  %tensorflow_version 2.x
except Exception:
  pass
TensorFlow 2.x selected.
pip install tensorflow-io
from datetime import datetime

import tensorflow as tf
import tensorflow_io as tfio

Instalar y configurar CoreDNS y Prometheus

Para propósitos de demostración, un servidor CoreDNS localmente con el puerto 9053 abierto a recibir consultas de DNS y el puerto 9153 (defult) abierta para exponer las métricas para raspar. La siguiente es una configuración básica para el fichero de núcleo CoreDNS y está disponible para descarga :

.:9053 {
  prometheus
  whoami
}

Más detalles acerca de la instalación se podían encontrar en CoreDNS de documentación .

curl -s -OL https://github.com/coredns/coredns/releases/download/v1.6.7/coredns_1.6.7_linux_amd64.tgz
tar -xzf coredns_1.6.7_linux_amd64.tgz

curl -s -OL https://raw.githubusercontent.com/tensorflow/io/master/docs/tutorials/prometheus/Corefile

cat Corefile
.:9053 {
  prometheus
  whoami
}
# Run `./coredns` as a background process.
# IPython doesn't recognize `&` in inline bash cells.
get_ipython().system_raw('./coredns &')

El siguiente paso es configurar el servidor de Prometeo y el uso de Prometeo a CoreDNS rascado métricas que están expuestas en el puerto 9153 desde arriba. El prometheus.yml archivo de configuración también está disponible para su descarga :

curl -s -OL https://github.com/prometheus/prometheus/releases/download/v2.15.2/prometheus-2.15.2.linux-amd64.tar.gz
tar -xzf prometheus-2.15.2.linux-amd64.tar.gz --strip-components=1

curl -s -OL https://raw.githubusercontent.com/tensorflow/io/master/docs/tutorials/prometheus/prometheus.yml

cat prometheus.yml
global:
  scrape_interval:     1s
  evaluation_interval: 1s
alerting:
  alertmanagers:

  - static_configs:
    - targets:
rule_files:
scrape_configs:
- job_name: 'prometheus'
  static_configs:
  - targets: ['localhost:9090']
- job_name: "coredns"
  static_configs:
  - targets: ['localhost:9153']
# Run `./prometheus` as a background process.
# IPython doesn't recognize `&` in inline bash cells.
get_ipython().system_raw('./prometheus &')

Con el fin de mostrar alguna actividad, dig de comandos podría ser utilizado para generar un par de consultas DNS contra el servidor CoreDNS que ha sido configurado:

sudo apt-get install -y -qq dnsutils
dig @127.0.0.1 -p 9053 demo1.example.org
; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> @127.0.0.1 -p 9053 demo1.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53868
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 855234f1adcb7a28 (echoed)
;; QUESTION SECTION:
;demo1.example.org.     IN  A

;; ADDITIONAL SECTION:
demo1.example.org.  0   IN  A   127.0.0.1
_udp.demo1.example.org. 0   IN  SRV 0 0 45361 .

;; Query time: 0 msec
;; SERVER: 127.0.0.1#9053(127.0.0.1)
;; WHEN: Tue Mar 03 22:35:20 UTC 2020
;; MSG SIZE  rcvd: 132
dig @127.0.0.1 -p 9053 demo2.example.org
; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> @127.0.0.1 -p 9053 demo2.example.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53163
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: f18b2ba23e13446d (echoed)
;; QUESTION SECTION:
;demo2.example.org.     IN  A

;; ADDITIONAL SECTION:
demo2.example.org.  0   IN  A   127.0.0.1
_udp.demo2.example.org. 0   IN  SRV 0 0 42194 .

;; Query time: 0 msec
;; SERVER: 127.0.0.1#9053(127.0.0.1)
;; WHEN: Tue Mar 03 22:35:21 UTC 2020
;; MSG SIZE  rcvd: 132

Ahora, un servidor CoreDNS cuyas métricas son extraídas por un servidor Prometheus y están listas para ser consumidas por TensorFlow.

Cree un conjunto de datos para las métricas de CoreDNS y utilícelo en TensorFlow

Crear un conjunto de datos para CoreDNS métricas que se encuentra disponible en el servidor PostgreSQL, que se podría hacer con tfio.experimental.IODataset.from_prometheus . Como mínimo, se necesitan dos argumentos. query se pasa al servidor de Prometeo para seleccionar las métricas y la length es el período que desea cargar en conjunto de datos.

Puede comenzar con "coredns_dns_request_count_total" y "5" (segundos) para crear el conjunto de datos a continuación. Dado que fueron enviados anteriormente en el tutorial de dos consultas DNS, se espera que las métricas para "coredns_dns_request_count_total" serán "2.0" al final de la serie de tiempo:

dataset = tfio.experimental.IODataset.from_prometheus(
      "coredns_dns_request_count_total", 5, endpoint="http://localhost:9090")


print("Dataset Spec:\n{}\n".format(dataset.element_spec))

print("CoreDNS Time Series:")
for (time, value) in dataset:
  # time is milli second, convert to data time:
  time = datetime.fromtimestamp(time // 1000)
  print("{}: {}".format(time, value['coredns']['localhost:9153']['coredns_dns_request_count_total']))
Dataset Spec:
(TensorSpec(shape=(), dtype=tf.int64, name=None), {'coredns': {'localhost:9153': {'coredns_dns_request_count_total': TensorSpec(shape=(), dtype=tf.float64, name=None)} } })

CoreDNS Time Series:
2020-03-03 22:35:17: 2.0
2020-03-03 22:35:18: 2.0
2020-03-03 22:35:19: 2.0
2020-03-03 22:35:20: 2.0
2020-03-03 22:35:21: 2.0

Analizando más a fondo las especificaciones del conjunto de datos:

(
  TensorSpec(shape=(), dtype=tf.int64, name=None),
  {
    'coredns': {
      'localhost:9153': {
        'coredns_dns_request_count_total': TensorSpec(shape=(), dtype=tf.float64, name=None)
      }
    }
  }
)

Es obvio que el conjunto de datos consiste en una (time, values) tupla donde el values de campo es un diccionario ampliado en Python:

"job_name": {
  "instance_name": {
    "metric_name": value,
  },
}

En el ejemplo anterior, 'coredns' es el nombre del trabajo, 'localhost:9153' es el nombre de la instancia, y 'coredns_dns_request_count_total' es el nombre de la métrica. Tenga en cuenta que, según la consulta de Prometheus utilizada, es posible que se devuelvan varios trabajos / instancias / métricas. Esta es también la razón por la que se ha utilizado python dict en la estructura del conjunto de datos.

Tome otra consulta "go_memstats_gc_sys_bytes" como un ejemplo. Dado que ambos CoreDNS y Prometeo están escritos en Golang, "go_memstats_gc_sys_bytes" métrica está disponible tanto para "coredns" trabajo y "prometheus" de empleo:

dataset = tfio.experimental.IODataset.from_prometheus(
    "go_memstats_gc_sys_bytes", 5, endpoint="http://localhost:9090")

print("Time Series CoreDNS/Prometheus Comparision:")
for (time, value) in dataset:
  # time is milli second, convert to data time:
  time = datetime.fromtimestamp(time // 1000)
  print("{}: {}/{}".format(
      time,
      value['coredns']['localhost:9153']['go_memstats_gc_sys_bytes'],
      value['prometheus']['localhost:9090']['go_memstats_gc_sys_bytes']))
Time Series CoreDNS/Prometheus Comparision:
2020-03-03 22:35:17: 2385920.0/2775040.0
2020-03-03 22:35:18: 2385920.0/2775040.0
2020-03-03 22:35:19: 2385920.0/2775040.0
2020-03-03 22:35:20: 2385920.0/2775040.0
2020-03-03 22:35:21: 2385920.0/2775040.0

El creado Dataset está listo para ser pasado a tf.keras directamente, ya sea para fines de entrenamiento o de inferencia ahora.

Usa el conjunto de datos para el entrenamiento de modelos

Con la métrica del conjunto de datos creada, es posible pasar directamente al conjunto de datos para tf.keras para la formación de modelo o inferencia.

Para propósitos de demostración, este tutorial solo usará un modelo LSTM muy simple con 1 característica y 2 pasos como entrada:

n_steps, n_features = 2, 1
simple_lstm_model = tf.keras.models.Sequential([
    tf.keras.layers.LSTM(8, input_shape=(n_steps, n_features)),
    tf.keras.layers.Dense(1)
])

simple_lstm_model.compile(optimizer='adam', loss='mae')

El conjunto de datos que se utilizará es el valor de 'go_memstats_sys_bytes' para CoreDNS con 10 muestras. Sin embargo, desde una ventana deslizante de window=n_steps y shift=1 están formados, se necesitan muestras adicionales (para cualquier par de elementos consecute, la primera se toma como x , y la segunda se toma como y para la formación). El total es 10 + n_steps - 1 + 1 = 12 segundos.

El valor de datos también se escala a [0, 1] .

n_samples = 10

dataset = tfio.experimental.IODataset.from_prometheus(
    "go_memstats_sys_bytes", n_samples + n_steps - 1 + 1, endpoint="http://localhost:9090")

# take go_memstats_gc_sys_bytes from coredns job 
dataset = dataset.map(lambda _, v: v['coredns']['localhost:9153']['go_memstats_sys_bytes'])

# find the max value and scale the value to [0, 1]
v_max = dataset.reduce(tf.constant(0.0, tf.float64), tf.math.maximum)
dataset = dataset.map(lambda v: (v / v_max))

# expand the dimension by 1 to fit n_features=1
dataset = dataset.map(lambda v: tf.expand_dims(v, -1))

# take a sliding window
dataset = dataset.window(n_steps, shift=1, drop_remainder=True)
dataset = dataset.flat_map(lambda d: d.batch(n_steps))


# the first value is x and the next value is y, only take 10 samples
x = dataset.take(n_samples)
y = dataset.skip(1).take(n_samples)

dataset = tf.data.Dataset.zip((x, y))

# pass the final dataset to model.fit for training
simple_lstm_model.fit(dataset.batch(1).repeat(10),  epochs=5, steps_per_epoch=10)
Train for 10 steps
Epoch 1/5
10/10 [==============================] - 2s 150ms/step - loss: 0.8484
Epoch 2/5
10/10 [==============================] - 0s 10ms/step - loss: 0.7808
Epoch 3/5
10/10 [==============================] - 0s 10ms/step - loss: 0.7102
Epoch 4/5
10/10 [==============================] - 0s 11ms/step - loss: 0.6359
Epoch 5/5
10/10 [==============================] - 0s 11ms/step - loss: 0.5572
<tensorflow.python.keras.callbacks.History at 0x7f1758f3da90>

El modelo entrenado anterior no es muy útil en realidad, ya que el servidor CoreDNS que se ha configurado en este tutorial no tiene ninguna carga de trabajo. Sin embargo, esta es una canalización de trabajo que podría usarse para cargar métricas desde verdaderos servidores de producción. Luego, el modelo podría mejorarse para resolver el problema del mundo real de la automatización de DevOps.